summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/gtk
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/platform/gtk
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/platform/gtk')
-rw-r--r--Source/WebCore/platform/gtk/ClipboardGtk.cpp335
-rw-r--r--Source/WebCore/platform/gtk/ClipboardGtk.h90
-rw-r--r--Source/WebCore/platform/gtk/ClipboardUtilitiesGtk.cpp75
-rw-r--r--Source/WebCore/platform/gtk/ClipboardUtilitiesGtk.h33
-rw-r--r--Source/WebCore/platform/gtk/ContextMenuGtk.cpp72
-rw-r--r--Source/WebCore/platform/gtk/ContextMenuItemGtk.cpp227
-rw-r--r--Source/WebCore/platform/gtk/CursorGtk.cpp210
-rw-r--r--Source/WebCore/platform/gtk/CursorGtk.h383
-rw-r--r--Source/WebCore/platform/gtk/DataObjectGtk.cpp175
-rw-r--r--Source/WebCore/platform/gtk/DataObjectGtk.h83
-rw-r--r--Source/WebCore/platform/gtk/DragDataGtk.cpp90
-rw-r--r--Source/WebCore/platform/gtk/DragImageGtk.cpp86
-rw-r--r--Source/WebCore/platform/gtk/EventLoopGtk.cpp32
-rw-r--r--Source/WebCore/platform/gtk/FileChooserGtk.cpp67
-rw-r--r--Source/WebCore/platform/gtk/FileSystemGtk.cpp305
-rw-r--r--Source/WebCore/platform/gtk/GOwnPtrGtk.cpp38
-rw-r--r--Source/WebCore/platform/gtk/GOwnPtrGtk.h32
-rw-r--r--Source/WebCore/platform/gtk/GRefPtrGtk.cpp54
-rw-r--r--Source/WebCore/platform/gtk/GRefPtrGtk.h36
-rw-r--r--Source/WebCore/platform/gtk/GeolocationServiceGtk.cpp215
-rw-r--r--Source/WebCore/platform/gtk/GeolocationServiceGtk.h75
-rw-r--r--Source/WebCore/platform/gtk/GtkPluginWidget.cpp114
-rw-r--r--Source/WebCore/platform/gtk/GtkPluginWidget.h42
-rw-r--r--Source/WebCore/platform/gtk/GtkVersioning.c273
-rw-r--r--Source/WebCore/platform/gtk/GtkVersioning.h112
-rw-r--r--Source/WebCore/platform/gtk/KURLGtk.cpp40
-rw-r--r--Source/WebCore/platform/gtk/KeyEventGtk.cpp604
-rw-r--r--Source/WebCore/platform/gtk/LanguageGtk.cpp56
-rw-r--r--Source/WebCore/platform/gtk/LocalizedStringsGtk.cpp635
-rw-r--r--Source/WebCore/platform/gtk/LoggingGtk.cpp64
-rw-r--r--Source/WebCore/platform/gtk/MIMETypeRegistryGtk.cpp81
-rw-r--r--Source/WebCore/platform/gtk/MainFrameScrollbarGtk.cpp118
-rw-r--r--Source/WebCore/platform/gtk/MainFrameScrollbarGtk.h52
-rw-r--r--Source/WebCore/platform/gtk/MouseEventGtk.cpp105
-rw-r--r--Source/WebCore/platform/gtk/PasteboardGtk.cpp160
-rw-r--r--Source/WebCore/platform/gtk/PasteboardHelper.cpp315
-rw-r--r--Source/WebCore/platform/gtk/PasteboardHelper.h68
-rw-r--r--Source/WebCore/platform/gtk/PlatformScreenGtk.cpp154
-rw-r--r--Source/WebCore/platform/gtk/PopupMenuGtk.cpp270
-rw-r--r--Source/WebCore/platform/gtk/PopupMenuGtk.h72
-rw-r--r--Source/WebCore/platform/gtk/RenderThemeGtk.cpp598
-rw-r--r--Source/WebCore/platform/gtk/RenderThemeGtk.h209
-rw-r--r--Source/WebCore/platform/gtk/RenderThemeGtk2.cpp517
-rw-r--r--Source/WebCore/platform/gtk/RenderThemeGtk3.cpp643
-rw-r--r--Source/WebCore/platform/gtk/ScrollViewGtk.cpp238
-rw-r--r--Source/WebCore/platform/gtk/ScrollbarThemeGtk.cpp287
-rw-r--r--Source/WebCore/platform/gtk/ScrollbarThemeGtk.h80
-rw-r--r--Source/WebCore/platform/gtk/ScrollbarThemeGtk2.cpp154
-rw-r--r--Source/WebCore/platform/gtk/ScrollbarThemeGtk3.cpp198
-rw-r--r--Source/WebCore/platform/gtk/SearchPopupMenuGtk.cpp53
-rw-r--r--Source/WebCore/platform/gtk/SearchPopupMenuGtk.h44
-rw-r--r--Source/WebCore/platform/gtk/SharedBufferGtk.cpp51
-rw-r--r--Source/WebCore/platform/gtk/SharedTimerGtk.cpp81
-rw-r--r--Source/WebCore/platform/gtk/SoundGtk.cpp35
-rw-r--r--Source/WebCore/platform/gtk/TemporaryLinkStubs.cpp52
-rw-r--r--Source/WebCore/platform/gtk/WheelEventGtk.cpp76
-rw-r--r--Source/WebCore/platform/gtk/WidgetGtk.cpp144
-rw-r--r--Source/WebCore/platform/gtk/WidgetRenderingContext.h60
-rw-r--r--Source/WebCore/platform/gtk/WidgetRenderingContextGtk2.cpp191
-rw-r--r--Source/WebCore/platform/gtk/WidgetRenderingContextGtk3.cpp73
-rw-r--r--Source/WebCore/platform/gtk/gtk2drawing.c1372
-rw-r--r--Source/WebCore/platform/gtk/gtk3drawing.c1288
-rw-r--r--Source/WebCore/platform/gtk/gtkdrawing.h296
63 files changed, 12788 insertions, 0 deletions
diff --git a/Source/WebCore/platform/gtk/ClipboardGtk.cpp b/Source/WebCore/platform/gtk/ClipboardGtk.cpp
new file mode 100644
index 0000000..eb7248b
--- /dev/null
+++ b/Source/WebCore/platform/gtk/ClipboardGtk.cpp
@@ -0,0 +1,335 @@
+/*
+ * 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 "ClipboardGtk.h"
+
+#include "CachedImage.h"
+#include "DragData.h"
+#include "Editor.h"
+#include "Element.h"
+#include "FileList.h"
+#include "Frame.h"
+#include "HTMLNames.h"
+#include "Image.h"
+#include "NotImplemented.h"
+#include "Pasteboard.h"
+#include "PasteboardHelper.h"
+#include "RenderImage.h"
+#include "ScriptExecutionContext.h"
+#include "markup.h"
+#include <wtf/text/CString.h>
+#include <wtf/text/StringHash.h>
+#include <gtk/gtk.h>
+
+namespace WebCore {
+
+enum ClipboardDataType {
+ ClipboardDataTypeText,
+ ClipboardDataTypeMarkup,
+ ClipboardDataTypeURIList,
+ ClipboardDataTypeURL,
+ ClipboardDataTypeImage,
+ ClipboardDataTypeUnknown
+};
+
+PassRefPtr<Clipboard> Editor::newGeneralClipboard(ClipboardAccessPolicy policy, Frame* frame)
+{
+ return ClipboardGtk::create(policy, gtk_clipboard_get_for_display(gdk_display_get_default(), GDK_SELECTION_CLIPBOARD), frame);
+}
+
+PassRefPtr<Clipboard> Clipboard::create(ClipboardAccessPolicy policy, DragData* dragData, Frame* frame)
+{
+ return ClipboardGtk::create(policy, dragData->platformData(), DragAndDrop, frame);
+}
+
+ClipboardGtk::ClipboardGtk(ClipboardAccessPolicy policy, GtkClipboard* clipboard, Frame* frame)
+ : Clipboard(policy, CopyAndPaste)
+ , m_dataObject(DataObjectGtk::forClipboard(clipboard))
+ , m_clipboard(clipboard)
+ , m_helper(Pasteboard::generalPasteboard()->helper())
+ , m_frame(frame)
+{
+}
+
+ClipboardGtk::ClipboardGtk(ClipboardAccessPolicy policy, PassRefPtr<DataObjectGtk> dataObject, ClipboardType clipboardType, Frame* frame)
+ : Clipboard(policy, clipboardType)
+ , m_dataObject(dataObject)
+ , m_clipboard(0)
+ , m_helper(Pasteboard::generalPasteboard()->helper())
+ , m_frame(frame)
+{
+}
+
+ClipboardGtk::~ClipboardGtk()
+{
+}
+
+static ClipboardDataType dataObjectTypeFromHTMLClipboardType(const String& rawType)
+{
+ String type(rawType.stripWhiteSpace());
+
+ // Two special cases for IE compatibility
+ if (type == "Text")
+ return ClipboardDataTypeText;
+ if (type == "URL")
+ return ClipboardDataTypeURL;
+
+ // From the Mac port: Ignore any trailing charset - JS strings are
+ // Unicode, which encapsulates the charset issue.
+ if (type == "text/plain" || type.startsWith("text/plain;"))
+ return ClipboardDataTypeText;
+ if (type == "text/html" || type.startsWith("text/html;"))
+ return ClipboardDataTypeMarkup;
+ if (type == "Files" || type == "text/uri-list" || type.startsWith("text/uri-list;"))
+ return ClipboardDataTypeURIList;
+
+ // Not a known type, so just default to using the text portion.
+ return ClipboardDataTypeUnknown;
+}
+
+void ClipboardGtk::clearData(const String& typeString)
+{
+ if (policy() != ClipboardWritable)
+ return;
+
+ ClipboardDataType type = dataObjectTypeFromHTMLClipboardType(typeString);
+ switch (type) {
+ case ClipboardDataTypeURIList:
+ case ClipboardDataTypeURL:
+ m_dataObject->clearURIList();
+ break;
+ case ClipboardDataTypeMarkup:
+ m_dataObject->clearMarkup();
+ break;
+ case ClipboardDataTypeText:
+ m_dataObject->clearText();
+ break;
+ case ClipboardDataTypeUnknown:
+ default:
+ m_dataObject->clear();
+ }
+
+ if (m_clipboard)
+ m_helper->writeClipboardContents(m_clipboard);
+}
+
+
+void ClipboardGtk::clearAllData()
+{
+ if (policy() != ClipboardWritable)
+ return;
+
+ m_dataObject->clear();
+
+ if (m_clipboard)
+ m_helper->writeClipboardContents(m_clipboard);
+}
+
+String ClipboardGtk::getData(const String& typeString, bool& success) const
+{
+ success = true; // According to http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html
+ // "The getData(format) method must return the data that is associated with the type format converted
+ // to ASCII lowercase, if any, and must return the empty string otherwise." Since success == false
+ // results in an 'undefined' return value, we always want to return success == true. This parameter
+ // should eventually be removed.
+ if (policy() != ClipboardReadable || !m_dataObject)
+ return String();
+
+ if (m_clipboard)
+ m_helper->getClipboardContents(m_clipboard);
+
+ ClipboardDataType type = dataObjectTypeFromHTMLClipboardType(typeString);
+ if (type == ClipboardDataTypeURIList)
+ return m_dataObject->uriList();
+ if (type == ClipboardDataTypeURL)
+ return m_dataObject->url();
+ if (type == ClipboardDataTypeMarkup)
+ return m_dataObject->markup();
+ if (type == ClipboardDataTypeText)
+ return m_dataObject->text();
+
+ return String();
+}
+
+bool ClipboardGtk::setData(const String& typeString, const String& data)
+{
+ if (policy() != ClipboardWritable)
+ return false;
+
+ bool success = false;
+ ClipboardDataType type = dataObjectTypeFromHTMLClipboardType(typeString);
+ if (type == ClipboardDataTypeURIList || type == ClipboardDataTypeURL) {
+ m_dataObject->setURIList(data);
+ success = true;
+ } else if (type == ClipboardDataTypeMarkup) {
+ m_dataObject->setMarkup(data);
+ success = true;
+ } else if (type == ClipboardDataTypeText) {
+ m_dataObject->setText(data);
+ success = true;
+ }
+
+ if (success && m_clipboard)
+ m_helper->writeClipboardContents(m_clipboard);
+
+ return success;
+}
+
+HashSet<String> ClipboardGtk::types() const
+{
+ if (policy() != ClipboardReadable && policy() != ClipboardTypesReadable)
+ return HashSet<String>();
+
+ if (m_clipboard)
+ m_helper->getClipboardContents(m_clipboard);
+
+ HashSet<String> types;
+ if (m_dataObject->hasText()) {
+ types.add("text/plain");
+ types.add("Text");
+ }
+
+ if (m_dataObject->hasMarkup())
+ types.add("text/html");
+
+ if (m_dataObject->hasURIList()) {
+ types.add("text/uri-list");
+ types.add("URL");
+ }
+
+ if (m_dataObject->hasFilenames())
+ types.add("Files");
+
+ return types;
+}
+
+PassRefPtr<FileList> ClipboardGtk::files() const
+{
+ if (policy() != ClipboardReadable)
+ return FileList::create();
+
+ if (m_clipboard)
+ m_helper->getClipboardContents(m_clipboard);
+
+ RefPtr<FileList> fileList = FileList::create();
+ const Vector<String>& filenames = m_dataObject->filenames();
+ for (size_t i = 0; i < filenames.size(); i++)
+ fileList->append(File::create(filenames[i]));
+ return fileList.release();
+}
+
+void ClipboardGtk::setDragImage(CachedImage* image, const IntPoint& location)
+{
+ setDragImage(image, 0, location);
+}
+
+void ClipboardGtk::setDragImageElement(Node* element, const IntPoint& location)
+{
+ setDragImage(0, element, location);
+}
+
+void ClipboardGtk::setDragImage(CachedImage* image, Node* element, const IntPoint& location)
+{
+ if (policy() != ClipboardImageWritable && policy() != ClipboardWritable)
+ return;
+
+ if (m_dragImage)
+ m_dragImage->removeClient(this);
+ m_dragImage = image;
+ if (m_dragImage)
+ m_dragImage->addClient(this);
+
+ m_dragLoc = location;
+ m_dragImageElement = element;
+}
+
+DragImageRef ClipboardGtk::createDragImage(IntPoint& location) const
+{
+ location = m_dragLoc;
+ if (!m_dragImage)
+ return 0;
+
+ return createDragImageFromImage(m_dragImage->image());
+}
+
+static CachedImage* getCachedImage(Element* element)
+{
+ // Attempt to pull CachedImage from element
+ ASSERT(element);
+ RenderObject* renderer = element->renderer();
+ if (!renderer || !renderer->isImage())
+ return 0;
+
+ RenderImage* image = static_cast<RenderImage*>(renderer);
+ if (image->cachedImage() && !image->cachedImage()->errorOccurred())
+ return image->cachedImage();
+
+ return 0;
+}
+
+void ClipboardGtk::declareAndWriteDragImage(Element* element, const KURL& url, const String& label, Frame* frame)
+{
+ m_dataObject->setURL(url, label);
+ m_dataObject->setMarkup(createMarkup(element, IncludeNode, 0, AbsoluteURLs));
+
+ CachedImage* image = getCachedImage(element);
+ if (!image || !image->isLoaded())
+ return;
+
+ GRefPtr<GdkPixbuf> pixbuf = adoptGRef(image->image()->getGdkPixbuf());
+ if (!pixbuf)
+ return;
+
+ m_dataObject->setImage(pixbuf.get());
+}
+
+void ClipboardGtk::writeURL(const KURL& url, const String& label, Frame*)
+{
+ m_dataObject->setURL(url, label);
+ if (m_clipboard)
+ m_helper->writeClipboardContents(m_clipboard);
+}
+
+void ClipboardGtk::writeRange(Range* range, Frame* frame)
+{
+ ASSERT(range);
+
+ m_dataObject->setText(frame->editor()->selectedText());
+ m_dataObject->setMarkup(createMarkup(range, 0, AnnotateForInterchange, false, AbsoluteURLs));
+
+ if (m_clipboard)
+ m_helper->writeClipboardContents(m_clipboard);
+}
+
+void ClipboardGtk::writePlainText(const String& text)
+{
+ m_dataObject->setText(text);
+
+ if (m_clipboard)
+ m_helper->writeClipboardContents(m_clipboard);
+}
+
+bool ClipboardGtk::hasData()
+{
+ if (m_clipboard)
+ m_helper->getClipboardContents(m_clipboard);
+
+ return m_dataObject->hasText() || m_dataObject->hasMarkup()
+ || m_dataObject->hasURIList() || m_dataObject->hasImage();
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/ClipboardGtk.h b/Source/WebCore/platform/gtk/ClipboardGtk.h
new file mode 100644
index 0000000..e14a583
--- /dev/null
+++ b/Source/WebCore/platform/gtk/ClipboardGtk.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, Holger Hans Peter Freyther
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ClipboardGtk_h
+#define ClipboardGtk_h
+
+#include "CachedResourceClient.h"
+#include "Clipboard.h"
+#include "DataObjectGtk.h"
+
+namespace WebCore {
+ class CachedImage;
+ class Frame;
+ class PasteboardHelper;
+
+ // State available during IE's events for drag and drop and copy/paste
+ // Created from the EventHandlerGtk to be used by the dom
+ class ClipboardGtk : public Clipboard, public CachedResourceClient {
+ public:
+ static PassRefPtr<ClipboardGtk> create(ClipboardAccessPolicy policy, GtkClipboard* clipboard, Frame* frame)
+ {
+ return adoptRef(new ClipboardGtk(policy, clipboard, frame));
+ }
+
+ static PassRefPtr<ClipboardGtk> create(ClipboardAccessPolicy policy, PassRefPtr<DataObjectGtk> dataObject, ClipboardType clipboardType, Frame* frame)
+ {
+ return adoptRef(new ClipboardGtk(policy, dataObject, clipboardType, frame));
+ }
+ virtual ~ClipboardGtk();
+
+ void clearData(const String&);
+ void clearAllData();
+ String getData(const String&, bool&) const;
+ bool setData(const String&, const String&);
+
+ virtual HashSet<String> types() const;
+ virtual PassRefPtr<FileList> files() const;
+
+ void setDragImage(CachedImage*, const IntPoint&);
+ void setDragImageElement(Node*, const IntPoint&);
+ void setDragImage(CachedImage*, Node*, const IntPoint&);
+
+ virtual DragImageRef createDragImage(IntPoint&) const;
+#if ENABLE(DRAG_SUPPORT)
+ virtual void declareAndWriteDragImage(Element*, const KURL&, const String&, Frame*);
+#endif
+ virtual void writeURL(const KURL&, const String&, Frame*);
+ virtual void writeRange(Range*, Frame*);
+ virtual void writePlainText(const String&);
+
+ virtual bool hasData();
+
+ PasteboardHelper* helper() { return m_helper; }
+ PassRefPtr<DataObjectGtk> dataObject() { return m_dataObject; }
+
+ private:
+ ClipboardGtk(ClipboardAccessPolicy, GtkClipboard*, Frame*);
+ ClipboardGtk(ClipboardAccessPolicy, PassRefPtr<DataObjectGtk>, ClipboardType, Frame*);
+
+ RefPtr<DataObjectGtk> m_dataObject;
+ GtkClipboard* m_clipboard;
+ PasteboardHelper* m_helper;
+ Frame* m_frame;
+ };
+}
+
+#endif
diff --git a/Source/WebCore/platform/gtk/ClipboardUtilitiesGtk.cpp b/Source/WebCore/platform/gtk/ClipboardUtilitiesGtk.cpp
new file mode 100644
index 0000000..9fc0e74
--- /dev/null
+++ b/Source/WebCore/platform/gtk/ClipboardUtilitiesGtk.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2010, 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 "ClipboardUtilitiesGtk.h"
+
+namespace WebCore {
+
+GdkDragAction dragOperationToGdkDragActions(DragOperation coreAction)
+{
+ GdkDragAction gdkAction = static_cast<GdkDragAction>(0);
+ if (coreAction == DragOperationNone)
+ return gdkAction;
+
+ if (coreAction & DragOperationCopy)
+ gdkAction = static_cast<GdkDragAction>(GDK_ACTION_COPY | gdkAction);
+ if (coreAction & DragOperationMove)
+ gdkAction = static_cast<GdkDragAction>(GDK_ACTION_MOVE | gdkAction);
+ if (coreAction & DragOperationLink)
+ gdkAction = static_cast<GdkDragAction>(GDK_ACTION_LINK | gdkAction);
+ if (coreAction & DragOperationPrivate)
+ gdkAction = static_cast<GdkDragAction>(GDK_ACTION_PRIVATE | gdkAction);
+
+ return gdkAction;
+}
+
+GdkDragAction dragOperationToSingleGdkDragAction(DragOperation coreAction)
+{
+ if (coreAction == DragOperationEvery || coreAction & DragOperationCopy)
+ return GDK_ACTION_COPY;
+ if (coreAction & DragOperationMove)
+ return GDK_ACTION_MOVE;
+ if (coreAction & DragOperationLink)
+ return GDK_ACTION_LINK;
+ if (coreAction & DragOperationPrivate)
+ return GDK_ACTION_PRIVATE;
+ return static_cast<GdkDragAction>(0);
+}
+
+DragOperation gdkDragActionToDragOperation(GdkDragAction gdkAction)
+{
+ // We have no good way to detect DragOperationEvery other than
+ // to use it when all applicable flags are on.
+ if (gdkAction & GDK_ACTION_COPY && gdkAction & GDK_ACTION_MOVE
+ && gdkAction & GDK_ACTION_LINK && gdkAction & GDK_ACTION_PRIVATE)
+ return DragOperationEvery;
+
+ unsigned int action = DragOperationNone;
+ if (gdkAction & GDK_ACTION_COPY)
+ action |= DragOperationCopy;
+ if (gdkAction & GDK_ACTION_MOVE)
+ action |= DragOperationMove;
+ if (gdkAction & GDK_ACTION_LINK)
+ action |= DragOperationLink;
+ if (gdkAction & GDK_ACTION_PRIVATE)
+ action |= DragOperationPrivate;
+ return static_cast<DragOperation>(action);
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/ClipboardUtilitiesGtk.h b/Source/WebCore/platform/gtk/ClipboardUtilitiesGtk.h
new file mode 100644
index 0000000..26f6346
--- /dev/null
+++ b/Source/WebCore/platform/gtk/ClipboardUtilitiesGtk.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2010, 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 ClipboardUtilitiesGtk_h
+#define ClipboardUtilitiesGtk_h
+
+#include "DragActions.h"
+#include <gdk/gdk.h>
+
+namespace WebCore {
+
+GdkDragAction dragOperationToGdkDragActions(DragOperation);
+GdkDragAction dragOperationToSingleGdkDragAction(DragOperation);
+DragOperation gdkDragActionToDragOperation(GdkDragAction);
+
+}
+
+#endif // ClipboardUtilitiesGtk_h
diff --git a/Source/WebCore/platform/gtk/ContextMenuGtk.cpp b/Source/WebCore/platform/gtk/ContextMenuGtk.cpp
new file mode 100644
index 0000000..423959a
--- /dev/null
+++ b/Source/WebCore/platform/gtk/ContextMenuGtk.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ *
+ * 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 "ContextMenu.h"
+
+#include <gtk/gtk.h>
+
+namespace WebCore {
+
+ContextMenu::ContextMenu()
+{
+ m_platformDescription = GTK_MENU(gtk_menu_new());
+
+ g_object_ref_sink(G_OBJECT(m_platformDescription));
+}
+
+ContextMenu::~ContextMenu()
+{
+ if (m_platformDescription)
+ g_object_unref(m_platformDescription);
+}
+
+void ContextMenu::appendItem(ContextMenuItem& item)
+{
+ ASSERT(m_platformDescription);
+
+ GtkMenuItem* platformItem = item.releasePlatformDescription();
+ ASSERT(platformItem);
+ gtk_menu_shell_append(GTK_MENU_SHELL(m_platformDescription), GTK_WIDGET(platformItem));
+ gtk_widget_show(GTK_WIDGET(platformItem));
+}
+
+void ContextMenu::setPlatformDescription(PlatformMenuDescription menu)
+{
+ ASSERT(menu);
+ if (m_platformDescription)
+ g_object_unref(m_platformDescription);
+
+ m_platformDescription = menu;
+ g_object_ref(m_platformDescription);
+}
+
+PlatformMenuDescription ContextMenu::platformDescription() const
+{
+ return m_platformDescription;
+}
+
+PlatformMenuDescription ContextMenu::releasePlatformDescription()
+{
+ PlatformMenuDescription description = m_platformDescription;
+ m_platformDescription = 0;
+
+ return description;
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/ContextMenuItemGtk.cpp b/Source/WebCore/platform/gtk/ContextMenuItemGtk.cpp
new file mode 100644
index 0000000..4d79f13
--- /dev/null
+++ b/Source/WebCore/platform/gtk/ContextMenuItemGtk.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * Copyright (C) 2010 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 "ContextMenuItem.h"
+
+#include "ContextMenu.h"
+#include "GOwnPtr.h"
+#include "NotImplemented.h"
+#include <gtk/gtk.h>
+#include <wtf/text/CString.h>
+
+#define WEBKIT_CONTEXT_MENU_ACTION "webkit-context-menu"
+
+namespace WebCore {
+
+static const char* gtkStockIDFromContextMenuAction(const ContextMenuAction& action)
+{
+ switch (action) {
+ case ContextMenuItemTagCopyLinkToClipboard:
+ case ContextMenuItemTagCopyImageToClipboard:
+ case ContextMenuItemTagCopyMediaLinkToClipboard:
+ case ContextMenuItemTagCopy:
+ return GTK_STOCK_COPY;
+ case ContextMenuItemTagOpenLinkInNewWindow:
+ case ContextMenuItemTagOpenImageInNewWindow:
+ case ContextMenuItemTagOpenFrameInNewWindow:
+ case ContextMenuItemTagOpenMediaInNewWindow:
+ return GTK_STOCK_OPEN;
+ case ContextMenuItemTagDownloadLinkToDisk:
+ case ContextMenuItemTagDownloadImageToDisk:
+ return GTK_STOCK_SAVE;
+ case ContextMenuItemTagGoBack:
+ return GTK_STOCK_GO_BACK;
+ case ContextMenuItemTagGoForward:
+ return GTK_STOCK_GO_FORWARD;
+ case ContextMenuItemTagStop:
+ return GTK_STOCK_STOP;
+ case ContextMenuItemTagReload:
+ return GTK_STOCK_REFRESH;
+ case ContextMenuItemTagCut:
+ return GTK_STOCK_CUT;
+ case ContextMenuItemTagPaste:
+ return GTK_STOCK_PASTE;
+ case ContextMenuItemTagDelete:
+ return GTK_STOCK_DELETE;
+ case ContextMenuItemTagSelectAll:
+ return GTK_STOCK_SELECT_ALL;
+ case ContextMenuItemTagSpellingGuess:
+ return 0;
+ case ContextMenuItemTagIgnoreSpelling:
+ return GTK_STOCK_NO;
+ case ContextMenuItemTagLearnSpelling:
+ return GTK_STOCK_OK;
+ case ContextMenuItemTagOther:
+ return GTK_STOCK_MISSING_IMAGE;
+ case ContextMenuItemTagSearchInSpotlight:
+ return GTK_STOCK_FIND;
+ case ContextMenuItemTagSearchWeb:
+ return GTK_STOCK_FIND;
+ case ContextMenuItemTagOpenWithDefaultApplication:
+ return GTK_STOCK_OPEN;
+ case ContextMenuItemPDFZoomIn:
+ return GTK_STOCK_ZOOM_IN;
+ case ContextMenuItemPDFZoomOut:
+ return GTK_STOCK_ZOOM_OUT;
+ case ContextMenuItemPDFAutoSize:
+ return GTK_STOCK_ZOOM_FIT;
+ case ContextMenuItemPDFNextPage:
+ return GTK_STOCK_GO_FORWARD;
+ case ContextMenuItemPDFPreviousPage:
+ return GTK_STOCK_GO_BACK;
+ // New tags, not part of API
+ case ContextMenuItemTagOpenLink:
+ return GTK_STOCK_OPEN;
+ case ContextMenuItemTagCheckSpelling:
+ return GTK_STOCK_SPELL_CHECK;
+ case ContextMenuItemTagFontMenu:
+ return GTK_STOCK_SELECT_FONT;
+ case ContextMenuItemTagShowFonts:
+ return GTK_STOCK_SELECT_FONT;
+ case ContextMenuItemTagBold:
+ return GTK_STOCK_BOLD;
+ case ContextMenuItemTagItalic:
+ return GTK_STOCK_ITALIC;
+ case ContextMenuItemTagUnderline:
+ return GTK_STOCK_UNDERLINE;
+ case ContextMenuItemTagShowColors:
+ return GTK_STOCK_SELECT_COLOR;
+ case ContextMenuItemTagToggleMediaControls:
+ case ContextMenuItemTagToggleMediaLoop:
+ // No icon for this.
+ return 0;
+ case ContextMenuItemTagEnterVideoFullscreen:
+ return GTK_STOCK_FULLSCREEN;
+ default:
+ return 0;
+ }
+}
+
+// Extract the ActionType from the menu item
+ContextMenuItem::ContextMenuItem(PlatformMenuItemDescription item)
+ : m_platformDescription(item)
+{
+}
+
+ContextMenuItem::ContextMenuItem(ContextMenu*)
+{
+ notImplemented();
+}
+
+ContextMenuItem::ContextMenuItem(ContextMenuItemType type, ContextMenuAction action, const String& title, ContextMenu* subMenu)
+{
+ if (type == SeparatorType) {
+ m_platformDescription = GTK_MENU_ITEM(gtk_separator_menu_item_new());
+ return;
+ }
+
+ GOwnPtr<char> actionName(g_strdup_printf("context-menu-action-%d", action));
+ GtkAction* platformAction = 0;
+
+ if (type == CheckableActionType)
+ platformAction = GTK_ACTION(gtk_toggle_action_new(actionName.get(), title.utf8().data(), 0, gtkStockIDFromContextMenuAction(action)));
+ else
+ platformAction = gtk_action_new(actionName.get(), title.utf8().data(), 0, gtkStockIDFromContextMenuAction(action));
+
+ m_platformDescription = GTK_MENU_ITEM(gtk_action_create_menu_item(platformAction));
+ g_object_unref(platformAction);
+
+ g_object_set_data(G_OBJECT(m_platformDescription.get()), WEBKIT_CONTEXT_MENU_ACTION, GINT_TO_POINTER(action));
+
+ if (subMenu)
+ setSubMenu(subMenu);
+}
+
+ContextMenuItem::~ContextMenuItem()
+{
+}
+
+PlatformMenuItemDescription ContextMenuItem::releasePlatformDescription()
+{
+ return m_platformDescription.leakRef();
+}
+
+ContextMenuItemType ContextMenuItem::type() const
+{
+ if (GTK_IS_SEPARATOR_MENU_ITEM(m_platformDescription.get()))
+ return SeparatorType;
+ if (GTK_IS_CHECK_MENU_ITEM(m_platformDescription.get()))
+ return CheckableActionType;
+ if (gtk_menu_item_get_submenu(m_platformDescription.get()))
+ return SubmenuType;
+ return ActionType;
+}
+
+void ContextMenuItem::setType(ContextMenuItemType type)
+{
+ if (type == SeparatorType)
+ m_platformDescription = GTK_MENU_ITEM(gtk_separator_menu_item_new());
+}
+
+ContextMenuAction ContextMenuItem::action() const
+{
+ return static_cast<ContextMenuAction>(GPOINTER_TO_INT(g_object_get_data(G_OBJECT(m_platformDescription.get()), WEBKIT_CONTEXT_MENU_ACTION)));
+}
+
+void ContextMenuItem::setAction(ContextMenuAction action)
+{
+ g_object_set_data(G_OBJECT(m_platformDescription.get()), WEBKIT_CONTEXT_MENU_ACTION, GINT_TO_POINTER(action));
+}
+
+String ContextMenuItem::title() const
+{
+ GtkAction* action = gtk_activatable_get_related_action(GTK_ACTIVATABLE(m_platformDescription.get()));
+ return action ? String(gtk_action_get_label(action)) : String();
+}
+
+void ContextMenuItem::setTitle(const String& title)
+{
+ GtkAction* action = gtk_activatable_get_related_action(GTK_ACTIVATABLE(m_platformDescription.get()));
+ if (action)
+ gtk_action_set_label(action, title.utf8().data());
+}
+
+PlatformMenuDescription ContextMenuItem::platformSubMenu() const
+{
+ GtkWidget* subMenu = gtk_menu_item_get_submenu(m_platformDescription.get());
+ return subMenu ? GTK_MENU(subMenu) : 0;
+}
+
+void ContextMenuItem::setSubMenu(ContextMenu* menu)
+{
+ gtk_menu_item_set_submenu(m_platformDescription.get(), GTK_WIDGET(menu->platformDescription()));
+}
+
+void ContextMenuItem::setChecked(bool shouldCheck)
+{
+ GtkAction* action = gtk_activatable_get_related_action(GTK_ACTIVATABLE(m_platformDescription.get()));
+ if (action && GTK_IS_TOGGLE_ACTION(action))
+ gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), shouldCheck);
+}
+
+void ContextMenuItem::setEnabled(bool shouldEnable)
+{
+ GtkAction* action = gtk_activatable_get_related_action(GTK_ACTIVATABLE(m_platformDescription.get()));
+ if (action)
+ gtk_action_set_sensitive(action, shouldEnable);
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/CursorGtk.cpp b/Source/WebCore/platform/gtk/CursorGtk.cpp
new file mode 100644
index 0000000..9c5c16c
--- /dev/null
+++ b/Source/WebCore/platform/gtk/CursorGtk.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007 Christian Dywan <christian@twotoasts.de>
+ * Copyright (C) 2010 Igalia S.L.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CursorGtk.h"
+#include "GtkVersioning.h"
+
+#include "Image.h"
+#include "IntPoint.h"
+#include "RefPtrCairo.h"
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+#include <wtf/Assertions.h>
+
+namespace WebCore {
+
+static GRefPtr<GdkCursor> createNamedCursor(CustomCursorType cursorType)
+{
+ CustomCursor cursor = CustomCursors[cursorType];
+ GRefPtr<GdkCursor> c = adoptGRef(gdk_cursor_new_from_name(gdk_display_get_default(), cursor.name));
+ if (c)
+ return c;
+
+ IntSize cursorSize = IntSize(32, 32);
+ RefPtr<cairo_surface_t> source = adoptRef(cairo_image_surface_create_for_data(const_cast<unsigned char*>(cursor.bits), CAIRO_FORMAT_A1, 32, 32, 4));
+ RefPtr<cairo_surface_t> mask = adoptRef(cairo_image_surface_create_for_data(const_cast<unsigned char*>(cursor.mask_bits), CAIRO_FORMAT_A1, 32, 32, 4));
+ RefPtr<cairo_surface_t> surface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_A1, 32, 32));
+ RefPtr<cairo_t> cr = adoptRef(cairo_create(surface.get()));
+
+ cairo_set_source_surface(cr.get(), source.get(), cursor.hot_x, cursor.hot_y);
+ cairo_mask_surface(cr.get(), mask.get(), cursor.hot_x, cursor.hot_y);
+
+ GRefPtr<GdkPixbuf> pixbuf = adoptGRef(gdk_pixbuf_get_from_surface(surface.get(), 0, 0, 32, 32));
+ return adoptGRef(gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pixbuf.get(), 0, 0));
+}
+
+static GRefPtr<GdkCursor> createCustomCursor(Image* image, const IntPoint& hotSpot)
+{
+ IntPoint effectiveHotSpot = determineHotSpot(image, hotSpot);
+ GRefPtr<GdkPixbuf> pixbuf = adoptGRef(image->getGdkPixbuf());
+ return adoptGRef(gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pixbuf.get(), effectiveHotSpot.x(), effectiveHotSpot.y()));
+}
+
+void Cursor::ensurePlatformCursor() const
+{
+ if (m_platformCursor || m_type == Cursor::Pointer)
+ return;
+
+ switch (m_type) {
+ case Cursor::Pointer:
+ // A null GdkCursor is the default cursor for the window.
+ m_platformCursor = 0;
+ break;
+ case Cursor::Cross:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_CROSS));
+ break;
+ case Cursor::Hand:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_HAND2));
+ break;
+ case Cursor::IBeam:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_XTERM));
+ break;
+ case Cursor::Wait:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_WATCH));
+ break;
+ case Cursor::Help:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_QUESTION_ARROW));
+ break;
+ case Cursor::Move:
+ case Cursor::MiddlePanning:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_FLEUR));
+ break;
+ case Cursor::EastResize:
+ case Cursor::EastPanning:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_RIGHT_SIDE));
+ break;
+ case Cursor::NorthResize:
+ case Cursor::NorthPanning:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_TOP_SIDE));
+ break;
+ case Cursor::NorthEastResize:
+ case Cursor::NorthEastPanning:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_LEFT_SIDE));
+ break;
+ case Cursor::NorthWestResize:
+ case Cursor::NorthWestPanning:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_TOP_LEFT_CORNER));
+ break;
+ case Cursor::SouthResize:
+ case Cursor::SouthPanning:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_BOTTOM_SIDE));
+ break;
+ case Cursor::SouthEastResize:
+ case Cursor::SouthEastPanning:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER));
+ break;
+ case Cursor::SouthWestResize:
+ case Cursor::SouthWestPanning:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_BOTTOM_LEFT_CORNER));
+ break;
+ case Cursor::WestResize:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_LEFT_SIDE));
+ break;
+ case Cursor::NorthSouthResize:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_TOP_TEE));
+ break;
+ case Cursor::EastWestResize:
+ case Cursor::WestPanning:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_LEFT_SIDE));
+ break;
+ case Cursor::NorthEastSouthWestResize:
+ case Cursor::NorthWestSouthEastResize:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_SIZING));
+ break;
+ case Cursor::ColumnResize:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW));
+ break;
+ case Cursor::RowResize:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW));
+ break;
+ case Cursor::VerticalText:
+ m_platformCursor = createNamedCursor(CustomCursorVerticalText);
+ break;
+ case Cursor::Cell:
+ m_platformCursor = adoptGRef(gdk_cursor_new(GDK_PLUS));
+ break;
+ case Cursor::ContextMenu:
+ m_platformCursor = createNamedCursor(CustomCursorContextMenu);
+ break;
+ case Cursor::Alias:
+ m_platformCursor = createNamedCursor(CustomCursorAlias);
+ break;
+ case Cursor::Progress:
+ m_platformCursor = createNamedCursor(CustomCursorProgress);
+ break;
+ case Cursor::NoDrop:
+ case Cursor::NotAllowed:
+ m_platformCursor = createNamedCursor(CustomCursorNoDrop);
+ break;
+ case Cursor::Copy:
+ m_platformCursor = createNamedCursor(CustomCursorCopy);
+ break;
+ case Cursor::None:
+ m_platformCursor = createNamedCursor(CustomCursorNone);
+ break;
+ case Cursor::ZoomIn:
+ m_platformCursor = createNamedCursor(CustomCursorZoomIn);
+ break;
+ case Cursor::ZoomOut:
+ m_platformCursor = createNamedCursor(CustomCursorZoomOut);
+ break;
+ case Cursor::Grab:
+ m_platformCursor = createNamedCursor(CustomCursorGrab);
+ break;
+ case Cursor::Grabbing:
+ m_platformCursor = createNamedCursor(CustomCursorGrabbing);
+ break;
+ case Cursor::Custom:
+ m_platformCursor = createCustomCursor(m_image.get(), m_hotSpot);
+ break;
+ }
+}
+
+Cursor::Cursor(const Cursor& other)
+ : m_type(other.m_type)
+ , m_image(other.m_image)
+ , m_hotSpot(other.m_hotSpot)
+ , m_platformCursor(other.m_platformCursor)
+{
+}
+
+Cursor& Cursor::operator=(const Cursor& other)
+{
+ m_type = other.m_type;
+ m_image = other.m_image;
+ m_hotSpot = other.m_hotSpot;
+ m_platformCursor = other.m_platformCursor;
+ return *this;
+}
+
+Cursor::~Cursor()
+{
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/CursorGtk.h b/Source/WebCore/platform/gtk/CursorGtk.h
new file mode 100644
index 0000000..568919b
--- /dev/null
+++ b/Source/WebCore/platform/gtk/CursorGtk.h
@@ -0,0 +1,383 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Tim Copperfield.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Tim Copperfield <timecop@network.email.ne.jp>
+ * Christian Dywan <christian@twotoasts.de>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef CursorGtk_h
+#define CursorGtk_h
+
+#include "Cursor.h"
+
+/*
+ These cursors are copied from Mozilla code:
+ http://lxr.mozilla.org/mozilla1.8/source/widget/src/gtk2/nsGtkCursors.h
+*/
+
+/* MOZ_CURSOR_VERTICAL_TEXT */
+static const unsigned char moz_vertical_text_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00,
+ 0x06, 0x60, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00,
+ 0x02, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static const unsigned char moz_vertical_text_mask_bits[] = {
+ 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x0f, 0xf0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+/* MOZ_CURSOR_CONTEXT_MENU */
+static const unsigned char moz_menu_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
+ 0x7c, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0xfd, 0x00, 0x00,
+ 0xfc, 0xff, 0x00, 0x00, 0x7c, 0x84, 0x00, 0x00, 0x6c, 0xfc, 0x00, 0x00,
+ 0xc4, 0x84, 0x00, 0x00, 0xc0, 0xfc, 0x00, 0x00, 0x80, 0x85, 0x00, 0x00,
+ 0x80, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static const unsigned char moz_menu_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0xfe, 0x00, 0x00, 0x00, 0xfe, 0xfd, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x00,
+ 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xff, 0x01, 0x00, 0xfe, 0xfe, 0x01, 0x00,
+ 0xee, 0xff, 0x01, 0x00, 0xe4, 0xff, 0x01, 0x00, 0xc0, 0xff, 0x01, 0x00,
+ 0xc0, 0xff, 0x01, 0x00, 0x80, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+/* MOZ_CURSOR_COPY */
+static const unsigned char moz_copy_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
+ 0x7c, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00,
+ 0xfc, 0x03, 0x00, 0x00, 0x7c, 0x30, 0x00, 0x00, 0x6c, 0x30, 0x00, 0x00,
+ 0xc4, 0xfc, 0x00, 0x00, 0xc0, 0xfc, 0x00, 0x00, 0x80, 0x31, 0x00, 0x00,
+ 0x80, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static const unsigned char moz_copy_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00,
+ 0xfe, 0x37, 0x00, 0x00, 0xfe, 0x7b, 0x00, 0x00, 0xfe, 0xfc, 0x00, 0x00,
+ 0xee, 0xff, 0x01, 0x00, 0xe4, 0xff, 0x01, 0x00, 0xc0, 0xff, 0x00, 0x00,
+ 0xc0, 0x7b, 0x00, 0x00, 0x80, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+/* MOZ_CURSOR_ALIAS */
+static const unsigned char moz_alias_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
+ 0x7c, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00,
+ 0xfc, 0x03, 0x00, 0x00, 0x7c, 0xf0, 0x00, 0x00, 0x6c, 0xe0, 0x00, 0x00,
+ 0xc4, 0xf0, 0x00, 0x00, 0xc0, 0xb0, 0x00, 0x00, 0x80, 0x19, 0x00, 0x00,
+ 0x80, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static const unsigned char moz_alias_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00,
+ 0xfe, 0xf7, 0x00, 0x00, 0xfe, 0xfb, 0x01, 0x00, 0xfe, 0xf0, 0x01, 0x00,
+ 0xee, 0xf9, 0x01, 0x00, 0xe4, 0xf9, 0x01, 0x00, 0xc0, 0xbf, 0x00, 0x00,
+ 0xc0, 0x3f, 0x00, 0x00, 0x80, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+/* MOZ_CURSOR_ZOOM_IN */
+static const unsigned char moz_zoom_in_bits[] = {
+ 0xf0, 0x00, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00,
+ 0x62, 0x04, 0x00, 0x00, 0x61, 0x08, 0x00, 0x00, 0xf9, 0x09, 0x00, 0x00,
+ 0xf9, 0x09, 0x00, 0x00, 0x61, 0x08, 0x00, 0x00, 0x62, 0x04, 0x00, 0x00,
+ 0x02, 0x04, 0x00, 0x00, 0x0c, 0x0f, 0x00, 0x00, 0xf0, 0x1c, 0x00, 0x00,
+ 0x00, 0x38, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static const unsigned char moz_zoom_in_mask_bits[] = {
+ 0xf0, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00,
+ 0xfe, 0x07, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00,
+ 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00,
+ 0xfe, 0x07, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xf0, 0x1c, 0x00, 0x00,
+ 0x00, 0x38, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+/* MOZ_CURSOR_ZOOM_OUT */
+static const unsigned char moz_zoom_out_bits[] = {
+ 0xf0, 0x00, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00,
+ 0x02, 0x04, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0xf9, 0x09, 0x00, 0x00,
+ 0xf9, 0x09, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00,
+ 0x02, 0x04, 0x00, 0x00, 0x0c, 0x0f, 0x00, 0x00, 0xf0, 0x1c, 0x00, 0x00,
+ 0x00, 0x38, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static const unsigned char moz_zoom_out_mask_bits[] = {
+ 0xf0, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00,
+ 0xfe, 0x07, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00,
+ 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00,
+ 0xfe, 0x07, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0xf0, 0x1c, 0x00, 0x00,
+ 0x00, 0x38, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+/* MOZ_CURSOR_NOT_ALLOWED */
+static const unsigned char moz_not_allowed_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00,
+ 0xf0, 0xf0, 0x00, 0x00, 0x38, 0xc0, 0x01, 0x00, 0x7c, 0x80, 0x03, 0x00,
+ 0xec, 0x00, 0x03, 0x00, 0xce, 0x01, 0x07, 0x00, 0x86, 0x03, 0x06, 0x00,
+ 0x06, 0x07, 0x06, 0x00, 0x06, 0x0e, 0x06, 0x00, 0x06, 0x1c, 0x06, 0x00,
+ 0x0e, 0x38, 0x07, 0x00, 0x0c, 0x70, 0x03, 0x00, 0x1c, 0xe0, 0x03, 0x00,
+ 0x38, 0xc0, 0x01, 0x00, 0xf0, 0xf0, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00,
+ 0x80, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static const unsigned char moz_not_allowed_mask_bits[] = {
+ 0x80, 0x1f, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0xf0, 0xff, 0x00, 0x00,
+ 0xf8, 0xff, 0x01, 0x00, 0xfc, 0xf0, 0x03, 0x00, 0xfe, 0xc0, 0x07, 0x00,
+ 0xfe, 0x81, 0x07, 0x00, 0xff, 0x83, 0x0f, 0x00, 0xcf, 0x07, 0x0f, 0x00,
+ 0x8f, 0x0f, 0x0f, 0x00, 0x0f, 0x1f, 0x0f, 0x00, 0x0f, 0x3e, 0x0f, 0x00,
+ 0x1f, 0xfc, 0x0f, 0x00, 0x1e, 0xf8, 0x07, 0x00, 0x3e, 0xf0, 0x07, 0x00,
+ 0xfc, 0xf0, 0x03, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x00, 0x00,
+ 0xe0, 0x7f, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+/* MOZ_CURSOR_SPINNING */
+static const unsigned char moz_spinning_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00,
+ 0x7c, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00,
+ 0xfc, 0x3b, 0x00, 0x00, 0x7c, 0x38, 0x00, 0x00, 0x6c, 0x54, 0x00, 0x00,
+ 0xc4, 0xdc, 0x00, 0x00, 0xc0, 0x44, 0x00, 0x00, 0x80, 0x39, 0x00, 0x00,
+ 0x80, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static const unsigned char moz_spinning_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x3b, 0x00, 0x00,
+ 0xfe, 0x7f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00,
+ 0xee, 0xff, 0x01, 0x00, 0xe4, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00,
+ 0xc0, 0x7f, 0x00, 0x00, 0x80, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+/* MOZ_CURSOR_NONE */
+static const unsigned char moz_none_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static const unsigned char moz_none_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+/* MOZ_CURSOR_HAND_GRAB */
+static const unsigned char moz_hand_grab_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,
+ 0x60, 0x39, 0x00, 0x00, 0x90, 0x49, 0x00, 0x00, 0x90, 0x49, 0x01, 0x00,
+ 0x20, 0xc9, 0x02, 0x00, 0x20, 0x49, 0x02, 0x00, 0x58, 0x40, 0x02, 0x00,
+ 0x64, 0x00, 0x02, 0x00, 0x44, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x10, 0x80, 0x00, 0x00, 0x20, 0x80, 0x00, 0x00,
+ 0x40, 0x40, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static const unsigned char moz_hand_grab_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x60, 0x3f, 0x00, 0x00,
+ 0xf0, 0x7f, 0x00, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x03, 0x00,
+ 0xf0, 0xff, 0x07, 0x00, 0xf8, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x07, 0x00,
+ 0xfe, 0xff, 0x07, 0x00, 0xfe, 0xff, 0x03, 0x00, 0xfc, 0xff, 0x03, 0x00,
+ 0xf8, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x01, 0x00,
+ 0xe0, 0xff, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+/* MOZ_CURSOR_HAND_GRABBING */
+static const unsigned char moz_hand_grabbing_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xc0, 0x36, 0x00, 0x00, 0x20, 0xc9, 0x00, 0x00, 0x20, 0x40, 0x01, 0x00,
+ 0x40, 0x00, 0x01, 0x00, 0x60, 0x00, 0x01, 0x00, 0x10, 0x00, 0x01, 0x00,
+ 0x10, 0x00, 0x01, 0x00, 0x10, 0x80, 0x00, 0x00, 0x20, 0x80, 0x00, 0x00,
+ 0x40, 0x40, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static const unsigned char moz_hand_grabbing_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x36, 0x00, 0x00,
+ 0xe0, 0xff, 0x00, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x03, 0x00,
+ 0xe0, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x03, 0x00,
+ 0xf8, 0xff, 0x03, 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x01, 0x00,
+ 0xe0, 0xff, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+enum CustomCursorType {
+ CustomCursorCopy = 0,
+ CustomCursorAlias,
+ CustomCursorContextMenu,
+ CustomCursorZoomIn,
+ CustomCursorZoomOut,
+ CustomCursorVerticalText,
+ CustomCursorNoDrop,
+ CustomCursorProgress,
+ CustomCursorNone,
+ CustomCursorGrab,
+ CustomCursorGrabbing,
+};
+
+typedef struct {
+ const char* name;
+ const unsigned char* bits;
+ const unsigned char* mask_bits;
+ int hot_x;
+ int hot_y;
+} CustomCursor;
+
+// create custom pixmap cursor from cursors in nsGTKCursorData.h
+static const CustomCursor CustomCursors[] = {
+ { "copy", moz_copy_bits, moz_copy_mask_bits, 2, 2 },
+ { "alias", moz_alias_bits, moz_alias_mask_bits, 2, 2 },
+ { "context-menu", moz_menu_bits, moz_menu_mask_bits, 2, 2 },
+ { "zoom-in", moz_zoom_in_bits, moz_zoom_in_mask_bits, 6, 6 },
+ { "zoom-out", moz_zoom_out_bits, moz_zoom_out_mask_bits, 6, 6 },
+ { "vertical-text", moz_vertical_text_bits, moz_vertical_text_mask_bits, 8, 4 },
+ { "dnd-no-drop", moz_not_allowed_bits, moz_not_allowed_mask_bits, 9, 9 },
+ { "left_ptr_watch", moz_spinning_bits, moz_spinning_mask_bits, 2, 2},
+ { "none", moz_none_bits, moz_none_mask_bits, 0, 0 },
+ { "grab", moz_hand_grab_bits, moz_hand_grab_mask_bits, 10, 10 },
+ { "grabbing", moz_hand_grabbing_bits, moz_hand_grabbing_mask_bits, 10, 10 }
+};
+
+#endif // CursorGtk_h
diff --git a/Source/WebCore/platform/gtk/DataObjectGtk.cpp b/Source/WebCore/platform/gtk/DataObjectGtk.cpp
new file mode 100644
index 0000000..05a2da9
--- /dev/null
+++ b/Source/WebCore/platform/gtk/DataObjectGtk.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2009, Martin Robinson
+ *
+ * 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 "DataObjectGtk.h"
+
+#include "markup.h"
+#include <gtk/gtk.h>
+#include <wtf/gobject/GOwnPtr.h>
+
+namespace WebCore {
+
+static void replaceNonBreakingSpaceWithSpace(String& str)
+{
+ static const UChar NonBreakingSpaceCharacter = 0xA0;
+ static const UChar SpaceCharacter = ' ';
+ str.replace(NonBreakingSpaceCharacter, SpaceCharacter);
+}
+
+String DataObjectGtk::text()
+{
+ if (m_range)
+ return m_range->text();
+ return m_text;
+}
+
+String DataObjectGtk::markup()
+{
+ if (m_range)
+ return createMarkup(m_range.get(), 0, AnnotateForInterchange, false, AbsoluteURLs);
+ return m_markup;
+}
+
+void DataObjectGtk::setText(const String& newText)
+{
+ m_range = 0;
+ m_text = newText;
+ replaceNonBreakingSpaceWithSpace(m_text);
+}
+
+void DataObjectGtk::setMarkup(const String& newMarkup)
+{
+ m_range = 0;
+ m_markup = newMarkup;
+}
+
+void DataObjectGtk::setURIList(const String& uriListString)
+{
+ m_uriList = uriListString;
+
+ // This code is originally from: platform/chromium/ChromiumDataObject.cpp.
+ // FIXME: We should make this code cross-platform eventually.
+
+ // Line separator is \r\n per RFC 2483 - however, for compatibility
+ // reasons we also allow just \n here.
+ Vector<String> uriList;
+ uriListString.split('\n', uriList);
+
+ // Process the input and copy the first valid URL into the url member.
+ // In case no URLs can be found, subsequent calls to getData("URL")
+ // will get an empty string. This is in line with the HTML5 spec (see
+ // "The DragEvent and DataTransfer interfaces"). Also extract all filenames
+ // from the URI list.
+ bool setURL = false;
+ for (size_t i = 0; i < uriList.size(); ++i) {
+ String& line = uriList[i];
+ line = line.stripWhiteSpace();
+ if (line.isEmpty())
+ continue;
+ if (line[0] == '#')
+ continue;
+
+ KURL url = KURL(KURL(), line);
+ if (url.isValid()) {
+ if (!setURL) {
+ m_url = url;
+ setURL = true;
+ }
+
+ GOwnPtr<GError> error;
+ GOwnPtr<gchar> filename(g_filename_from_uri(line.utf8().data(), 0, &error.outPtr()));
+ if (!error && filename)
+ m_filenames.append(String::fromUTF8(filename.get()));
+ }
+ }
+}
+
+void DataObjectGtk::setURL(const KURL& url, const String& label)
+{
+ m_url = url;
+ m_uriList = url;
+ setText(url.string());
+
+ String actualLabel(label);
+ if (actualLabel.isEmpty())
+ actualLabel = url;
+
+ Vector<UChar> markup;
+ append(markup, "<a href=\"");
+ append(markup, url.string());
+ append(markup, "\">");
+ GOwnPtr<gchar> escaped(g_markup_escape_text(actualLabel.utf8().data(), -1));
+ append(markup, String::fromUTF8(escaped.get()));
+ append(markup, "</a>");
+ setMarkup(String::adopt(markup));
+}
+
+void DataObjectGtk::clearText()
+{
+ m_range = 0;
+ m_text = "";
+}
+
+void DataObjectGtk::clearMarkup()
+{
+ m_range = 0;
+ m_markup = "";
+}
+
+String DataObjectGtk::urlLabel()
+{
+ if (hasText())
+ return text();
+
+ if (hasURL())
+ return url();
+
+ return String();
+}
+
+void DataObjectGtk::clear()
+{
+ m_text = "";
+ m_markup = "";
+ m_uriList = "";
+ m_url = KURL();
+ m_image = 0;
+ m_range = 0;
+
+ // We do not clear filenames. According to the spec: "The clearData() method
+ // does not affect whether any files were included in the drag, so the types
+ // attribute's list might still not be empty after calling clearData() (it would
+ // still contain the "Files" string if any files were included in the drag)."
+}
+
+DataObjectGtk* DataObjectGtk::forClipboard(GtkClipboard* clipboard)
+{
+ static HashMap<GtkClipboard*, RefPtr<DataObjectGtk> > objectMap;
+
+ if (!objectMap.contains(clipboard)) {
+ RefPtr<DataObjectGtk> dataObject = DataObjectGtk::create();
+ objectMap.set(clipboard, dataObject);
+ return dataObject.get();
+ }
+
+ HashMap<GtkClipboard*, RefPtr<DataObjectGtk> >::iterator it = objectMap.find(clipboard);
+ return it->second.get();
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/DataObjectGtk.h b/Source/WebCore/platform/gtk/DataObjectGtk.h
new file mode 100644
index 0000000..5423f81
--- /dev/null
+++ b/Source/WebCore/platform/gtk/DataObjectGtk.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2009, Martin Robinson
+ *
+ * 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 DataObjectGtk_h
+#define DataObjectGtk_h
+
+#include "FileList.h"
+#include <GRefPtr.h>
+#include "KURL.h"
+#include "Range.h"
+#include <wtf/RefCounted.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+
+class DataObjectGtk : public RefCounted<DataObjectGtk> {
+public:
+ static PassRefPtr<DataObjectGtk> create()
+ {
+ return adoptRef(new DataObjectGtk());
+ }
+
+ const KURL& url() { return m_url; }
+ const String& uriList() { return m_uriList; }
+ const Vector<String>& filenames() { return m_filenames; }
+ GdkPixbuf* image() { return m_image.get(); }
+ void setRange(PassRefPtr<Range> newRange) { m_range = newRange; }
+ void setImage(GdkPixbuf* newImage) { m_image = newImage; }
+ void setDragContext(GdkDragContext* newDragContext) { m_dragContext = newDragContext; }
+ void setURL(const KURL&, const String&);
+ bool hasText() { return m_range || !m_text.isEmpty(); }
+ bool hasMarkup() { return m_range || !m_markup.isEmpty(); }
+ bool hasURIList() { return !m_uriList.isEmpty(); }
+ bool hasURL() { return !m_url.isEmpty() && m_url.isValid(); }
+ bool hasFilenames() { return !m_filenames.isEmpty(); }
+ bool hasImage() { return m_image; }
+ void clearURIList() { m_uriList = ""; }
+ void clearURL() { m_url = KURL(); }
+ void clearImage() { m_image = 0; }
+ GdkDragContext* dragContext() { return m_dragContext.get(); }
+
+ String text();
+ String markup();
+ void setText(const String&);
+ void setMarkup(const String&);
+ void setURIList(const String&);
+ String urlLabel();
+ void clear();
+ void clearText();
+ void clearMarkup();
+
+ static DataObjectGtk* forClipboard(GtkClipboard*);
+
+private:
+ String m_text;
+ String m_markup;
+ KURL m_url;
+ String m_uriList;
+ Vector<String> m_filenames;
+ GRefPtr<GdkPixbuf> m_image;
+ GRefPtr<GdkDragContext> m_dragContext;
+ RefPtr<Range> m_range;
+};
+
+}
+
+#endif // DataObjectGtk_h
diff --git a/Source/WebCore/platform/gtk/DragDataGtk.cpp b/Source/WebCore/platform/gtk/DragDataGtk.cpp
new file mode 100644
index 0000000..42ddb16
--- /dev/null
+++ b/Source/WebCore/platform/gtk/DragDataGtk.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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 "DragData.h"
+
+#include "Clipboard.h"
+#include "ClipboardGtk.h"
+#include "Document.h"
+#include "DocumentFragment.h"
+#include "markup.h"
+
+namespace WebCore {
+
+bool DragData::canSmartReplace() const
+{
+ return false;
+}
+
+bool DragData::containsColor() const
+{
+ return false;
+}
+
+bool DragData::containsFiles() const
+{
+ return m_platformDragData->hasFilenames();
+}
+
+void DragData::asFilenames(Vector<String>& result) const
+{
+ result = m_platformDragData->filenames();
+}
+
+bool DragData::containsPlainText() const
+{
+ return m_platformDragData->hasText();
+}
+
+String DragData::asPlainText() const
+{
+ return m_platformDragData->text();
+}
+
+Color DragData::asColor() const
+{
+ return Color();
+}
+
+bool DragData::containsCompatibleContent() const
+{
+ return containsPlainText() || containsURL() || m_platformDragData->hasMarkup() || containsColor() || containsFiles();
+}
+
+bool DragData::containsURL(FilenameConversionPolicy filenamePolicy) const
+{
+ return m_platformDragData->hasURL();
+}
+
+String DragData::asURL(FilenameConversionPolicy filenamePolicy, String* title) const
+{
+ String url(m_platformDragData->url());
+ if (title)
+ *title = m_platformDragData->urlLabel();
+ return url;
+}
+
+
+PassRefPtr<DocumentFragment> DragData::asFragment(Document* document) const
+{
+ if (!m_platformDragData->hasMarkup())
+ return 0;
+
+ return createFragmentFromMarkup(document, m_platformDragData->markup(), "");
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/DragImageGtk.cpp b/Source/WebCore/platform/gtk/DragImageGtk.cpp
new file mode 100644
index 0000000..71a65e1
--- /dev/null
+++ b/Source/WebCore/platform/gtk/DragImageGtk.cpp
@@ -0,0 +1,86 @@
+/*
+ * 2010 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 "DragImage.h"
+
+#include "CachedImage.h"
+#include "Image.h"
+#include "RefPtrCairo.h"
+#include <cairo.h>
+
+namespace WebCore {
+
+IntSize dragImageSize(DragImageRef image)
+{
+ if (image)
+ return IntSize(cairo_image_surface_get_width(image), cairo_image_surface_get_height(image));
+
+ return IntSize(0, 0);
+}
+
+void deleteDragImage(DragImageRef image)
+{
+ if (image)
+ cairo_surface_destroy(image);
+}
+
+DragImageRef scaleDragImage(DragImageRef image, FloatSize scale)
+{
+ if (!image)
+ return 0;
+
+ int newWidth = scale.width() * cairo_image_surface_get_width(image);
+ int newHeight = scale.height() * cairo_image_surface_get_height(image);
+ cairo_surface_t* scaledSurface = cairo_surface_create_similar(image, CAIRO_CONTENT_COLOR_ALPHA, newWidth, newHeight);
+
+ RefPtr<cairo_t> context = adoptRef(cairo_create(scaledSurface));
+ cairo_scale(context.get(), scale.width(), scale.height());
+ cairo_pattern_set_extend(cairo_get_source(context.get()), CAIRO_EXTEND_PAD);
+ cairo_pattern_set_filter(cairo_get_source(context.get()), CAIRO_FILTER_BEST);
+ cairo_set_operator(context.get(), CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_surface(context.get(), image, 0, 0);
+ cairo_paint(context.get());
+
+ deleteDragImage(image);
+ return scaledSurface;
+}
+
+DragImageRef dissolveDragImageToFraction(DragImageRef image, float fraction)
+{
+ if (!image)
+ return 0;
+
+ RefPtr<cairo_t> context = adoptRef(cairo_create(image));
+ cairo_set_operator(context.get(), CAIRO_OPERATOR_DEST_IN);
+ cairo_set_source_rgba(context.get(), 0, 0, 0, fraction);
+ cairo_paint(context.get());
+ return image;
+}
+
+DragImageRef createDragImageFromImage(Image* image)
+{
+ return cairo_surface_reference(image->nativeImageForCurrentFrame());
+}
+
+DragImageRef createDragImageIconForCachedImage(CachedImage*)
+{
+ return 0;
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/EventLoopGtk.cpp b/Source/WebCore/platform/gtk/EventLoopGtk.cpp
new file mode 100644
index 0000000..4ef7b5c
--- /dev/null
+++ b/Source/WebCore/platform/gtk/EventLoopGtk.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 Nuanti Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "EventLoop.h"
+
+#include <glib.h>
+
+namespace WebCore {
+
+void EventLoop::cycle()
+{
+ g_main_context_iteration(NULL, FALSE);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/gtk/FileChooserGtk.cpp b/Source/WebCore/platform/gtk/FileChooserGtk.cpp
new file mode 100644
index 0000000..54763d4
--- /dev/null
+++ b/Source/WebCore/platform/gtk/FileChooserGtk.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FileChooser.h"
+
+#include "FileSystem.h"
+#include "Icon.h"
+#include "LocalizedStrings.h"
+#include "StringTruncator.h"
+#include <wtf/text/CString.h>
+
+#include <glib.h>
+
+namespace WebCore {
+
+static bool stringByAdoptingFileSystemRepresentation(gchar* systemFilename, String& result)
+{
+ if (!systemFilename)
+ return false;
+
+ result = filenameToString(systemFilename);
+ g_free(systemFilename);
+
+ return true;
+}
+
+String FileChooser::basenameForWidth(const Font& font, int width) const
+{
+ if (width <= 0)
+ return String();
+
+ String string = fileButtonNoFileSelectedLabel();
+
+ if (m_filenames.size() == 1) {
+ CString systemFilename = fileSystemRepresentation(m_filenames[0]);
+ gchar* systemBasename = g_path_get_basename(systemFilename.data());
+ stringByAdoptingFileSystemRepresentation(systemBasename, string);
+ } else if (m_filenames.size() > 1)
+ return StringTruncator::rightTruncate(multipleFileUploadText(m_filenames.size()), width, font, false);
+
+ return StringTruncator::centerTruncate(string, width, font, false);
+}
+}
diff --git a/Source/WebCore/platform/gtk/FileSystemGtk.cpp b/Source/WebCore/platform/gtk/FileSystemGtk.cpp
new file mode 100644
index 0000000..b8aa102
--- /dev/null
+++ b/Source/WebCore/platform/gtk/FileSystemGtk.cpp
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2007, 2009 Holger Hans Peter Freyther
+ * Copyright (C) 2008 Collabora, Ltd.
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "FileSystem.h"
+
+#include "GOwnPtr.h"
+#include "PlatformString.h"
+#include "UUID.h"
+#include <gio/gio.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <wtf/gobject/GRefPtr.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+/* On linux file names are just raw bytes, so also strings that cannot be encoded in any way
+ * are valid file names. This mean that we cannot just store a file name as-is in a String
+ * but we have to escape it.
+ * On Windows the GLib file name encoding is always UTF-8 so we can optimize this case. */
+String filenameToString(const char* filename)
+{
+ if (!filename)
+ return String();
+
+#if OS(WINDOWS)
+ return String::fromUTF8(filename);
+#else
+ gchar* escapedString = g_uri_escape_string(filename, "/:", false);
+ String string(escapedString);
+ g_free(escapedString);
+ return string;
+#endif
+}
+
+CString fileSystemRepresentation(const String& path)
+{
+#if OS(WINDOWS)
+ return path.utf8();
+#else
+ char* filename = g_uri_unescape_string(path.utf8().data(), 0);
+ CString cfilename(filename);
+ g_free(filename);
+ return cfilename;
+#endif
+}
+
+// Converts a string to something suitable to be displayed to the user.
+String filenameForDisplay(const String& string)
+{
+#if OS(WINDOWS)
+ return string;
+#else
+ CString filename = fileSystemRepresentation(string);
+ gchar* display = g_filename_to_utf8(filename.data(), 0, 0, 0, 0);
+ if (!display)
+ return string;
+
+ String displayString = String::fromUTF8(display);
+ g_free(display);
+
+ return displayString;
+#endif
+}
+
+bool fileExists(const String& path)
+{
+ bool result = false;
+ CString filename = fileSystemRepresentation(path);
+
+ if (!filename.isNull())
+ result = g_file_test(filename.data(), G_FILE_TEST_EXISTS);
+
+ return result;
+}
+
+bool deleteFile(const String& path)
+{
+ bool result = false;
+ CString filename = fileSystemRepresentation(path);
+
+ if (!filename.isNull())
+ result = g_remove(filename.data()) == 0;
+
+ return result;
+}
+
+bool deleteEmptyDirectory(const String& path)
+{
+ bool result = false;
+ CString filename = fileSystemRepresentation(path);
+
+ if (!filename.isNull())
+ result = g_rmdir(filename.data()) == 0;
+
+ return result;
+}
+
+bool getFileSize(const String& path, long long& resultSize)
+{
+ CString filename = fileSystemRepresentation(path);
+ if (filename.isNull())
+ return false;
+
+ struct stat statResult;
+ gint result = g_stat(filename.data(), &statResult);
+ if (result != 0)
+ return false;
+
+ resultSize = statResult.st_size;
+ return true;
+}
+
+bool getFileModificationTime(const String& path, time_t& modifiedTime)
+{
+ CString filename = fileSystemRepresentation(path);
+ if (filename.isNull())
+ return false;
+
+ struct stat statResult;
+ gint result = g_stat(filename.data(), &statResult);
+ if (result != 0)
+ return false;
+
+ modifiedTime = statResult.st_mtime;
+ return true;
+
+}
+
+String pathByAppendingComponent(const String& path, const String& component)
+{
+ if (path.endsWith(G_DIR_SEPARATOR_S))
+ return path + component;
+ else
+ return path + G_DIR_SEPARATOR_S + component;
+}
+
+bool makeAllDirectories(const String& path)
+{
+ CString filename = fileSystemRepresentation(path);
+ if (filename.isNull())
+ return false;
+
+ gint result = g_mkdir_with_parents(filename.data(), S_IRWXU);
+
+ return result == 0;
+}
+
+String homeDirectoryPath()
+{
+ return filenameToString(g_get_home_dir());
+}
+
+String pathGetFileName(const String& pathName)
+{
+ if (pathName.isEmpty())
+ return pathName;
+
+ CString tmpFilename = fileSystemRepresentation(pathName);
+ char* baseName = g_path_get_basename(tmpFilename.data());
+ String fileName = String::fromUTF8(baseName);
+ g_free(baseName);
+
+ return fileName;
+}
+
+String directoryName(const String& path)
+{
+ /* No null checking needed */
+ GOwnPtr<char> dirname(g_path_get_dirname(fileSystemRepresentation(path).data()));
+ return String::fromUTF8(dirname.get());
+}
+
+Vector<String> listDirectory(const String& path, const String& filter)
+{
+ Vector<String> entries;
+
+ CString filename = fileSystemRepresentation(path);
+ GDir* dir = g_dir_open(filename.data(), 0, 0);
+ if (!dir)
+ return entries;
+
+ GPatternSpec *pspec = g_pattern_spec_new((filter.utf8()).data());
+ while (const char* name = g_dir_read_name(dir)) {
+ if (!g_pattern_match_string(pspec, name))
+ continue;
+
+ GOwnPtr<gchar> entry(g_build_filename(filename.data(), name, NULL));
+ entries.append(filenameToString(entry.get()));
+ }
+ g_pattern_spec_free(pspec);
+ g_dir_close(dir);
+
+ return entries;
+}
+
+CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle)
+{
+ GOwnPtr<gchar> filename(g_strdup_printf("%s%s", prefix, createCanonicalUUIDString().utf8().data()));
+ GOwnPtr<gchar> tempPath(g_build_filename(g_get_tmp_dir(), filename.get(), NULL));
+ GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(tempPath.get()));
+
+ handle = g_file_create_readwrite(file.get(), G_FILE_CREATE_NONE, 0, 0);
+ if (!isHandleValid(handle))
+ return CString();
+ return tempPath.get();
+}
+
+PlatformFileHandle openFile(const String& path, FileOpenMode mode)
+{
+ CString fsRep = fileSystemRepresentation(path);
+ if (fsRep.isNull())
+ return invalidPlatformFileHandle;
+
+ GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(fsRep.data()));
+ GFileIOStream* ioStream = 0;
+ if (mode == OpenForRead)
+ ioStream = g_file_open_readwrite(file.get(), 0, 0);
+ else if (mode == OpenForWrite) {
+ if (g_file_test(fsRep.data(), static_cast<GFileTest>(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)))
+ ioStream = g_file_open_readwrite(file.get(), 0, 0);
+ else
+ ioStream = g_file_create_readwrite(file.get(), G_FILE_CREATE_NONE, 0, 0);
+ }
+
+ return ioStream;
+}
+
+void closeFile(PlatformFileHandle& handle)
+{
+ if (!isHandleValid(handle))
+ return;
+
+ g_io_stream_close(G_IO_STREAM(handle), 0, 0);
+ g_object_unref(handle);
+ handle = invalidPlatformFileHandle;
+}
+
+long long seekFile(PlatformFileHandle handle, long long offset, FileSeekOrigin origin)
+{
+ GSeekType seekType = G_SEEK_SET;
+ switch (origin) {
+ case SeekFromBeginning:
+ seekType = G_SEEK_SET;
+ break;
+ case SeekFromCurrent:
+ seekType = G_SEEK_CUR;
+ break;
+ case SeekFromEnd:
+ seekType = G_SEEK_END;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ if (!g_seekable_seek(G_SEEKABLE(g_io_stream_get_input_stream(G_IO_STREAM(handle))),
+ offset, seekType, 0, 0))
+ return -1;
+ return g_seekable_tell(G_SEEKABLE(g_io_stream_get_input_stream(G_IO_STREAM(handle))));
+}
+
+int writeToFile(PlatformFileHandle handle, const char* data, int length)
+{
+ gsize bytesWritten;
+ g_output_stream_write_all(g_io_stream_get_output_stream(G_IO_STREAM(handle)),
+ data, length, &bytesWritten, 0, 0);
+ return bytesWritten;
+}
+
+int readFromFile(PlatformFileHandle handle, char* data, int length)
+{
+ GOwnPtr<GError> error;
+ do {
+ gssize bytesRead = g_input_stream_read(g_io_stream_get_input_stream(G_IO_STREAM(handle)),
+ data, length, 0, &error.outPtr());
+ if (bytesRead >= 0)
+ return bytesRead;
+ } while (error && error->code == G_FILE_ERROR_INTR);
+ return -1;
+}
+
+bool unloadModule(PlatformModule module)
+{
+ return g_module_close(module);
+}
+}
diff --git a/Source/WebCore/platform/gtk/GOwnPtrGtk.cpp b/Source/WebCore/platform/gtk/GOwnPtrGtk.cpp
new file mode 100644
index 0000000..9b693f4
--- /dev/null
+++ b/Source/WebCore/platform/gtk/GOwnPtrGtk.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010 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 "GOwnPtrGtk.h"
+
+#include <gtk/gtk.h>
+
+namespace WTF {
+
+template <> void freeOwnedGPtr<GdkEvent>(GdkEvent* ptr)
+{
+ if (ptr)
+ gdk_event_free(ptr);
+}
+
+template <> void freeOwnedGPtr<GtkIconInfo>(GtkIconInfo* info)
+{
+ if (info)
+ gtk_icon_info_free(info);
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/GOwnPtrGtk.h b/Source/WebCore/platform/gtk/GOwnPtrGtk.h
new file mode 100644
index 0000000..c5d9cdc
--- /dev/null
+++ b/Source/WebCore/platform/gtk/GOwnPtrGtk.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GOwnPtrGtk_h
+#define GOwnPtrGtk_h
+
+#include "GOwnPtr.h"
+
+namespace WTF {
+
+template <> void freeOwnedGPtr<GdkEvent>(GdkEvent*);
+template <> void freeOwnedGPtr<GtkIconInfo>(GtkIconInfo*);
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/gtk/GRefPtrGtk.cpp b/Source/WebCore/platform/gtk/GRefPtrGtk.cpp
new file mode 100644
index 0000000..6647b99
--- /dev/null
+++ b/Source/WebCore/platform/gtk/GRefPtrGtk.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 Collabora Ltd.
+ * Copyright (C) 2009 Martin Robinson
+ *
+ * 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 "GRefPtrGtk.h"
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+namespace WTF {
+
+template <> GtkTargetList* refGPtr(GtkTargetList* ptr)
+{
+ if (ptr)
+ gtk_target_list_ref(ptr);
+ return ptr;
+}
+
+template <> void derefGPtr(GtkTargetList* ptr)
+{
+ if (ptr)
+ gtk_target_list_unref(ptr);
+}
+
+template <> GdkCursor* refGPtr(GdkCursor* ptr)
+{
+ if (ptr)
+ gdk_cursor_ref(ptr);
+ return ptr;
+}
+
+template <> void derefGPtr(GdkCursor* ptr)
+{
+ if (ptr)
+ gdk_cursor_unref(ptr);
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/GRefPtrGtk.h b/Source/WebCore/platform/gtk/GRefPtrGtk.h
new file mode 100644
index 0000000..1fb9772
--- /dev/null
+++ b/Source/WebCore/platform/gtk/GRefPtrGtk.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008 Collabora Ltd.
+ * Copyright (C) 2009 Martin Robinson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GRefPtrGtk_h
+#define GRefPtrGtk_h
+
+#include <wtf/gobject/GRefPtr.h>
+
+namespace WTF {
+
+template <> GtkTargetList* refGPtr(GtkTargetList* ptr);
+template <> void derefGPtr(GtkTargetList* ptr);
+
+template <> GdkCursor* refGPtr(GdkCursor* ptr);
+template <> void derefGPtr(GdkCursor* ptr);
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/gtk/GeolocationServiceGtk.cpp b/Source/WebCore/platform/gtk/GeolocationServiceGtk.cpp
new file mode 100644
index 0000000..5b34c68
--- /dev/null
+++ b/Source/WebCore/platform/gtk/GeolocationServiceGtk.cpp
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "GeolocationServiceGtk.h"
+#if ENABLE(GEOLOCATION)
+
+#include "GOwnPtr.h"
+#include "NotImplemented.h"
+#include "PositionOptions.h"
+#include <wtf/text/CString.h>
+
+namespace WTF {
+ template<> void freeOwnedGPtr<GeoclueAccuracy>(GeoclueAccuracy* accuracy)
+ {
+ if (!accuracy)
+ return;
+
+ geoclue_accuracy_free(accuracy);
+ }
+}
+
+namespace WebCore {
+
+GeolocationService* GeolocationServiceGtk::create(GeolocationServiceClient* client)
+{
+ return new GeolocationServiceGtk(client);
+}
+
+GeolocationService::FactoryFunction* GeolocationService::s_factoryFunction = &GeolocationServiceGtk::create;
+
+GeolocationServiceGtk::GeolocationServiceGtk(GeolocationServiceClient* client)
+ : GeolocationService(client)
+ , m_geoclueClient(0)
+ , m_geocluePosition(0)
+ , m_latitude(0.0)
+ , m_longitude(0.0)
+ , m_altitude(0.0)
+ , m_altitudeAccuracy(0.0)
+ , m_timestamp(0)
+{
+}
+
+GeolocationServiceGtk::~GeolocationServiceGtk()
+{
+ if (m_geoclueClient)
+ g_object_unref(m_geoclueClient);
+
+ if (m_geocluePosition)
+ g_object_unref(m_geocluePosition);
+}
+
+//
+// 1.) Initialize Geoclue with our requirements
+// 2.) Try to get a GeocluePosition
+// 3.) Update the Information and get the current position
+//
+// TODO: Also get GeoclueVelocity but there is no master client
+// API for that.
+//
+bool GeolocationServiceGtk::startUpdating(PositionOptions* options)
+{
+ ASSERT(!m_geoclueClient);
+
+ m_lastPosition = 0;
+ m_lastError = 0;
+
+ GOwnPtr<GError> error;
+ GeoclueMaster* master = geoclue_master_get_default();
+ GeoclueMasterClient* client = geoclue_master_create_client(master, 0, 0);
+ g_object_unref(master);
+
+ if (!client) {
+ setError(PositionError::POSITION_UNAVAILABLE, "Could not connect to location provider.");
+ return false;
+ }
+
+ GeoclueAccuracyLevel accuracyLevel = GEOCLUE_ACCURACY_LEVEL_LOCALITY;
+ int timeout = 0;
+ if (options) {
+ accuracyLevel = options->enableHighAccuracy() ? GEOCLUE_ACCURACY_LEVEL_DETAILED : GEOCLUE_ACCURACY_LEVEL_LOCALITY;
+ if (options->hasTimeout())
+ timeout = options->timeout();
+ }
+
+ gboolean result = geoclue_master_client_set_requirements(client, accuracyLevel, timeout,
+ false, GEOCLUE_RESOURCE_ALL, &error.outPtr());
+
+ if (!result) {
+ setError(PositionError::POSITION_UNAVAILABLE, error->message);
+ g_object_unref(client);
+ return false;
+ }
+
+ m_geocluePosition = geoclue_master_client_create_position(client, &error.outPtr());
+ if (!m_geocluePosition) {
+ setError(PositionError::POSITION_UNAVAILABLE, error->message);
+ g_object_unref(client);
+ return false;
+ }
+
+ m_geoclueClient = client;
+
+ geoclue_position_get_position_async(m_geocluePosition, (GeocluePositionCallback)getPositionCallback, this);
+
+ g_signal_connect(G_OBJECT(m_geocluePosition), "position-changed",
+ G_CALLBACK(position_changed), this);
+
+ return true;
+}
+
+void GeolocationServiceGtk::stopUpdating()
+{
+ if (!m_geoclueClient)
+ return;
+
+ g_object_unref(m_geocluePosition);
+ g_object_unref(m_geoclueClient);
+
+ m_geocluePosition = 0;
+ m_geoclueClient = 0;
+}
+
+void GeolocationServiceGtk::suspend()
+{
+ // not available with geoclue
+ notImplemented();
+}
+
+void GeolocationServiceGtk::resume()
+{
+ // not available with geoclue
+ notImplemented();
+}
+
+Geoposition* GeolocationServiceGtk::lastPosition() const
+{
+ return m_lastPosition.get();
+}
+
+PositionError* GeolocationServiceGtk::lastError() const
+{
+ return m_lastError.get();
+}
+
+void GeolocationServiceGtk::updatePosition()
+{
+ m_lastError = 0;
+
+ RefPtr<Coordinates> coordinates = Coordinates::create(m_latitude, m_longitude,
+ true, m_altitude, m_accuracy,
+ true, m_altitudeAccuracy, false, 0.0, false, 0.0);
+ m_lastPosition = Geoposition::create(coordinates.release(), m_timestamp * 1000.0);
+ positionChanged();
+}
+
+void GeolocationServiceGtk::getPositionCallback(GeocluePosition *position,
+ GeocluePositionFields fields,
+ int timestamp,
+ double latitude,
+ double longitude,
+ double altitude,
+ GeoclueAccuracy* accuracy,
+ GError* error,
+ GeolocationServiceGtk* that)
+{
+ if (error) {
+ that->setError(PositionError::POSITION_UNAVAILABLE, error->message);
+ g_error_free(error);
+ return;
+ }
+ position_changed(position, fields, timestamp, latitude, longitude, altitude, accuracy, that);
+}
+
+void GeolocationServiceGtk::position_changed(GeocluePosition*, GeocluePositionFields fields, int timestamp, double latitude, double longitude, double altitude, GeoclueAccuracy* accuracy, GeolocationServiceGtk* that)
+{
+ if (!(fields & GEOCLUE_POSITION_FIELDS_LATITUDE && fields & GEOCLUE_POSITION_FIELDS_LONGITUDE)) {
+ that->setError(PositionError::POSITION_UNAVAILABLE, "Position could not be determined.");
+ return;
+ }
+
+ that->m_timestamp = timestamp;
+ that->m_latitude = latitude;
+ that->m_longitude = longitude;
+ that->m_altitude = altitude;
+
+ GeoclueAccuracyLevel level;
+ geoclue_accuracy_get_details(accuracy, &level, &that->m_accuracy, &that->m_altitudeAccuracy);
+ that->updatePosition();
+}
+
+void GeolocationServiceGtk::setError(PositionError::ErrorCode errorCode, const char* message)
+{
+ m_lastPosition = 0;
+ m_lastError = PositionError::create(errorCode, String::fromUTF8(message));
+}
+
+}
+#endif // ENABLE(GEOLOCATION)
diff --git a/Source/WebCore/platform/gtk/GeolocationServiceGtk.h b/Source/WebCore/platform/gtk/GeolocationServiceGtk.h
new file mode 100644
index 0000000..46249ed
--- /dev/null
+++ b/Source/WebCore/platform/gtk/GeolocationServiceGtk.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GeolocationServiceGtk_h
+#define GeolocationServiceGtk_h
+#if ENABLE(GEOLOCATION)
+
+#include "GeolocationService.h"
+#include "Geoposition.h"
+#include "PositionError.h"
+#include "RefPtr.h"
+
+#include <geoclue/geoclue-master.h>
+#include <geoclue/geoclue-position.h>
+
+namespace WebCore {
+ class GeolocationServiceGtk : public GeolocationService {
+ public:
+ static GeolocationService* create(GeolocationServiceClient*);
+ ~GeolocationServiceGtk();
+
+ virtual bool startUpdating(PositionOptions*);
+ virtual void stopUpdating();
+
+ virtual void suspend();
+ virtual void resume();
+
+ Geoposition* lastPosition() const;
+ PositionError* lastError() const;
+
+ private:
+ GeolocationServiceGtk(GeolocationServiceClient*);
+
+ void setError(PositionError::ErrorCode, const char* message);
+ void updatePosition();
+
+ static void position_changed(GeocluePosition*, GeocluePositionFields, int, double, double, double, GeoclueAccuracy*, GeolocationServiceGtk*);
+ static void getPositionCallback(GeocluePosition*, GeocluePositionFields, int, double, double, double, GeoclueAccuracy*, GError*, GeolocationServiceGtk*);
+
+ private:
+ RefPtr<Geoposition> m_lastPosition;
+ RefPtr<PositionError> m_lastError;
+
+ // state objects
+ GeoclueMasterClient* m_geoclueClient;
+ GeocluePosition* m_geocluePosition;
+
+ // Error and Position state
+ double m_latitude;
+ double m_longitude;
+ double m_altitude;
+ double m_accuracy;
+ double m_altitudeAccuracy;
+ int m_timestamp;
+ };
+}
+
+#endif // ENABLE(GEOLOCATION)
+#endif
diff --git a/Source/WebCore/platform/gtk/GtkPluginWidget.cpp b/Source/WebCore/platform/gtk/GtkPluginWidget.cpp
new file mode 100644
index 0000000..331f60f
--- /dev/null
+++ b/Source/WebCore/platform/gtk/GtkPluginWidget.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2009 Holger Hans Peter Freyther
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GtkPluginWidget.h"
+
+#include "GraphicsContext.h"
+#include "GtkVersioning.h"
+#include "ScrollView.h"
+
+#include <gtk/gtk.h>
+
+namespace WebCore {
+
+GtkPluginWidget::GtkPluginWidget(GtkWidget* widget)
+ : Widget(widget)
+{
+ gtk_widget_hide(widget);
+}
+
+void GtkPluginWidget::invalidateRect(const IntRect& _rect)
+{
+ /* no need to */
+ if (!gtk_widget_get_has_window(platformWidget()))
+ return;
+
+ GdkWindow* window = gtk_widget_get_window(platformWidget());
+ if (!window)
+ return;
+
+ GdkRectangle rect = _rect;
+ gdk_window_invalidate_rect(window, &rect, FALSE);
+}
+
+void GtkPluginWidget::frameRectsChanged()
+{
+ IntRect rect = frameRect();
+ IntPoint loc = parent()->contentsToWindow(rect.location());
+ GtkAllocation allocation = { loc.x(), loc.y(), rect.width(), rect.height() };
+
+ gtk_widget_set_size_request(platformWidget(), rect.width(), rect.height());
+ gtk_widget_size_allocate(platformWidget(), &allocation);
+ gtk_widget_show(platformWidget());
+}
+
+void GtkPluginWidget::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (!context->gdkExposeEvent())
+ return;
+
+ /* only paint widgets with no window this way */
+ if (gtk_widget_get_has_window(platformWidget()))
+ return;
+
+ GtkWidget* widget = platformWidget();
+ ASSERT(!gtk_widget_get_has_window(widget));
+
+ GdkEvent* event = gdk_event_new(GDK_EXPOSE);
+ event->expose = *context->gdkExposeEvent();
+ event->expose.area = static_cast<GdkRectangle>(rect);
+
+ IntPoint loc = parent()->contentsToWindow(rect.location());
+
+ event->expose.area.x = loc.x();
+ event->expose.area.y = loc.y();
+
+#ifdef GTK_API_VERSION_2
+ event->expose.region = gdk_region_rectangle(&event->expose.area);
+#else
+ event->expose.region = cairo_region_create_rectangle(&event->expose.area);
+#endif
+
+ /*
+ * This will be unref'ed by gdk_event_free.
+ */
+ g_object_ref(event->expose.window);
+
+ /*
+ * If we are going to paint do the translation and GtkAllocation manipulation.
+ */
+#ifdef GTK_API_VERSION_2
+ if (!gdk_region_empty(event->expose.region))
+#else
+ if (!cairo_region_is_empty(event->expose.region))
+#endif
+ gtk_widget_send_expose(widget, event);
+
+ gdk_event_free(event);
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/GtkPluginWidget.h b/Source/WebCore/platform/gtk/GtkPluginWidget.h
new file mode 100644
index 0000000..cad3462
--- /dev/null
+++ b/Source/WebCore/platform/gtk/GtkPluginWidget.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009 Holger Hans Peter Freyther
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GtkPluginWidget_h
+#define GtkPluginWidget_h
+
+#include "Widget.h"
+
+namespace WebCore {
+ class GtkPluginWidget : public Widget {
+ public:
+ GtkPluginWidget(GtkWidget*);
+ void invalidateRect(const IntRect&);
+ void frameRectsChanged();
+ void paint(GraphicsContext*, const IntRect&);
+ };
+}
+
+#endif
diff --git a/Source/WebCore/platform/gtk/GtkVersioning.c b/Source/WebCore/platform/gtk/GtkVersioning.c
new file mode 100644
index 0000000..c3407ea
--- /dev/null
+++ b/Source/WebCore/platform/gtk/GtkVersioning.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2010 Collabora Ltd.
+ * Copyright (C) 2010 Igalia, S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "GtkVersioning.h"
+
+#include <gtk/gtk.h>
+
+#if !GTK_CHECK_VERSION(2, 14, 0)
+void gtk_adjustment_set_value(GtkAdjustment* adjusment, gdouble value)
+{
+ m_adjustment->value = m_currentPos;
+ gtk_adjustment_value_changed(m_adjustment);
+}
+
+void gtk_adjustment_configure(GtkAdjustment* adjustment, gdouble value, gdouble lower, gdouble upper,
+ gdouble stepIncrement, gdouble pageIncrement, gdouble pageSize)
+{
+ g_object_freeze_notify(G_OBJECT(adjustment));
+
+ g_object_set(adjustment,
+ "lower", lower,
+ "upper", upper,
+ "step-increment", stepIncrement,
+ "page-increment", pageIncrement,
+ "page-size", pageSize,
+ NULL);
+
+ g_object_thaw_notify(G_OBJECT(adjustment));
+
+ gtk_adjustment_changed(adjustment);
+ gtk_adjustment_value_changed(adjustment);
+}
+#endif
+
+GdkDevice *getDefaultGDKPointerDevice(GdkWindow* window)
+{
+#ifndef GTK_API_VERSION_2
+ GdkDeviceManager *manager = gdk_display_get_device_manager(gdk_window_get_display(window));
+ return gdk_device_manager_get_client_pointer(manager);
+#else
+ return gdk_device_get_core_pointer();
+#endif // GTK_API_VERSION_2
+}
+
+#if !GTK_CHECK_VERSION(2, 17, 3)
+void gdk_window_get_root_coords(GdkWindow* window, gint x, gint y, gint* rootX, gint* rootY)
+{
+ gdk_window_get_root_origin(window, rootX, rootY);
+ *rootX = *rootX + x;
+ *rootY = *rootY + y;
+}
+#endif
+
+GdkCursor * blankCursor()
+{
+#if GTK_CHECK_VERSION(2, 16, 0)
+ return gdk_cursor_new(GDK_BLANK_CURSOR);
+#else
+ GdkCursor * cursor;
+ GdkPixmap * source;
+ GdkPixmap * mask;
+ GdkColor foreground = { 0, 65535, 0, 0 }; // Red.
+ GdkColor background = { 0, 0, 0, 65535 }; // Blue.
+ static gchar cursorBits[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+
+ source = gdk_bitmap_create_from_data(0, cursorBits, 8, 8);
+ mask = gdk_bitmap_create_from_data(0, cursorBits, 8, 8);
+ cursor = gdk_cursor_new_from_pixmap(source, mask, &foreground, &background, 8, 8);
+ gdk_pixmap_unref(source);
+ gdk_pixmap_unref(mask);
+ return cursor;
+#endif // GTK_CHECK_VERSION(2, 16, 0)
+}
+
+#if !GTK_CHECK_VERSION(2, 16, 0)
+const gchar* gtk_menu_item_get_label(GtkMenuItem* menuItem)
+{
+ GtkWidget * label = gtk_bin_get_child(GTK_BIN(menuItem));
+ if (GTK_IS_LABEL(label))
+ return gtk_label_get_text(GTK_LABEL(label));
+ return 0;
+}
+#endif // GTK_CHECK_VERSION(2, 16, 0)
+
+#ifdef GTK_API_VERSION_2
+static cairo_format_t
+gdk_cairo_format_for_content(cairo_content_t content)
+{
+ switch (content) {
+ case CAIRO_CONTENT_COLOR:
+ return CAIRO_FORMAT_RGB24;
+ case CAIRO_CONTENT_ALPHA:
+ return CAIRO_FORMAT_A8;
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ default:
+ return CAIRO_FORMAT_ARGB32;
+ }
+}
+
+static cairo_surface_t*
+gdk_cairo_surface_coerce_to_image(cairo_surface_t* surface,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ cairo_surface_t * copy;
+ cairo_t * cr;
+
+ if (cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE
+ && cairo_surface_get_content(surface) == content
+ && cairo_image_surface_get_width(surface) >= width
+ && cairo_image_surface_get_height(surface) >= height)
+ return cairo_surface_reference(surface);
+
+ copy = cairo_image_surface_create(gdk_cairo_format_for_content(content),
+ width,
+ height);
+
+ cr = cairo_create(copy);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_surface(cr, surface, 0, 0);
+ cairo_paint(cr);
+ cairo_destroy(cr);
+
+ return copy;
+}
+
+static void
+convert_alpha(guchar * destData, int destStride,
+ guchar * srcData, int srcStride,
+ int srcX, int srcY, int width, int height)
+{
+ int x, y;
+
+ srcData += srcStride * srcY + srcY * 4;
+
+ for (y = 0; y < height; y++) {
+ guint32 * src = (guint32 *) srcData;
+
+ for (x = 0; x < width; x++) {
+ guint alpha = src[x] >> 24;
+
+ if (!alpha) {
+ destData[x * 4 + 0] = 0;
+ destData[x * 4 + 1] = 0;
+ destData[x * 4 + 2] = 0;
+ } else {
+ destData[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
+ destData[x * 4 + 1] = (((src[x] & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
+ destData[x * 4 + 2] = (((src[x] & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
+ }
+ destData[x * 4 + 3] = alpha;
+ }
+
+ srcData += srcStride;
+ destData += destStride;
+ }
+}
+
+static void
+convert_no_alpha(guchar * destData, int destStride, guchar * srcData,
+ int srcStride, int srcX, int srcY,
+ int width, int height)
+{
+ int x, y;
+
+ srcData += srcStride * srcY + srcX * 4;
+
+ for (y = 0; y < height; y++) {
+ guint32 * src = (guint32 *) srcData;
+
+ for (x = 0; x < width; x++) {
+ destData[x * 3 + 0] = src[x] >> 16;
+ destData[x * 3 + 1] = src[x] >> 8;
+ destData[x * 3 + 2] = src[x];
+ }
+
+ srcData += srcStride;
+ destData += destStride;
+ }
+}
+
+/**
+ * gdk_pixbuf_get_from_surface:
+ * @surface: surface to copy from
+ * @src_x: Source X coordinate within @surface
+ * @src_y: Source Y coordinate within @surface
+ * @width: Width in pixels of region to get
+ * @height: Height in pixels of region to get
+ *
+ * Transfers image data from a #cairo_surface_t and converts it to an RGB(A)
+ * representation inside a #GdkPixbuf. This allows you to efficiently read
+ * individual pixels from cairo surfaces. For #GdkWindows, use
+ * gdk_pixbuf_get_from_window() instead.
+ *
+ * This function will create an RGB pixbuf with 8 bits per channel. The pixbuf
+ * will contain an alpha channel if the @surface contains one.
+ *
+ * Return value: (transfer full): A newly-created pixbuf with a reference count
+ * of 1, or %NULL on error
+ **/
+GdkPixbuf*
+gdk_pixbuf_get_from_surface(cairo_surface_t * surface,
+ int srcX, int srcY,
+ int width, int height)
+{
+ cairo_content_t content;
+ GdkPixbuf * dest;
+
+ /* General sanity checks */
+ g_return_val_if_fail(surface, NULL);
+ g_return_val_if_fail(srcX >= 0 && srcY >= 0, NULL);
+ g_return_val_if_fail(width > 0 && height > 0, NULL);
+
+ content = cairo_surface_get_content(surface) | CAIRO_CONTENT_COLOR;
+ dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
+ !!(content & CAIRO_CONTENT_ALPHA),
+ 8,
+ width, height);
+
+ surface = gdk_cairo_surface_coerce_to_image(surface, content, srcX + width, srcY + height);
+ cairo_surface_flush(surface);
+ if (cairo_surface_status(surface) || !dest) {
+ cairo_surface_destroy(surface);
+ return NULL;
+ }
+
+ if (gdk_pixbuf_get_has_alpha(dest))
+ convert_alpha(gdk_pixbuf_get_pixels(dest),
+ gdk_pixbuf_get_rowstride(dest),
+ cairo_image_surface_get_data(surface),
+ cairo_image_surface_get_stride(surface),
+ srcX, srcY,
+ width, height);
+ else
+ convert_no_alpha(gdk_pixbuf_get_pixels(dest),
+ gdk_pixbuf_get_rowstride(dest),
+ cairo_image_surface_get_data(surface),
+ cairo_image_surface_get_stride(surface),
+ srcX, srcY,
+ width, height);
+
+ cairo_surface_destroy(surface);
+ return dest;
+}
+
+#endif // GTK_API_VERSION_2
+
+#if !GLIB_CHECK_VERSION(2, 27, 1)
+gboolean g_signal_accumulator_first_wins(GSignalInvocationHint *invocationHint, GValue *returnAccumulator, const GValue *handlerReturn, gpointer data)
+{
+ g_value_copy(handlerReturn, returnAccumulator);
+ return FALSE;
+}
+#endif
+
diff --git a/Source/WebCore/platform/gtk/GtkVersioning.h b/Source/WebCore/platform/gtk/GtkVersioning.h
new file mode 100644
index 0000000..11d1f8a
--- /dev/null
+++ b/Source/WebCore/platform/gtk/GtkVersioning.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2010 Collabora Ltd.
+ * Copyright (C) 2010 Igalia, S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GtkVersioning_h
+#define GtkVersioning_h
+
+#include <gtk/gtk.h>
+
+#ifndef GTK_API_VERSION_2
+#include <gdk/gdkkeysyms-compat.h>
+#endif
+
+G_BEGIN_DECLS
+
+// Macros to avoid deprecation checking churn
+#ifndef GTK_API_VERSION_2
+#define GDK_WINDOW_XWINDOW(window) (gdk_x11_window_get_xid(window))
+#else
+GdkPixbuf* gdk_pixbuf_get_from_surface(cairo_surface_t* surface, int srcX, int srcY,
+ int width, int height);
+#endif
+
+#if !GTK_CHECK_VERSION(2, 24, 0)
+#define gdk_window_get_display(window) gdk_drawable_get_display(window)
+#ifdef GDK_DISABLE_DEPRECATED
+#define gdk_window_get_visual gdk_drawable_get_visual
+#endif
+#endif // GTK_CHECK_VERSION(2, 24, 0)
+
+#if !GTK_CHECK_VERSION(2, 21, 2)
+#define gdk_visual_get_depth(visual) (visual)->depth
+#define gdk_visual_get_bits_per_rgb(visual) (visual)->bits_per_rgb
+#define gdk_drag_context_get_selected_action(context) (context)->action
+#define gdk_drag_context_get_actions(context) (context)->actions
+#endif // GTK_CHECK_VERSION(2, 21, 2)
+
+#if !GTK_CHECK_VERSION(2, 20, 0)
+#define gtk_widget_get_realized(widget) GTK_WIDGET_REALIZED(widget)
+#define gtk_widget_set_realized(widget, TRUE) GTK_WIDGET_SET_FLAGS((widget), GTK_REALIZED)
+#define gtk_range_get_min_slider_size(range) (range)->min_slider_size
+#endif // GTK_CHECK_VERSION(2, 20, 0)
+
+#if !GTK_CHECK_VERSION(2, 19, 0)
+#define gtk_widget_is_toplevel(widget) GTK_WIDGET_TOPLEVEL(widget)
+#define gtk_widget_get_realized(widget) GTK_WIDGET_REALIZED(widget)
+#define gtk_widget_get_has_window(widget) !GTK_WIDGET_NO_WINDOW(widget)
+#define gtk_widget_get_can_focus(widget) GTK_WIDGET_CAN_FOCUS(widget)
+#define gtk_widget_is_sensitive(widget) GTK_WIDGET_IS_SENSITIVE(widget)
+#endif // GTK_CHECK_VERSION(2, 19, 0)
+
+#if !GTK_CHECK_VERSION(2, 18, 0)
+#define gtk_widget_set_visible(widget, FALSE) GTK_WIDGET_UNSET_FLAGS((widget), GTK_VISIBLE)
+#define gtk_widget_get_visible(widget) (GTK_WIDGET_FLAGS(widget) & GTK_VISIBLE)
+
+#define gtk_widget_set_window(widget, new_window) (widget)->window = (new_window)
+#define gtk_widget_set_can_focus(widget, TRUE) GTK_WIDGET_SET_FLAGS((widget), GTK_CAN_FOCUS)
+#define gtk_widget_get_allocation(widget, alloc) (*(alloc) = (widget)->allocation)
+#define gtk_widget_set_allocation(widget, alloc) ((widget)->allocation = *(alloc))
+#endif // GTK_CHECK_VERSION(2, 18, 0)
+
+#if !GTK_CHECK_VERSION(2, 17, 3)
+void gdk_window_get_root_coords(GdkWindow* window, gint x, gint y, gint* rootX, gint* rootY);
+#endif // GTK_CHECK_VERSION(2, 17, 3)
+
+#if !GTK_CHECK_VERSION(2, 16, 0)
+const gchar* gtk_menu_item_get_label(GtkMenuItem*);
+#endif // GTK_CHECK_VERSION(2, 16, 0)
+
+
+#if !GTK_CHECK_VERSION(2, 14, 0)
+#define gtk_widget_get_window(widget) (widget)->window
+#define gtk_adjustment_get_value(adj) (adj)->value
+#define gtk_dialog_get_content_area(dialog) (dialog)->vbox
+#define gtk_dialog_get_action_area(dialog) (dialog)->action_area
+#define gtk_selection_data_get_length(data) (data)->length
+#define gtk_selection_data_get_data(data) (data)->data
+#define gtk_selection_data_get_target(data) (data)->target
+#define gtk_adjustment_set_page_size(adj, value) (adj)->page_size = value
+
+void gtk_adjustment_configure(GtkAdjustment* adjustment, gdouble value, gdouble lower, gdouble upper,
+ gdouble stepIncrement, gdouble pageIncrement, gdouble pageSize);
+
+void gtk_adjustment_set_value(GtkAdjustment* adjusment, gdouble value);
+#endif // GTK_CHECK_VERSION(2, 14, 0)
+
+GdkDevice* getDefaultGDKPointerDevice(GdkWindow* window);
+GdkCursor* blankCursor();
+
+#if !GLIB_CHECK_VERSION(2, 27, 1)
+gboolean g_signal_accumulator_first_wins(GSignalInvocationHint* invocationHint, GValue* returnAccumulator, const GValue* handlerReturn, gpointer data);
+#endif
+
+G_END_DECLS
+
+#endif // GtkVersioning_h
diff --git a/Source/WebCore/platform/gtk/KURLGtk.cpp b/Source/WebCore/platform/gtk/KURLGtk.cpp
new file mode 100644
index 0000000..47bc48b
--- /dev/null
+++ b/Source/WebCore/platform/gtk/KURLGtk.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * 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 "KURL.h"
+
+#include "FileSystem.h"
+#include <wtf/text/CString.h>
+
+#include <glib.h>
+
+namespace WebCore {
+
+String KURL::fileSystemPath() const
+{
+ gchar* filename = g_filename_from_uri(m_string.utf8().data(), 0, 0);
+ if (!filename)
+ return String();
+
+ String path = filenameToString(filename);
+ g_free(filename);
+ return path;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/gtk/KeyEventGtk.cpp b/Source/WebCore/platform/gtk/KeyEventGtk.cpp
new file mode 100644
index 0000000..50dfa4c
--- /dev/null
+++ b/Source/WebCore/platform/gtk/KeyEventGtk.cpp
@@ -0,0 +1,604 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PlatformKeyboardEvent.h"
+
+#include "GtkVersioning.h"
+#include "NotImplemented.h"
+#include "TextEncoding.h"
+#include "WindowsKeyboardCodes.h"
+
+#include <gdk/gdk.h>
+#include <gdk/gdkkeysyms.h>
+
+namespace WebCore {
+
+// FIXME: This is incomplete. We should change this to mirror
+// more like what Firefox does, and generate these switch statements
+// at build time.
+static String keyIdentifierForGdkKeyCode(guint keyCode)
+{
+ switch (keyCode) {
+ case GDK_Menu:
+ case GDK_Alt_L:
+ case GDK_Alt_R:
+ return "Alt";
+ case GDK_Clear:
+ return "Clear";
+ case GDK_Down:
+ return "Down";
+ // "End"
+ case GDK_End:
+ return "End";
+ // "Enter"
+ case GDK_ISO_Enter:
+ case GDK_KP_Enter:
+ case GDK_Return:
+ return "Enter";
+ case GDK_Execute:
+ return "Execute";
+ case GDK_F1:
+ return "F1";
+ case GDK_F2:
+ return "F2";
+ case GDK_F3:
+ return "F3";
+ case GDK_F4:
+ return "F4";
+ case GDK_F5:
+ return "F5";
+ case GDK_F6:
+ return "F6";
+ case GDK_F7:
+ return "F7";
+ case GDK_F8:
+ return "F8";
+ case GDK_F9:
+ return "F9";
+ case GDK_F10:
+ return "F10";
+ case GDK_F11:
+ return "F11";
+ case GDK_F12:
+ return "F12";
+ case GDK_F13:
+ return "F13";
+ case GDK_F14:
+ return "F14";
+ case GDK_F15:
+ return "F15";
+ case GDK_F16:
+ return "F16";
+ case GDK_F17:
+ return "F17";
+ case GDK_F18:
+ return "F18";
+ case GDK_F19:
+ return "F19";
+ case GDK_F20:
+ return "F20";
+ case GDK_F21:
+ return "F21";
+ case GDK_F22:
+ return "F22";
+ case GDK_F23:
+ return "F23";
+ case GDK_F24:
+ return "F24";
+ case GDK_Help:
+ return "Help";
+ case GDK_Home:
+ return "Home";
+ case GDK_Insert:
+ return "Insert";
+ case GDK_Left:
+ return "Left";
+ case GDK_Page_Down:
+ return "PageDown";
+ case GDK_Page_Up:
+ return "PageUp";
+ case GDK_Pause:
+ return "Pause";
+ case GDK_3270_PrintScreen:
+ case GDK_Print:
+ return "PrintScreen";
+ case GDK_Right:
+ return "Right";
+ case GDK_Select:
+ return "Select";
+ case GDK_Up:
+ return "Up";
+ // Standard says that DEL becomes U+007F.
+ case GDK_Delete:
+ return "U+007F";
+ case GDK_BackSpace:
+ return "U+0008";
+ case GDK_ISO_Left_Tab:
+ case GDK_3270_BackTab:
+ case GDK_Tab:
+ return "U+0009";
+ default:
+ return String::format("U+%04X", gdk_keyval_to_unicode(gdk_keyval_to_upper(keyCode)));
+ }
+}
+
+static int windowsKeyCodeForKeyEvent(unsigned int keycode)
+{
+ switch (keycode) {
+ case GDK_KP_0:
+ return VK_NUMPAD0;// (60) Numeric keypad 0 key
+ case GDK_KP_1:
+ return VK_NUMPAD1;// (61) Numeric keypad 1 key
+ case GDK_KP_2:
+ return VK_NUMPAD2; // (62) Numeric keypad 2 key
+ case GDK_KP_3:
+ return VK_NUMPAD3; // (63) Numeric keypad 3 key
+ case GDK_KP_4:
+ return VK_NUMPAD4; // (64) Numeric keypad 4 key
+ case GDK_KP_5:
+ return VK_NUMPAD5; //(65) Numeric keypad 5 key
+ case GDK_KP_6:
+ return VK_NUMPAD6; // (66) Numeric keypad 6 key
+ case GDK_KP_7:
+ return VK_NUMPAD7; // (67) Numeric keypad 7 key
+ case GDK_KP_8:
+ return VK_NUMPAD8; // (68) Numeric keypad 8 key
+ case GDK_KP_9:
+ return VK_NUMPAD9; // (69) Numeric keypad 9 key
+ case GDK_KP_Multiply:
+ return VK_MULTIPLY; // (6A) Multiply key
+ case GDK_KP_Add:
+ return VK_ADD; // (6B) Add key
+ case GDK_KP_Subtract:
+ return VK_SUBTRACT; // (6D) Subtract key
+ case GDK_KP_Decimal:
+ return VK_DECIMAL; // (6E) Decimal key
+ case GDK_KP_Divide:
+ return VK_DIVIDE; // (6F) Divide key
+
+ case GDK_KP_Page_Up:
+ return VK_PRIOR; // (21) PAGE UP key
+ case GDK_KP_Page_Down:
+ return VK_NEXT; // (22) PAGE DOWN key
+ case GDK_KP_End:
+ return VK_END; // (23) END key
+ case GDK_KP_Home:
+ return VK_HOME; // (24) HOME key
+ case GDK_KP_Left:
+ return VK_LEFT; // (25) LEFT ARROW key
+ case GDK_KP_Up:
+ return VK_UP; // (26) UP ARROW key
+ case GDK_KP_Right:
+ return VK_RIGHT; // (27) RIGHT ARROW key
+ case GDK_KP_Down:
+ return VK_DOWN; // (28) DOWN ARROW key
+
+ case GDK_BackSpace:
+ return VK_BACK; // (08) BACKSPACE key
+ case GDK_ISO_Left_Tab:
+ case GDK_3270_BackTab:
+ case GDK_Tab:
+ return VK_TAB; // (09) TAB key
+ case GDK_Clear:
+ return VK_CLEAR; // (0C) CLEAR key
+ case GDK_ISO_Enter:
+ case GDK_KP_Enter:
+ case GDK_Return:
+ return VK_RETURN; //(0D) Return key
+ case GDK_Shift_L:
+ case GDK_Shift_R:
+ return VK_SHIFT; // (10) SHIFT key
+ case GDK_Control_L:
+ case GDK_Control_R:
+ return VK_CONTROL; // (11) CTRL key
+ case GDK_Menu:
+ return VK_APPS; // (5D) Applications key (Natural keyboard)
+ case GDK_Alt_L:
+ case GDK_Alt_R:
+ return VK_MENU; // (12) ALT key
+
+ case GDK_Pause:
+ return VK_PAUSE; // (13) PAUSE key
+ case GDK_Caps_Lock:
+ return VK_CAPITAL; // (14) CAPS LOCK key
+ case GDK_Kana_Lock:
+ case GDK_Kana_Shift:
+ return VK_KANA; // (15) Input Method Editor (IME) Kana mode
+ case GDK_Hangul:
+ return VK_HANGUL; // VK_HANGUL (15) IME Hangul mode
+ // VK_JUNJA (17) IME Junja mode
+ // VK_FINAL (18) IME final mode
+ case GDK_Hangul_Hanja:
+ return VK_HANJA; // (19) IME Hanja mode
+ case GDK_Kanji:
+ return VK_KANJI; // (19) IME Kanji mode
+ case GDK_Escape:
+ return VK_ESCAPE; // (1B) ESC key
+ // VK_CONVERT (1C) IME convert
+ // VK_NONCONVERT (1D) IME nonconvert
+ // VK_ACCEPT (1E) IME accept
+ // VK_MODECHANGE (1F) IME mode change request
+ case GDK_space:
+ return VK_SPACE; // (20) SPACEBAR
+ case GDK_Page_Up:
+ return VK_PRIOR; // (21) PAGE UP key
+ case GDK_Page_Down:
+ return VK_NEXT; // (22) PAGE DOWN key
+ case GDK_End:
+ return VK_END; // (23) END key
+ case GDK_Home:
+ return VK_HOME; // (24) HOME key
+ case GDK_Left:
+ return VK_LEFT; // (25) LEFT ARROW key
+ case GDK_Up:
+ return VK_UP; // (26) UP ARROW key
+ case GDK_Right:
+ return VK_RIGHT; // (27) RIGHT ARROW key
+ case GDK_Down:
+ return VK_DOWN; // (28) DOWN ARROW key
+ case GDK_Select:
+ return VK_SELECT; // (29) SELECT key
+ case GDK_Print:
+ return VK_SNAPSHOT; // (2C) PRINT SCREEN key
+ case GDK_Execute:
+ return VK_EXECUTE;// (2B) EXECUTE key
+ case GDK_Insert:
+ case GDK_KP_Insert:
+ return VK_INSERT; // (2D) INS key
+ case GDK_Delete:
+ case GDK_KP_Delete:
+ return VK_DELETE; // (2E) DEL key
+ case GDK_Help:
+ return VK_HELP; // (2F) HELP key
+ case GDK_0:
+ case GDK_parenright:
+ return VK_0; // (30) 0) key
+ case GDK_1:
+ case GDK_exclam:
+ return VK_1; // (31) 1 ! key
+ case GDK_2:
+ case GDK_at:
+ return VK_2; // (32) 2 & key
+ case GDK_3:
+ case GDK_numbersign:
+ return VK_3; //case '3': case '#';
+ case GDK_4:
+ case GDK_dollar: // (34) 4 key '$';
+ return VK_4;
+ case GDK_5:
+ case GDK_percent:
+ return VK_5; // (35) 5 key '%'
+ case GDK_6:
+ case GDK_asciicircum:
+ return VK_6; // (36) 6 key '^'
+ case GDK_7:
+ case GDK_ampersand:
+ return VK_7; // (37) 7 key case '&'
+ case GDK_8:
+ case GDK_asterisk:
+ return VK_8; // (38) 8 key '*'
+ case GDK_9:
+ case GDK_parenleft:
+ return VK_9; // (39) 9 key '('
+ case GDK_a:
+ case GDK_A:
+ return VK_A; // (41) A key case 'a': case 'A': return 0x41;
+ case GDK_b:
+ case GDK_B:
+ return VK_B; // (42) B key case 'b': case 'B': return 0x42;
+ case GDK_c:
+ case GDK_C:
+ return VK_C; // (43) C key case 'c': case 'C': return 0x43;
+ case GDK_d:
+ case GDK_D:
+ return VK_D; // (44) D key case 'd': case 'D': return 0x44;
+ case GDK_e:
+ case GDK_E:
+ return VK_E; // (45) E key case 'e': case 'E': return 0x45;
+ case GDK_f:
+ case GDK_F:
+ return VK_F; // (46) F key case 'f': case 'F': return 0x46;
+ case GDK_g:
+ case GDK_G:
+ return VK_G; // (47) G key case 'g': case 'G': return 0x47;
+ case GDK_h:
+ case GDK_H:
+ return VK_H; // (48) H key case 'h': case 'H': return 0x48;
+ case GDK_i:
+ case GDK_I:
+ return VK_I; // (49) I key case 'i': case 'I': return 0x49;
+ case GDK_j:
+ case GDK_J:
+ return VK_J; // (4A) J key case 'j': case 'J': return 0x4A;
+ case GDK_k:
+ case GDK_K:
+ return VK_K; // (4B) K key case 'k': case 'K': return 0x4B;
+ case GDK_l:
+ case GDK_L:
+ return VK_L; // (4C) L key case 'l': case 'L': return 0x4C;
+ case GDK_m:
+ case GDK_M:
+ return VK_M; // (4D) M key case 'm': case 'M': return 0x4D;
+ case GDK_n:
+ case GDK_N:
+ return VK_N; // (4E) N key case 'n': case 'N': return 0x4E;
+ case GDK_o:
+ case GDK_O:
+ return VK_O; // (4F) O key case 'o': case 'O': return 0x4F;
+ case GDK_p:
+ case GDK_P:
+ return VK_P; // (50) P key case 'p': case 'P': return 0x50;
+ case GDK_q:
+ case GDK_Q:
+ return VK_Q; // (51) Q key case 'q': case 'Q': return 0x51;
+ case GDK_r:
+ case GDK_R:
+ return VK_R; // (52) R key case 'r': case 'R': return 0x52;
+ case GDK_s:
+ case GDK_S:
+ return VK_S; // (53) S key case 's': case 'S': return 0x53;
+ case GDK_t:
+ case GDK_T:
+ return VK_T; // (54) T key case 't': case 'T': return 0x54;
+ case GDK_u:
+ case GDK_U:
+ return VK_U; // (55) U key case 'u': case 'U': return 0x55;
+ case GDK_v:
+ case GDK_V:
+ return VK_V; // (56) V key case 'v': case 'V': return 0x56;
+ case GDK_w:
+ case GDK_W:
+ return VK_W; // (57) W key case 'w': case 'W': return 0x57;
+ case GDK_x:
+ case GDK_X:
+ return VK_X; // (58) X key case 'x': case 'X': return 0x58;
+ case GDK_y:
+ case GDK_Y:
+ return VK_Y; // (59) Y key case 'y': case 'Y': return 0x59;
+ case GDK_z:
+ case GDK_Z:
+ return VK_Z; // (5A) Z key case 'z': case 'Z': return 0x5A;
+ case GDK_Meta_L:
+ return VK_LWIN; // (5B) Left Windows key (Microsoft Natural keyboard)
+ case GDK_Meta_R:
+ return VK_RWIN; // (5C) Right Windows key (Natural keyboard)
+ // VK_SLEEP (5F) Computer Sleep key
+ // VK_SEPARATOR (6C) Separator key
+ // VK_SUBTRACT (6D) Subtract key
+ // VK_DECIMAL (6E) Decimal key
+ // VK_DIVIDE (6F) Divide key
+ // handled by key code above
+
+ case GDK_Num_Lock:
+ return VK_NUMLOCK; // (90) NUM LOCK key
+
+ case GDK_Scroll_Lock:
+ return VK_SCROLL; // (91) SCROLL LOCK key
+
+ // VK_LSHIFT (A0) Left SHIFT key
+ // VK_RSHIFT (A1) Right SHIFT key
+ // VK_LCONTROL (A2) Left CONTROL key
+ // VK_RCONTROL (A3) Right CONTROL key
+ // VK_LMENU (A4) Left MENU key
+ // VK_RMENU (A5) Right MENU key
+ // VK_BROWSER_BACK (A6) Windows 2000/XP: Browser Back key
+ // VK_BROWSER_FORWARD (A7) Windows 2000/XP: Browser Forward key
+ // VK_BROWSER_REFRESH (A8) Windows 2000/XP: Browser Refresh key
+ // VK_BROWSER_STOP (A9) Windows 2000/XP: Browser Stop key
+ // VK_BROWSER_SEARCH (AA) Windows 2000/XP: Browser Search key
+ // VK_BROWSER_FAVORITES (AB) Windows 2000/XP: Browser Favorites key
+ // VK_BROWSER_HOME (AC) Windows 2000/XP: Browser Start and Home key
+ // VK_VOLUME_MUTE (AD) Windows 2000/XP: Volume Mute key
+ // VK_VOLUME_DOWN (AE) Windows 2000/XP: Volume Down key
+ // VK_VOLUME_UP (AF) Windows 2000/XP: Volume Up key
+ // VK_MEDIA_NEXT_TRACK (B0) Windows 2000/XP: Next Track key
+ // VK_MEDIA_PREV_TRACK (B1) Windows 2000/XP: Previous Track key
+ // VK_MEDIA_STOP (B2) Windows 2000/XP: Stop Media key
+ // VK_MEDIA_PLAY_PAUSE (B3) Windows 2000/XP: Play/Pause Media key
+ // VK_LAUNCH_MAIL (B4) Windows 2000/XP: Start Mail key
+ // VK_LAUNCH_MEDIA_SELECT (B5) Windows 2000/XP: Select Media key
+ // VK_LAUNCH_APP1 (B6) Windows 2000/XP: Start Application 1 key
+ // VK_LAUNCH_APP2 (B7) Windows 2000/XP: Start Application 2 key
+
+ // VK_OEM_1 (BA) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ';:' key
+ case GDK_semicolon:
+ case GDK_colon:
+ return VK_OEM_1; //case ';': case ':': return 0xBA;
+ // VK_OEM_PLUS (BB) Windows 2000/XP: For any country/region, the '+' key
+ case GDK_plus:
+ case GDK_equal:
+ return VK_OEM_PLUS; //case '=': case '+': return 0xBB;
+ // VK_OEM_COMMA (BC) Windows 2000/XP: For any country/region, the ',' key
+ case GDK_comma:
+ case GDK_less:
+ return VK_OEM_COMMA; //case ',': case '<': return 0xBC;
+ // VK_OEM_MINUS (BD) Windows 2000/XP: For any country/region, the '-' key
+ case GDK_minus:
+ case GDK_underscore:
+ return VK_OEM_MINUS; //case '-': case '_': return 0xBD;
+ // VK_OEM_PERIOD (BE) Windows 2000/XP: For any country/region, the '.' key
+ case GDK_period:
+ case GDK_greater:
+ return VK_OEM_PERIOD; //case '.': case '>': return 0xBE;
+ // VK_OEM_2 (BF) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '/?' key
+ case GDK_slash:
+ case GDK_question:
+ return VK_OEM_2; //case '/': case '?': return 0xBF;
+ // VK_OEM_3 (C0) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '`~' key
+ case GDK_asciitilde:
+ case GDK_quoteleft:
+ return VK_OEM_3; //case '`': case '~': return 0xC0;
+ // VK_OEM_4 (DB) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '[{' key
+ case GDK_bracketleft:
+ case GDK_braceleft:
+ return VK_OEM_4; //case '[': case '{': return 0xDB;
+ // VK_OEM_5 (DC) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '\|' key
+ case GDK_backslash:
+ case GDK_bar:
+ return VK_OEM_5; //case '\\': case '|': return 0xDC;
+ // VK_OEM_6 (DD) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ']}' key
+ case GDK_bracketright:
+ case GDK_braceright:
+ return VK_OEM_6; // case ']': case '}': return 0xDD;
+ // VK_OEM_7 (DE) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key
+ case GDK_quoteright:
+ case GDK_quotedbl:
+ return VK_OEM_7; // case '\'': case '"': return 0xDE;
+ // VK_OEM_8 (DF) Used for miscellaneous characters; it can vary by keyboard.
+ // VK_OEM_102 (E2) Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard
+ // VK_PROCESSKEY (E5) Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCESS key
+ // VK_PACKET (E7) Windows 2000/XP: Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT,SendInput, WM_KEYDOWN, and WM_KEYUP
+ // VK_ATTN (F6) Attn key
+ // VK_CRSEL (F7) CrSel key
+ // VK_EXSEL (F8) ExSel key
+ // VK_EREOF (F9) Erase EOF key
+ // VK_PLAY (FA) Play key
+ // VK_ZOOM (FB) Zoom key
+ // VK_NONAME (FC) Reserved for future use
+ // VK_PA1 (FD) PA1 key
+ // VK_OEM_CLEAR (FE) Clear key
+ case GDK_F1:
+ case GDK_F2:
+ case GDK_F3:
+ case GDK_F4:
+ case GDK_F5:
+ case GDK_F6:
+ case GDK_F7:
+ case GDK_F8:
+ case GDK_F9:
+ case GDK_F10:
+ case GDK_F11:
+ case GDK_F12:
+ case GDK_F13:
+ case GDK_F14:
+ case GDK_F15:
+ case GDK_F16:
+ case GDK_F17:
+ case GDK_F18:
+ case GDK_F19:
+ case GDK_F20:
+ case GDK_F21:
+ case GDK_F22:
+ case GDK_F23:
+ case GDK_F24:
+ return VK_F1 + (keycode - GDK_F1);
+
+ default:
+ return 0;
+ }
+
+}
+
+static String singleCharacterString(guint val)
+{
+ switch (val) {
+ case GDK_ISO_Enter:
+ case GDK_KP_Enter:
+ case GDK_Return:
+ return String("\r");
+ case GDK_BackSpace:
+ return String("\x8");
+ case GDK_Tab:
+ return String("\t");
+ default:
+ gunichar c = gdk_keyval_to_unicode(val);
+ glong nwc;
+ gunichar2* uchar16 = g_ucs4_to_utf16(&c, 1, 0, &nwc, 0);
+
+ String retVal;
+ if (uchar16)
+ retVal = String((UChar*)uchar16, nwc);
+ else
+ retVal = String();
+
+ g_free(uchar16);
+
+ return retVal;
+ }
+}
+
+// Keep this in sync with the other platform event constructors
+// TODO: m_gdkEventKey should be refcounted
+PlatformKeyboardEvent::PlatformKeyboardEvent(GdkEventKey* event)
+ : m_type((event->type == GDK_KEY_RELEASE) ? KeyUp : KeyDown)
+ , m_text(singleCharacterString(event->keyval))
+ , m_unmodifiedText(singleCharacterString(event->keyval))
+ , m_keyIdentifier(keyIdentifierForGdkKeyCode(event->keyval))
+ , m_autoRepeat(false)
+ , m_windowsVirtualKeyCode(windowsKeyCodeForKeyEvent(event->keyval))
+ , m_nativeVirtualKeyCode(event->keyval)
+ , m_isKeypad(event->keyval >= GDK_KP_Space && event->keyval <= GDK_KP_9)
+ , m_shiftKey((event->state & GDK_SHIFT_MASK) || (event->keyval == GDK_3270_BackTab))
+ , m_ctrlKey(event->state & GDK_CONTROL_MASK)
+ , m_altKey(event->state & GDK_MOD1_MASK)
+ , m_metaKey(event->state & GDK_META_MASK)
+ , m_gdkEventKey(event)
+{
+}
+
+void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool backwardCompatibilityMode)
+{
+ // Can only change type from KeyDown to RawKeyDown or Char, as we lack information for other conversions.
+ ASSERT(m_type == KeyDown);
+ m_type = type;
+
+ if (backwardCompatibilityMode)
+ return;
+
+ if (type == RawKeyDown) {
+ m_text = String();
+ m_unmodifiedText = String();
+ } else {
+ m_keyIdentifier = String();
+ m_windowsVirtualKeyCode = 0;
+ }
+}
+
+bool PlatformKeyboardEvent::currentCapsLockState()
+{
+ notImplemented();
+ return false;
+}
+
+void PlatformKeyboardEvent::getCurrentModifierState(bool& shiftKey, bool& ctrlKey, bool& altKey, bool& metaKey)
+{
+ notImplemented();
+ shiftKey = false;
+ ctrlKey = false;
+ altKey = false;
+ metaKey = false;
+}
+
+GdkEventKey* PlatformKeyboardEvent::gdkEventKey() const
+{
+ return m_gdkEventKey;
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/LanguageGtk.cpp b/Source/WebCore/platform/gtk/LanguageGtk.cpp
new file mode 100644
index 0000000..7d7a66d
--- /dev/null
+++ b/Source/WebCore/platform/gtk/LanguageGtk.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "Language.h"
+
+#include "GOwnPtr.h"
+#include "PlatformString.h"
+#include <wtf/text/CString.h>
+
+#include <glib.h>
+#include <locale.h>
+
+namespace WebCore {
+
+// Using pango_language_get_default() here is not an option, because
+// it doesn't support changing the locale in runtime, so it returns
+// always the same value.
+String platformDefaultLanguage()
+{
+ char* localeDefault = setlocale(LC_CTYPE, NULL);
+
+ if (!localeDefault)
+ return String("c");
+
+ GOwnPtr<gchar> normalizedDefault(g_ascii_strdown(localeDefault, -1));
+ char* ptr = strchr(normalizedDefault.get(), '_');
+
+ if (ptr)
+ *ptr = '-';
+
+ ptr = strchr(normalizedDefault.get(), '.');
+
+ if (ptr)
+ *ptr = '\0';
+
+ return String(normalizedDefault.get());
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/LocalizedStringsGtk.cpp b/Source/WebCore/platform/gtk/LocalizedStringsGtk.cpp
new file mode 100644
index 0000000..65e8852
--- /dev/null
+++ b/Source/WebCore/platform/gtk/LocalizedStringsGtk.cpp
@@ -0,0 +1,635 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * Copyright (C) 2008 Christian Dywan <christian@imendio.com>
+ * Copyright (C) 2008 Nuanti Ltd.
+ * Copyright (C) 2010 Igalia S.L
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "LocalizedStrings.h"
+#include "GOwnPtr.h"
+#include "IntSize.h"
+#include "NotImplemented.h"
+#include "PlatformString.h"
+#include <wtf/text/CString.h>
+
+#include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+#include <math.h>
+
+namespace WebCore {
+
+static const char* gtkStockLabel(const char* stockID)
+{
+ GtkStockItem item;
+ if (!gtk_stock_lookup(stockID, &item))
+ return stockID;
+ return item.label;
+}
+
+String submitButtonDefaultLabel()
+{
+ return String::fromUTF8(_("Submit"));
+}
+
+String inputElementAltText()
+{
+ return String::fromUTF8(_("Submit"));
+}
+
+String resetButtonDefaultLabel()
+{
+ return String::fromUTF8(_("Reset"));
+}
+
+String searchableIndexIntroduction()
+{
+ return String::fromUTF8(_("This is a searchable index. Enter search keywords: "));
+}
+
+String fileButtonChooseFileLabel()
+{
+ return String::fromUTF8(_("Choose File"));
+}
+
+String fileButtonNoFileSelectedLabel()
+{
+ return String::fromUTF8(_("(None)"));
+}
+
+String contextMenuItemTagOpenLinkInNewWindow()
+{
+ return String::fromUTF8(_("Open Link in New _Window"));
+}
+
+String contextMenuItemTagDownloadLinkToDisk()
+{
+ return String::fromUTF8(_("_Download Linked File"));
+}
+
+String contextMenuItemTagCopyLinkToClipboard()
+{
+ return String::fromUTF8(_("Copy Link Loc_ation"));
+}
+
+String contextMenuItemTagOpenImageInNewWindow()
+{
+ return String::fromUTF8(_("Open _Image in New Window"));
+}
+
+String contextMenuItemTagDownloadImageToDisk()
+{
+ return String::fromUTF8(_("Sa_ve Image As"));
+}
+
+String contextMenuItemTagCopyImageToClipboard()
+{
+ return String::fromUTF8(_("Cop_y Image"));
+}
+
+String contextMenuItemTagOpenVideoInNewWindow()
+{
+ return String::fromUTF8(_("Open _Video in New Window"));
+}
+
+String contextMenuItemTagOpenAudioInNewWindow()
+{
+ return String::fromUTF8(_("Open _Audio in New Window"));
+}
+
+String contextMenuItemTagCopyVideoLinkToClipboard()
+{
+ return String::fromUTF8(_("Cop_y Video Link Location"));
+}
+
+String contextMenuItemTagCopyAudioLinkToClipboard()
+{
+ return String::fromUTF8(_("Cop_y Audio Link Location"));
+}
+
+String contextMenuItemTagToggleMediaControls()
+{
+ return String::fromUTF8(_("_Toggle Media Controls"));
+}
+
+String contextMenuItemTagToggleMediaLoop()
+{
+ return String::fromUTF8(_("Toggle Media _Loop Playback"));
+}
+
+String contextMenuItemTagEnterVideoFullscreen()
+{
+ return String::fromUTF8(_("Switch Video to _Fullscreen"));
+}
+
+String contextMenuItemTagMediaPlay()
+{
+ return String::fromUTF8(_("_Play"));
+}
+
+String contextMenuItemTagMediaPause()
+{
+ return String::fromUTF8(_("_Pause"));
+}
+
+String contextMenuItemTagMediaMute()
+{
+ return String::fromUTF8(_("_Mute"));
+}
+
+String contextMenuItemTagOpenFrameInNewWindow()
+{
+ return String::fromUTF8(_("Open _Frame in New Window"));
+}
+
+String contextMenuItemTagCopy()
+{
+ static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_COPY));
+ return stockLabel;
+}
+
+String contextMenuItemTagDelete()
+{
+ static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_DELETE));
+ return stockLabel;
+}
+
+String contextMenuItemTagSelectAll()
+{
+ static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_SELECT_ALL));
+ return stockLabel;
+}
+
+String contextMenuItemTagUnicode()
+{
+ return String::fromUTF8(_("_Insert Unicode Control Character"));
+}
+
+String contextMenuItemTagInputMethods()
+{
+ return String::fromUTF8(_("Input _Methods"));
+}
+
+String contextMenuItemTagGoBack()
+{
+ static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_GO_BACK));
+ return stockLabel;
+}
+
+String contextMenuItemTagGoForward()
+{
+ static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_GO_FORWARD));
+ return stockLabel;
+}
+
+String contextMenuItemTagStop()
+{
+ static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_STOP));
+ return stockLabel;
+}
+
+String contextMenuItemTagReload()
+{
+ return String::fromUTF8(_("_Reload"));
+}
+
+String contextMenuItemTagCut()
+{
+ static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_CUT));
+ return stockLabel;
+}
+
+String contextMenuItemTagPaste()
+{
+ static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_PASTE));
+ return stockLabel;
+}
+
+String contextMenuItemTagNoGuessesFound()
+{
+ return String::fromUTF8(_("No Guesses Found"));
+}
+
+String contextMenuItemTagIgnoreSpelling()
+{
+ return String::fromUTF8(_("_Ignore Spelling"));
+}
+
+String contextMenuItemTagLearnSpelling()
+{
+ return String::fromUTF8(_("_Learn Spelling"));
+}
+
+String contextMenuItemTagSearchWeb()
+{
+ return String::fromUTF8(_("_Search the Web"));
+}
+
+String contextMenuItemTagLookUpInDictionary()
+{
+ return String::fromUTF8(_("_Look Up in Dictionary"));
+}
+
+String contextMenuItemTagOpenLink()
+{
+ return String::fromUTF8(_("_Open Link"));
+}
+
+String contextMenuItemTagIgnoreGrammar()
+{
+ return String::fromUTF8(_("Ignore _Grammar"));
+}
+
+String contextMenuItemTagSpellingMenu()
+{
+ return String::fromUTF8(_("Spelling and _Grammar"));
+}
+
+String contextMenuItemTagShowSpellingPanel(bool show)
+{
+ return String::fromUTF8(show ? _("_Show Spelling and Grammar") : _("_Hide Spelling and Grammar"));
+}
+
+String contextMenuItemTagCheckSpelling()
+{
+ return String::fromUTF8(_("_Check Document Now"));
+}
+
+String contextMenuItemTagCheckSpellingWhileTyping()
+{
+ return String::fromUTF8(_("Check Spelling While _Typing"));
+}
+
+String contextMenuItemTagCheckGrammarWithSpelling()
+{
+ return String::fromUTF8(_("Check _Grammar With Spelling"));
+}
+
+String contextMenuItemTagFontMenu()
+{
+ return String::fromUTF8(_("_Font"));
+}
+
+String contextMenuItemTagBold()
+{
+ static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_BOLD));
+ return stockLabel;
+}
+
+String contextMenuItemTagItalic()
+{
+ static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_ITALIC));
+ return stockLabel;
+}
+
+String contextMenuItemTagUnderline()
+{
+ static String stockLabel = String::fromUTF8(gtkStockLabel(GTK_STOCK_UNDERLINE));
+ return stockLabel;
+}
+
+String contextMenuItemTagOutline()
+{
+ return String::fromUTF8(_("_Outline"));
+}
+
+String contextMenuItemTagInspectElement()
+{
+ return String::fromUTF8(_("Inspect _Element"));
+}
+
+String searchMenuNoRecentSearchesText()
+{
+ return String::fromUTF8(_("No recent searches"));
+}
+
+String searchMenuRecentSearchesText()
+{
+ return String::fromUTF8(_("Recent searches"));
+}
+
+String searchMenuClearRecentSearchesText()
+{
+ return String::fromUTF8(_("_Clear recent searches"));
+}
+
+String AXDefinitionListTermText()
+{
+ return String::fromUTF8(_("term"));
+}
+
+String AXDefinitionListDefinitionText()
+{
+ return String::fromUTF8(_("definition"));
+}
+
+String AXButtonActionVerb()
+{
+ return String::fromUTF8(_("press"));
+}
+
+String AXRadioButtonActionVerb()
+{
+ return String::fromUTF8(_("select"));
+}
+
+String AXTextFieldActionVerb()
+{
+ return String::fromUTF8(_("activate"));
+}
+
+String AXCheckedCheckBoxActionVerb()
+{
+ return String::fromUTF8(_("uncheck"));
+}
+
+String AXUncheckedCheckBoxActionVerb()
+{
+ return String::fromUTF8(_("check"));
+}
+
+String AXLinkActionVerb()
+{
+ return String::fromUTF8(_("jump"));
+}
+
+String AXMenuListPopupActionVerb()
+{
+ return String();
+}
+
+String AXMenuListActionVerb()
+{
+ return String();
+}
+
+String missingPluginText()
+{
+ return String::fromUTF8(_("Missing Plug-in"));
+}
+
+String crashedPluginText()
+{
+ notImplemented();
+ return String::fromUTF8(_("Plug-in Failure"));
+}
+
+String multipleFileUploadText(unsigned numberOfFiles)
+{
+ // FIXME: If this file gets localized, this should really be localized as one string with a wildcard for the number.
+ return String::number(numberOfFiles) + String::fromUTF8(_(" files"));
+}
+
+String unknownFileSizeText()
+{
+ return String::fromUTF8(_("Unknown"));
+}
+
+String imageTitle(const String& filename, const IntSize& size)
+{
+ GOwnPtr<gchar> string(g_strdup_printf(C_("Title string for images", "%s (%dx%d pixels)"),
+ filename.utf8().data(),
+ size.width(), size.height()));
+
+ return String::fromUTF8(string.get());
+}
+
+
+#if ENABLE(VIDEO)
+
+String mediaElementLoadingStateText()
+{
+ return String::fromUTF8(_("Loading..."));
+}
+
+String mediaElementLiveBroadcastStateText()
+{
+ return String::fromUTF8(_("Live Broadcast"));
+}
+
+String localizedMediaControlElementString(const String& name)
+{
+ if (name == "AudioElement")
+ return String::fromUTF8(_("audio element controller"));
+ if (name == "VideoElement")
+ return String::fromUTF8(_("video element controller"));
+ if (name == "MuteButton")
+ return String::fromUTF8(_("mute"));
+ if (name == "UnMuteButton")
+ return String::fromUTF8(_("unmute"));
+ if (name == "PlayButton")
+ return String::fromUTF8(_("play"));
+ if (name == "PauseButton")
+ return String::fromUTF8(_("pause"));
+ if (name == "Slider")
+ return String::fromUTF8(_("movie time"));
+ if (name == "SliderThumb")
+ return String::fromUTF8(_("timeline slider thumb"));
+ if (name == "RewindButton")
+ return String::fromUTF8(_("back 30 seconds"));
+ if (name == "ReturnToRealtimeButton")
+ return String::fromUTF8(_("return to realtime"));
+ if (name == "CurrentTimeDisplay")
+ return String::fromUTF8(_("elapsed time"));
+ if (name == "TimeRemainingDisplay")
+ return String::fromUTF8(_("remaining time"));
+ if (name == "StatusDisplay")
+ return String::fromUTF8(_("status"));
+ if (name == "FullscreenButton")
+ return String::fromUTF8(_("fullscreen"));
+ if (name == "SeekForwardButton")
+ return String::fromUTF8(_("fast forward"));
+ if (name == "SeekBackButton")
+ return String::fromUTF8(_("fast reverse"));
+ if (name == "ShowClosedCaptionsButton")
+ return String::fromUTF8(_("show closed captions"));
+ if (name == "HideClosedCaptionsButton")
+ return String::fromUTF8(_("hide closed captions"));
+
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String localizedMediaControlElementHelpText(const String& name)
+{
+ if (name == "AudioElement")
+ return String::fromUTF8(_("audio element playback controls and status display"));
+ if (name == "VideoElement")
+ return String::fromUTF8(_("video element playback controls and status display"));
+ if (name == "MuteButton")
+ return String::fromUTF8(_("mute audio tracks"));
+ if (name == "UnMuteButton")
+ return String::fromUTF8(_("unmute audio tracks"));
+ if (name == "PlayButton")
+ return String::fromUTF8(_("begin playback"));
+ if (name == "PauseButton")
+ return String::fromUTF8(_("pause playback"));
+ if (name == "Slider")
+ return String::fromUTF8(_("movie time scrubber"));
+ if (name == "SliderThumb")
+ return String::fromUTF8(_("movie time scrubber thumb"));
+ if (name == "RewindButton")
+ return String::fromUTF8(_("seek movie back 30 seconds"));
+ if (name == "ReturnToRealtimeButton")
+ return String::fromUTF8(_("return streaming movie to real time"));
+ if (name == "CurrentTimeDisplay")
+ return String::fromUTF8(_("current movie time in seconds"));
+ if (name == "TimeRemainingDisplay")
+ return String::fromUTF8(_("number of seconds of movie remaining"));
+ if (name == "StatusDisplay")
+ return String::fromUTF8(_("current movie status"));
+ if (name == "SeekBackButton")
+ return String::fromUTF8(_("seek quickly back"));
+ if (name == "SeekForwardButton")
+ return String::fromUTF8(_("seek quickly forward"));
+ if (name == "FullscreenButton")
+ return String::fromUTF8(_("Play movie in fullscreen mode"));
+ if (name == "ShowClosedCaptionsButton")
+ return String::fromUTF8(_("start displaying closed captions"));
+ if (name == "HideClosedCaptionsButton")
+ return String::fromUTF8(_("stop displaying closed captions"));
+
+ ASSERT_NOT_REACHED();
+ return String();
+}
+
+String localizedMediaTimeDescription(float time)
+{
+ if (!isfinite(time))
+ return String::fromUTF8(_("indefinite time"));
+
+ int seconds = (int)fabsf(time);
+ int days = seconds / (60 * 60 * 24);
+ int hours = seconds / (60 * 60);
+ int minutes = (seconds / 60) % 60;
+ seconds %= 60;
+
+ if (days) {
+ GOwnPtr<gchar> string(g_strdup_printf("%d days %d hours %d minutes %d seconds", days, hours, minutes, seconds));
+ return String::fromUTF8(string.get());
+ }
+
+ if (hours) {
+ GOwnPtr<gchar> string(g_strdup_printf("%d hours %d minutes %d seconds", hours, minutes, seconds));
+ return String::fromUTF8(string.get());
+ }
+
+ if (minutes) {
+ GOwnPtr<gchar> string(g_strdup_printf("%d minutes %d seconds", minutes, seconds));
+ return String::fromUTF8(string.get());
+ }
+
+ GOwnPtr<gchar> string(g_strdup_printf("%d seconds", seconds));
+ return String::fromUTF8(string.get());
+}
+#endif // ENABLE(VIDEO)
+
+String validationMessageValueMissingText()
+{
+ return String::fromUTF8(_("value missing"));
+}
+
+String validationMessageValueMissingForCheckboxText()
+{
+ notImplemented();
+ return validationMessageValueMissingText();
+}
+
+String validationMessageValueMissingForFileText()
+{
+ notImplemented();
+ return validationMessageValueMissingText();
+}
+
+String validationMessageValueMissingForMultipleFileText()
+{
+ notImplemented();
+ return validationMessageValueMissingText();
+}
+
+String validationMessageValueMissingForRadioText()
+{
+ notImplemented();
+ return validationMessageValueMissingText();
+}
+
+String validationMessageValueMissingForSelectText()
+{
+ notImplemented();
+ return validationMessageValueMissingText();
+}
+
+String validationMessageTypeMismatchText()
+{
+ notImplemented();
+ return String::fromUTF8(_("type mismatch"));
+}
+
+String validationMessageTypeMismatchForEmailText()
+{
+ notImplemented();
+ return validationMessageTypeMismatchText();
+}
+
+String validationMessageTypeMismatchForMultipleEmailText()
+{
+ notImplemented();
+ return validationMessageTypeMismatchText();
+}
+
+String validationMessageTypeMismatchForURLText()
+{
+ notImplemented();
+ return validationMessageTypeMismatchText();
+}
+
+String validationMessagePatternMismatchText()
+{
+ return String::fromUTF8(_("pattern mismatch"));
+}
+
+String validationMessageTooLongText(int, int)
+{
+ return String::fromUTF8(_("too long"));
+}
+
+String validationMessageRangeUnderflowText(const String&)
+{
+ return String::fromUTF8(_("range underflow"));
+}
+
+String validationMessageRangeOverflowText(const String&)
+{
+ return String::fromUTF8(_("range overflow"));
+}
+
+String validationMessageStepMismatchText(const String&, const String&)
+{
+ return String::fromUTF8(_("step mismatch"));
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/LoggingGtk.cpp b/Source/WebCore/platform/gtk/LoggingGtk.cpp
new file mode 100644
index 0000000..6350036
--- /dev/null
+++ b/Source/WebCore/platform/gtk/LoggingGtk.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2009 Gustavo Noronha Silva <gns@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "Logging.h"
+#include "PlatformString.h"
+
+#include <glib.h>
+#include <string.h>
+
+namespace WebCore {
+
+// Inspired by the code used by the Qt port
+
+void InitializeLoggingChannelsIfNecessary()
+{
+ static bool didInitializeLoggingChannels = false;
+ if (didInitializeLoggingChannels)
+ return;
+
+ didInitializeLoggingChannels = true;
+
+ char* logEnv = getenv("WEBKIT_DEBUG");
+ if (!logEnv)
+ return;
+
+ // we set up the logs anyway because some of our logging, such as
+ // soup's is available in release builds
+#if defined(NDEBUG)
+ g_warning("WEBKIT_DEBUG is not empty, but this is a release build. Notice that many log messages will only appear in a debug build.");
+#endif
+
+ char** logv = g_strsplit(logEnv, " ", -1);
+
+ for (int i = 0; logv[i]; i++) {
+ if (WTFLogChannel* channel = getChannelFromName(logv[i]))
+ channel->state = WTFLogChannelOn;
+ }
+
+ g_strfreev(logv);
+
+ // to disable logging notImplemented set the DISABLE_NI_WARNING
+ // environment variable to 1
+ LogNotYetImplemented.state = WTFLogChannelOn;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/gtk/MIMETypeRegistryGtk.cpp b/Source/WebCore/platform/gtk/MIMETypeRegistryGtk.cpp
new file mode 100644
index 0000000..8fc3020
--- /dev/null
+++ b/Source/WebCore/platform/gtk/MIMETypeRegistryGtk.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MIMETypeRegistry.h"
+
+namespace WebCore {
+
+struct ExtensionMap {
+ const char* extension;
+ const char* mimeType;
+};
+
+static const ExtensionMap extensionMap [] = {
+ { "bmp", "image/bmp" },
+ { "css", "text/css" },
+ { "gif", "image/gif" },
+ { "htm", "text/html" },
+ { "html", "text/html" },
+ { "ico", "image/x-icon" },
+ { "jpeg", "image/jpeg" },
+ { "jpg", "image/jpeg" },
+ { "js", "application/x-javascript" },
+ { "pdf", "application/pdf" },
+ { "png", "image/png" },
+ { "rss", "application/rss+xml" },
+ { "svg", "image/svg+xml" },
+ { "text", "text/plain" },
+ { "txt", "text/plain" },
+ { "xbm", "image/x-xbitmap" },
+ { "xml", "text/xml" },
+ { "xsl", "text/xsl" },
+ { "xhtml", "application/xhtml+xml" },
+ { "wml", "text/vnd.wap.wml" },
+ { "wmlc", "application/vnd.wap.wmlc" },
+ { 0, 0 }
+};
+
+String MIMETypeRegistry::getMIMETypeForExtension(const String &ext)
+{
+ String s = ext.lower();
+ const ExtensionMap *e = extensionMap;
+ while (e->extension) {
+ if (s == e->extension)
+ return e->mimeType;
+ ++e;
+ }
+
+ return String();
+}
+
+bool MIMETypeRegistry::isApplicationPluginMIMEType(const String&)
+{
+ return false;
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/MainFrameScrollbarGtk.cpp b/Source/WebCore/platform/gtk/MainFrameScrollbarGtk.cpp
new file mode 100644
index 0000000..c2e24e0
--- /dev/null
+++ b/Source/WebCore/platform/gtk/MainFrameScrollbarGtk.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2007, 2009 Holger Hans Peter Freyther zecke@selfish.org
+ * Copyright (C) 2010 Gustavo Noronha Silva <gns@gnome.org>
+ * Copyright (C) 2010 Collabora Ltd.
+ * Copyright (C) 2010 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 "MainFrameScrollbarGtk.h"
+
+#include "GraphicsContext.h"
+#include "GtkVersioning.h"
+#include "IntRect.h"
+#include <gtk/gtk.h>
+
+using namespace WebCore;
+
+PassRefPtr<MainFrameScrollbarGtk> MainFrameScrollbarGtk::create(ScrollbarClient* client, ScrollbarOrientation orientation, GtkAdjustment* adj)
+{
+ return adoptRef(new MainFrameScrollbarGtk(client, orientation, adj));
+}
+
+// Main frame scrollbars are slaves to a GtkAdjustment. If a main frame
+// scrollbar has an m_adjustment, it belongs to the container (a GtkWidget such
+// as GtkScrolledWindow). The adjustment may also be null, in which case there
+// is no containing view or the parent ScrollView is in some sort of transition
+// state. These scrollbars are never painted, as the container takes care of
+// that. They exist only to shuttle data from the GtkWidget container into
+// WebCore and vice-versa.
+MainFrameScrollbarGtk::MainFrameScrollbarGtk(ScrollbarClient* client, ScrollbarOrientation orientation, GtkAdjustment* adjustment)
+ : Scrollbar(client, orientation, RegularScrollbar)
+ , m_adjustment(0)
+{
+ attachAdjustment(adjustment);
+
+ // We have nothing to show as we are solely operating on the GtkAdjustment.
+ resize(0, 0);
+}
+
+MainFrameScrollbarGtk::~MainFrameScrollbarGtk()
+{
+ if (m_adjustment)
+ detachAdjustment();
+}
+
+void MainFrameScrollbarGtk::attachAdjustment(GtkAdjustment* adjustment)
+{
+ if (m_adjustment)
+ detachAdjustment();
+
+ m_adjustment = adjustment;
+ if (!m_adjustment)
+ return;
+
+ g_signal_connect(m_adjustment.get(), "value-changed", G_CALLBACK(MainFrameScrollbarGtk::gtkValueChanged), this);
+ updateThumbProportion();
+ updateThumbPosition();
+}
+
+void MainFrameScrollbarGtk::detachAdjustment()
+{
+ if (!m_adjustment)
+ return;
+
+ g_signal_handlers_disconnect_by_func(G_OBJECT(m_adjustment.get()), (gpointer)MainFrameScrollbarGtk::gtkValueChanged, this);
+
+ // For the case where we only operate on the GtkAdjustment it is best to
+ // reset the values so that the surrounding scrollbar gets updated, or
+ // e.g. for a GtkScrolledWindow the scrollbar gets hidden.
+ gtk_adjustment_configure(m_adjustment.get(), 0, 0, 0, 0, 0, 0);
+
+ m_adjustment = 0;
+}
+
+void MainFrameScrollbarGtk::updateThumbPosition()
+{
+ if (!m_adjustment || gtk_adjustment_get_value(m_adjustment.get()) == m_currentPos)
+ return;
+ gtk_adjustment_set_value(m_adjustment.get(), m_currentPos);
+}
+
+void MainFrameScrollbarGtk::updateThumbProportion()
+{
+ if (!m_adjustment)
+ return;
+ gtk_adjustment_configure(m_adjustment.get(),
+ gtk_adjustment_get_value(m_adjustment.get()),
+ gtk_adjustment_get_lower(m_adjustment.get()),
+ m_totalSize,
+ m_lineStep,
+ m_pageStep,
+ m_visibleSize);
+}
+
+void MainFrameScrollbarGtk::gtkValueChanged(GtkAdjustment*, MainFrameScrollbarGtk* that)
+{
+ that->setValue(static_cast<int>(gtk_adjustment_get_value(that->m_adjustment.get())), NotFromScrollAnimator);
+}
+
+void MainFrameScrollbarGtk::paint(GraphicsContext* context, const IntRect& rect)
+{
+ // Main frame scrollbars are not painted by WebCore.
+ return;
+}
diff --git a/Source/WebCore/platform/gtk/MainFrameScrollbarGtk.h b/Source/WebCore/platform/gtk/MainFrameScrollbarGtk.h
new file mode 100644
index 0000000..f184425
--- /dev/null
+++ b/Source/WebCore/platform/gtk/MainFrameScrollbarGtk.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010 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 MainFrameScrollbarGtk_h
+#define MainFrameScrollbarGtk_h
+
+#include "GRefPtrGtk.h"
+#include "Scrollbar.h"
+#include <wtf/PassRefPtr.h>
+
+typedef struct _GtkAdjustment GtkAdjustment;
+
+namespace WebCore {
+
+class MainFrameScrollbarGtk : public Scrollbar {
+public:
+ ~MainFrameScrollbarGtk();
+ virtual void paint(GraphicsContext*, const IntRect&);
+ void detachAdjustment();
+ void attachAdjustment(GtkAdjustment*);
+ static PassRefPtr<MainFrameScrollbarGtk> create(ScrollbarClient*, ScrollbarOrientation, GtkAdjustment*);
+
+protected:
+ virtual void updateThumbPosition();
+ virtual void updateThumbProportion();
+
+private:
+ MainFrameScrollbarGtk(ScrollbarClient*, ScrollbarOrientation, GtkAdjustment*);
+ static void gtkValueChanged(GtkAdjustment*, MainFrameScrollbarGtk*);
+
+ GRefPtr<GtkAdjustment> m_adjustment;
+};
+
+}
+
+#endif // ScrollbarGtk_h
diff --git a/Source/WebCore/platform/gtk/MouseEventGtk.cpp b/Source/WebCore/platform/gtk/MouseEventGtk.cpp
new file mode 100644
index 0000000..69f938f
--- /dev/null
+++ b/Source/WebCore/platform/gtk/MouseEventGtk.cpp
@@ -0,0 +1,105 @@
+/*
+* Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "config.h"
+#include "PlatformMouseEvent.h"
+
+#include "Assertions.h"
+
+#include <gdk/gdk.h>
+
+namespace WebCore {
+
+// FIXME: Would be even better to figure out which modifier is Alt instead of always using GDK_MOD1_MASK.
+
+// Keep this in sync with the other platform event constructors
+PlatformMouseEvent::PlatformMouseEvent(GdkEventButton* event)
+{
+ m_timestamp = event->time;
+ m_position = IntPoint((int)event->x, (int)event->y);
+ m_globalPosition = IntPoint((int)event->x_root, (int)event->y_root);
+ m_shiftKey = event->state & GDK_SHIFT_MASK;
+ m_ctrlKey = event->state & GDK_CONTROL_MASK;
+ m_altKey = event->state & GDK_MOD1_MASK;
+ m_metaKey = event->state & GDK_META_MASK;
+
+ switch (event->type) {
+ case GDK_BUTTON_PRESS:
+ case GDK_2BUTTON_PRESS:
+ case GDK_3BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ m_eventType = MouseEventPressed;
+ if (event->type == GDK_BUTTON_RELEASE) {
+ m_eventType = MouseEventReleased;
+ m_clickCount = 0;
+ } else if (event->type == GDK_BUTTON_PRESS)
+ m_clickCount = 1;
+ else if (event->type == GDK_2BUTTON_PRESS)
+ m_clickCount = 2;
+ else if (event->type == GDK_3BUTTON_PRESS)
+ m_clickCount = 3;
+
+ if (event->button == 1)
+ m_button = LeftButton;
+ else if (event->button == 2)
+ m_button = MiddleButton;
+ else if (event->button == 3)
+ m_button = RightButton;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ };
+}
+
+PlatformMouseEvent::PlatformMouseEvent(GdkEventMotion* motion)
+{
+ m_timestamp = motion->time;
+ m_position = IntPoint((int)motion->x, (int)motion->y);
+ m_globalPosition = IntPoint((int)motion->x_root, (int)motion->y_root);
+ m_shiftKey = motion->state & GDK_SHIFT_MASK;
+ m_ctrlKey = motion->state & GDK_CONTROL_MASK;
+ m_altKey = motion->state & GDK_MOD1_MASK;
+ m_metaKey = motion->state & GDK_MOD2_MASK;
+
+ switch (motion->type) {
+ case GDK_MOTION_NOTIFY:
+ m_eventType = MouseEventMoved;
+ m_button = NoButton;
+ m_clickCount = 0;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ };
+
+ if (motion->state & GDK_BUTTON1_MASK)
+ m_button = LeftButton;
+ else if (motion->state & GDK_BUTTON2_MASK)
+ m_button = MiddleButton;
+ else if (motion->state & GDK_BUTTON3_MASK)
+ m_button = RightButton;
+}
+}
diff --git a/Source/WebCore/platform/gtk/PasteboardGtk.cpp b/Source/WebCore/platform/gtk/PasteboardGtk.cpp
new file mode 100644
index 0000000..4cd5dc0
--- /dev/null
+++ b/Source/WebCore/platform/gtk/PasteboardGtk.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * 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 "Pasteboard.h"
+
+#include "DataObjectGtk.h"
+#include "DocumentFragment.h"
+#include "Frame.h"
+#include "NotImplemented.h"
+#include "PlatformString.h"
+#include "TextResourceDecoder.h"
+#include "Image.h"
+#include "RenderImage.h"
+#include "KURL.h"
+#include "markup.h"
+#include <wtf/gobject/GRefPtr.h>
+#include <wtf/text/CString.h>
+
+#include <gtk/gtk.h>
+
+namespace WebCore {
+
+Pasteboard* Pasteboard::generalPasteboard()
+{
+ static Pasteboard* pasteboard = new Pasteboard();
+ return pasteboard;
+}
+
+Pasteboard::Pasteboard()
+{
+ notImplemented();
+}
+
+Pasteboard::~Pasteboard()
+{
+ delete m_helper;
+}
+
+PasteboardHelper* Pasteboard::helper()
+{
+ return m_helper;
+}
+
+void Pasteboard::setHelper(PasteboardHelper* helper)
+{
+ m_helper = helper;
+}
+
+void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame)
+{
+ GtkClipboard* clipboard = m_helper->getClipboard(frame);
+ DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
+ dataObject->setText(frame->editor()->selectedText());
+ dataObject->setMarkup(createMarkup(selectedRange, 0, AnnotateForInterchange, false, AbsoluteURLs));
+ m_helper->writeClipboardContents(clipboard);
+}
+
+void Pasteboard::writePlainText(const String& text)
+{
+ GtkClipboard* clipboard = gtk_clipboard_get_for_display(gdk_display_get_default(), GDK_SELECTION_CLIPBOARD);
+ DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
+ dataObject->setText(text);
+ m_helper->writeClipboardContents(clipboard);
+}
+
+void Pasteboard::writeURL(const KURL& url, const String& label, Frame* frame)
+{
+ if (url.isEmpty())
+ return;
+
+ GtkClipboard* clipboard = m_helper->getClipboard(frame);
+ DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
+ dataObject->setURL(url, label);
+ m_helper->writeClipboardContents(clipboard);
+}
+
+void Pasteboard::writeImage(Node* node, const KURL&, const String&)
+{
+ GtkClipboard* clipboard = gtk_clipboard_get_for_display(gdk_display_get_default(), GDK_SELECTION_CLIPBOARD);
+
+ ASSERT(node && node->renderer() && node->renderer()->isImage());
+ RenderImage* renderer = toRenderImage(node->renderer());
+ CachedImage* cachedImage = renderer->cachedImage();
+ if (!cachedImage || cachedImage->errorOccurred())
+ return;
+ Image* image = cachedImage->image();
+ ASSERT(image);
+
+ GRefPtr<GdkPixbuf> pixbuf = adoptGRef(image->getGdkPixbuf());
+ DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
+ dataObject->setImage(pixbuf.get());
+ m_helper->writeClipboardContents(clipboard);
+}
+
+void Pasteboard::clear()
+{
+ gtk_clipboard_clear(gtk_clipboard_get_for_display(gdk_display_get_default(), GDK_SELECTION_CLIPBOARD));
+}
+
+bool Pasteboard::canSmartReplace()
+{
+ notImplemented();
+ return false;
+}
+
+PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefPtr<Range> context,
+ bool allowPlainText, bool& chosePlainText)
+{
+ GtkClipboard* clipboard = m_helper->getCurrentClipboard(frame);
+ DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
+ m_helper->getClipboardContents(clipboard);
+
+ chosePlainText = false;
+
+ if (dataObject->hasMarkup()) {
+ RefPtr<DocumentFragment> fragment = createFragmentFromMarkup(frame->document(), dataObject->markup(), "", FragmentScriptingNotAllowed);
+ if (fragment)
+ return fragment.release();
+ }
+
+ if (!allowPlainText)
+ return 0;
+
+ if (dataObject->hasText()) {
+ chosePlainText = true;
+ RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), dataObject->text());
+ if (fragment)
+ return fragment.release();
+ }
+
+ return 0;
+}
+
+String Pasteboard::plainText(Frame* frame)
+{
+ GtkClipboard* clipboard = m_helper->getCurrentClipboard(frame);
+ DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
+
+ m_helper->getClipboardContents(clipboard);
+ return dataObject->text();
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/PasteboardHelper.cpp b/Source/WebCore/platform/gtk/PasteboardHelper.cpp
new file mode 100644
index 0000000..013789f
--- /dev/null
+++ b/Source/WebCore/platform/gtk/PasteboardHelper.cpp
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2010 Martin Robinson <mrobinson@webkit.org>
+ * Copyright (C) Igalia S.L.
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+#include "config.h"
+#include "PasteboardHelper.h"
+
+#include "Chrome.h"
+#include "DataObjectGtk.h"
+#include "Frame.h"
+#include "GtkVersioning.h"
+#include "Page.h"
+#include "Pasteboard.h"
+#include "TextResourceDecoder.h"
+#include <gtk/gtk.h>
+#include <wtf/gobject/GOwnPtr.h>
+
+namespace WebCore {
+
+static GdkAtom textPlainAtom;
+static GdkAtom markupAtom;
+static GdkAtom netscapeURLAtom;
+static GdkAtom uriListAtom;
+static String gMarkupPrefix;
+
+static void removeMarkupPrefix(String& markup)
+{
+
+ // The markup prefix is not harmful, but we remove it from the string anyway, so that
+ // we can have consistent results with other ports during the layout tests.
+ if (markup.startsWith(gMarkupPrefix))
+ markup.remove(0, gMarkupPrefix.length());
+}
+
+static void initGdkAtoms()
+{
+ static gboolean initialized = FALSE;
+
+ if (initialized)
+ return;
+
+ initialized = TRUE;
+
+ textPlainAtom = gdk_atom_intern("text/plain;charset=utf-8", FALSE);
+ markupAtom = gdk_atom_intern("text/html", FALSE);
+ netscapeURLAtom = gdk_atom_intern("_NETSCAPE_URL", FALSE);
+ uriListAtom = gdk_atom_intern("text/uri-list", FALSE);
+ gMarkupPrefix = "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">";
+}
+
+PasteboardHelper::PasteboardHelper()
+ : m_targetList(gtk_target_list_new(0, 0))
+{
+ initGdkAtoms();
+}
+
+PasteboardHelper::~PasteboardHelper()
+{
+ gtk_target_list_unref(m_targetList);
+}
+
+void PasteboardHelper::initializeTargetList()
+{
+ gtk_target_list_add_text_targets(m_targetList, getIdForTargetType(TargetTypeText));
+ gtk_target_list_add(m_targetList, markupAtom, 0, getIdForTargetType(TargetTypeMarkup));
+ gtk_target_list_add_uri_targets(m_targetList, getIdForTargetType(TargetTypeURIList));
+ gtk_target_list_add(m_targetList, netscapeURLAtom, 0, getIdForTargetType(TargetTypeNetscapeURL));
+ gtk_target_list_add_image_targets(m_targetList, getIdForTargetType(TargetTypeImage), TRUE);
+}
+
+static inline GtkWidget* widgetFromFrame(Frame* frame)
+{
+ ASSERT(frame);
+ Page* page = frame->page();
+ ASSERT(page);
+ Chrome* chrome = page->chrome();
+ ASSERT(chrome);
+ PlatformPageClient client = chrome->platformPageClient();
+ ASSERT(client);
+ return client;
+}
+
+GtkClipboard* PasteboardHelper::getCurrentClipboard(Frame* frame)
+{
+ if (usePrimarySelectionClipboard(widgetFromFrame(frame)))
+ return getPrimarySelectionClipboard(frame);
+ return getClipboard(frame);
+}
+
+GtkClipboard* PasteboardHelper::getClipboard(Frame* frame) const
+{
+ return gtk_widget_get_clipboard(widgetFromFrame(frame), GDK_SELECTION_CLIPBOARD);
+}
+
+GtkClipboard* PasteboardHelper::getPrimarySelectionClipboard(Frame* frame) const
+{
+ return gtk_widget_get_clipboard(widgetFromFrame(frame), GDK_SELECTION_PRIMARY);
+}
+
+GtkTargetList* PasteboardHelper::targetList() const
+{
+ return m_targetList;
+}
+
+static String selectionDataToUTF8String(GtkSelectionData* data)
+{
+ // g_strndup guards against selection data that is not null-terminated.
+ GOwnPtr<gchar> markupString(g_strndup(reinterpret_cast<const char*>(gtk_selection_data_get_data(data)), gtk_selection_data_get_length(data)));
+ return String::fromUTF8(markupString.get());
+}
+
+void PasteboardHelper::getClipboardContents(GtkClipboard* clipboard)
+{
+ DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
+ ASSERT(dataObject);
+
+ if (gtk_clipboard_wait_is_text_available(clipboard)) {
+ GOwnPtr<gchar> textData(gtk_clipboard_wait_for_text(clipboard));
+ if (textData)
+ dataObject->setText(String::fromUTF8(textData.get()));
+ }
+
+ if (gtk_clipboard_wait_is_target_available(clipboard, markupAtom)) {
+ if (GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard, markupAtom)) {
+ String markup(selectionDataToUTF8String(data));
+ removeMarkupPrefix(markup);
+ dataObject->setMarkup(markup);
+ gtk_selection_data_free(data);
+ }
+ }
+
+ if (gtk_clipboard_wait_is_target_available(clipboard, uriListAtom)) {
+ if (GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard, uriListAtom)) {
+ dataObject->setURIList(selectionDataToUTF8String(data));
+ gtk_selection_data_free(data);
+ }
+ }
+}
+
+void PasteboardHelper::fillSelectionData(GtkSelectionData* selectionData, guint info, DataObjectGtk* dataObject)
+{
+ if (info == getIdForTargetType(TargetTypeText))
+ gtk_selection_data_set_text(selectionData, dataObject->text().utf8().data(), -1);
+
+ else if (info == getIdForTargetType(TargetTypeMarkup)) {
+ // Some Linux applications refuse to accept pasted markup unless it is
+ // prefixed by a content-type meta tag.
+ CString markup = (gMarkupPrefix + dataObject->markup()).utf8();
+ gtk_selection_data_set(selectionData, markupAtom, 8,
+ reinterpret_cast<const guchar*>(markup.data()), markup.length() + 1);
+
+ } else if (info == getIdForTargetType(TargetTypeURIList)) {
+ CString uriList = dataObject->uriList().utf8();
+ gtk_selection_data_set(selectionData, uriListAtom, 8,
+ reinterpret_cast<const guchar*>(uriList.data()), uriList.length() + 1);
+
+ } else if (info == getIdForTargetType(TargetTypeNetscapeURL) && dataObject->hasURL()) {
+ String url(dataObject->url());
+ String result(url);
+ result.append("\n");
+
+ if (dataObject->hasText())
+ result.append(dataObject->text());
+ else
+ result.append(url);
+
+ GOwnPtr<gchar> resultData(g_strdup(result.utf8().data()));
+ gtk_selection_data_set(selectionData, netscapeURLAtom, 8,
+ reinterpret_cast<const guchar*>(resultData.get()), strlen(resultData.get()) + 1);
+
+ } else if (info == getIdForTargetType(TargetTypeImage))
+ gtk_selection_data_set_pixbuf(selectionData, dataObject->image());
+}
+
+GtkTargetList* PasteboardHelper::targetListForDataObject(DataObjectGtk* dataObject)
+{
+ GtkTargetList* list = gtk_target_list_new(0, 0);
+
+ if (dataObject->hasText())
+ gtk_target_list_add_text_targets(list, getIdForTargetType(TargetTypeText));
+
+ if (dataObject->hasMarkup())
+ gtk_target_list_add(list, markupAtom, 0, getIdForTargetType(TargetTypeMarkup));
+
+ if (dataObject->hasURIList()) {
+ gtk_target_list_add_uri_targets(list, getIdForTargetType(TargetTypeURIList));
+ gtk_target_list_add(list, netscapeURLAtom, 0, getIdForTargetType(TargetTypeNetscapeURL));
+ }
+
+ if (dataObject->hasImage())
+ gtk_target_list_add_image_targets(list, getIdForTargetType(TargetTypeImage), TRUE);
+
+ return list;
+}
+
+void PasteboardHelper::fillDataObjectFromDropData(GtkSelectionData* data, guint info, DataObjectGtk* dataObject)
+{
+ if (!gtk_selection_data_get_data(data))
+ return;
+
+ GdkAtom target = gtk_selection_data_get_target(data);
+ if (target == textPlainAtom)
+ dataObject->setText(selectionDataToUTF8String(data));
+ else if (target == markupAtom) {
+ String markup(selectionDataToUTF8String(data));
+ removeMarkupPrefix(markup);
+ dataObject->setMarkup(markup);
+ } else if (target == uriListAtom) {
+ dataObject->setURIList(selectionDataToUTF8String(data));
+ } else if (target == netscapeURLAtom) {
+ String urlWithLabel(selectionDataToUTF8String(data));
+ Vector<String> pieces;
+ urlWithLabel.split("\n", pieces);
+
+ // Give preference to text/uri-list here, as it can hold more
+ // than one URI but still take the label if there is one.
+ if (!dataObject->hasURIList())
+ dataObject->setURIList(pieces[0]);
+ if (pieces.size() > 1)
+ dataObject->setText(pieces[1]);
+ }
+}
+
+Vector<GdkAtom> PasteboardHelper::dropAtomsForContext(GtkWidget* widget, GdkDragContext* context)
+{
+ // Always search for these common atoms.
+ Vector<GdkAtom> dropAtoms;
+ dropAtoms.append(textPlainAtom);
+ dropAtoms.append(markupAtom);
+ dropAtoms.append(uriListAtom);
+ dropAtoms.append(netscapeURLAtom);
+
+ // For images, try to find the most applicable image type.
+ GRefPtr<GtkTargetList> list(gtk_target_list_new(0, 0));
+ gtk_target_list_add_image_targets(list.get(), getIdForTargetType(TargetTypeImage), TRUE);
+ GdkAtom atom = gtk_drag_dest_find_target(widget, context, list.get());
+ if (atom != GDK_NONE)
+ dropAtoms.append(atom);
+
+ return dropAtoms;
+}
+
+static DataObjectGtk* settingClipboardDataObject = 0;
+
+static void getClipboardContentsCallback(GtkClipboard* clipboard, GtkSelectionData *selectionData, guint info, gpointer data)
+{
+ DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
+ ASSERT(dataObject);
+ Pasteboard::generalPasteboard()->helper()->fillSelectionData(selectionData, info, dataObject);
+}
+
+static void clearClipboardContentsCallback(GtkClipboard* clipboard, gpointer data)
+{
+ DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
+ ASSERT(dataObject);
+
+ // Only clear the DataObject for this clipboard if we are not currently setting it.
+ if (dataObject != settingClipboardDataObject)
+ dataObject->clear();
+
+ if (!data)
+ return;
+
+ GClosure* callback = static_cast<GClosure*>(data);
+ GValue firstArgument = {0, {{0}}};
+ g_value_init(&firstArgument, G_TYPE_POINTER);
+ g_value_set_pointer(&firstArgument, clipboard);
+ g_closure_invoke(callback, 0, 1, &firstArgument, 0);
+ g_closure_unref(callback);
+}
+
+void PasteboardHelper::writeClipboardContents(GtkClipboard* clipboard, GClosure* callback)
+{
+ DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
+ GtkTargetList* list = targetListForDataObject(dataObject);
+
+ int numberOfTargets;
+ GtkTargetEntry* table = gtk_target_table_new_from_list(list, &numberOfTargets);
+
+ if (numberOfTargets > 0 && table) {
+ settingClipboardDataObject = dataObject;
+
+ gtk_clipboard_set_with_data(clipboard, table, numberOfTargets,
+ getClipboardContentsCallback, clearClipboardContentsCallback, callback);
+ gtk_clipboard_set_can_store(clipboard, 0, 0);
+
+ settingClipboardDataObject = 0;
+
+ } else
+ gtk_clipboard_clear(clipboard);
+
+ if (table)
+ gtk_target_table_free(table, numberOfTargets);
+ gtk_target_list_unref(list);
+}
+
+}
+
diff --git a/Source/WebCore/platform/gtk/PasteboardHelper.h b/Source/WebCore/platform/gtk/PasteboardHelper.h
new file mode 100644
index 0000000..bb1b580
--- /dev/null
+++ b/Source/WebCore/platform/gtk/PasteboardHelper.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 Luca Bruno <lethalman88@gmail.com>
+ * Copyright (C) 2009 Holger Hans Peter Freyther
+ * Copyright (C) 2010 Martin Robinson <mrobinson@webkit.org>
+ * Copyright (C) 2010 Igalia S.L.
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PasteboardHelper_h
+#define PasteboardHelper_h
+
+/*
+ * FIXME: this is for WebCore support and must be removed once
+ * a better solution is found
+ */
+
+#include "Frame.h"
+
+namespace WebCore {
+
+class DataObjectGtk;
+
+class PasteboardHelper {
+public:
+ PasteboardHelper();
+ virtual ~PasteboardHelper();
+
+ GtkClipboard* getCurrentClipboard(Frame*);
+ GtkClipboard* getClipboard(Frame*) const;
+ GtkClipboard* getPrimarySelectionClipboard(Frame*) const;
+ GtkTargetList* targetList() const;
+ GtkTargetList* targetListForDataObject(DataObjectGtk*);
+ void fillSelectionData(GtkSelectionData*, guint, DataObjectGtk*);
+ void fillDataObjectFromDropData(GtkSelectionData*, guint, DataObjectGtk*);
+ Vector<GdkAtom> dropAtomsForContext(GtkWidget*, GdkDragContext*);
+ void writeClipboardContents(GtkClipboard*, GClosure* closure = 0);
+ void getClipboardContents(GtkClipboard*);
+
+ enum PasteboardTargetType { TargetTypeText, TargetTypeMarkup, TargetTypeURIList, TargetTypeNetscapeURL, TargetTypeImage, TargetTypeUnknown };
+ virtual guint getIdForTargetType(PasteboardTargetType) = 0;
+
+protected:
+ void initializeTargetList();
+ virtual bool usePrimarySelectionClipboard(GtkWidget*) = 0;
+
+private:
+ GtkTargetList* m_targetList;
+};
+
+}
+
+#endif // PasteboardHelper_h
diff --git a/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp b/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp
new file mode 100644
index 0000000..40b509e
--- /dev/null
+++ b/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2008 Christian Dywan <christian@imendio.com>
+ * Copyright (C) 2008 Collabora Ltd.
+ * Copyright (C) 2009 Holger Hans Peter Freyther
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PlatformScreen.h"
+
+#include "GtkVersioning.h"
+#include "HostWindow.h"
+#include "ScrollView.h"
+#include "Widget.h"
+
+#include <gtk/gtk.h>
+
+#if PLATFORM(X11)
+#include <gdk/gdkx.h>
+#include <X11/Xatom.h>
+#endif
+
+namespace WebCore {
+
+static GdkVisual* getVisual(Widget* widget)
+{
+ if (!widget)
+ return 0;
+
+ GtkWidget* container = GTK_WIDGET(widget->root()->hostWindow()->platformPageClient());
+
+ if (!container)
+ return 0;
+
+ if (!gtk_widget_get_realized(container)) {
+ GtkWidget* toplevel = gtk_widget_get_toplevel(container);
+ if (gtk_widget_is_toplevel(toplevel))
+ container = toplevel;
+ else
+ return 0;
+ }
+
+ return gdk_window_get_visual(gtk_widget_get_window(container));
+}
+
+int screenDepth(Widget* widget)
+{
+ GdkVisual* visual = getVisual(widget);
+ if (!visual)
+ return 24;
+ return gdk_visual_get_depth(visual);
+}
+
+int screenDepthPerComponent(Widget* widget)
+{
+ GdkVisual* visual = getVisual(widget);
+ if (!visual)
+ return 8;
+
+ return gdk_visual_get_bits_per_rgb(visual);
+}
+
+bool screenIsMonochrome(Widget* widget)
+{
+ return screenDepth(widget) < 2;
+}
+
+FloatRect screenRect(Widget* widget)
+{
+ if (!widget)
+ return FloatRect();
+
+ GtkWidget* container = gtk_widget_get_toplevel(GTK_WIDGET(widget->root()->hostWindow()->platformPageClient()));
+ if (!gtk_widget_is_toplevel(container))
+ return FloatRect();
+
+ GdkScreen* screen = gtk_widget_has_screen(container) ? gtk_widget_get_screen(container) : gdk_screen_get_default();
+ if (!screen)
+ return FloatRect();
+
+ gint monitor = gdk_screen_get_monitor_at_window(screen, gtk_widget_get_window(GTK_WIDGET(container)));
+ GdkRectangle geometry;
+ gdk_screen_get_monitor_geometry(screen, monitor, &geometry);
+
+ return FloatRect(geometry.x, geometry.y, geometry.width, geometry.height);
+}
+
+FloatRect screenAvailableRect(Widget* widget)
+{
+ if (!widget)
+ return FloatRect();
+
+#if PLATFORM(X11)
+ GtkWidget* container = GTK_WIDGET(widget->root()->hostWindow()->platformPageClient());
+ if (!container)
+ return FloatRect();
+
+ if (!gtk_widget_get_realized(container))
+ return screenRect(widget);
+
+ GdkWindow* rootWindow = gtk_widget_get_root_window(container);
+ GdkDisplay* display = gdk_window_get_display(rootWindow);
+ Atom xproperty = gdk_x11_get_xatom_by_name_for_display(display, "_NET_WORKAREA");
+
+ Atom retType;
+ int retFormat;
+ long *workAreaPos = NULL;
+ unsigned long retNItems;
+ unsigned long retAfter;
+ int xRes = XGetWindowProperty(GDK_DISPLAY_XDISPLAY(display), GDK_WINDOW_XWINDOW(rootWindow), xproperty,
+ 0, 4, FALSE, XA_CARDINAL, &retType, &retFormat, &retNItems, &retAfter, (guchar**)&workAreaPos);
+
+ FloatRect rect;
+ if (xRes == Success && workAreaPos != NULL && retType == XA_CARDINAL && retNItems == 4 && retFormat == 32) {
+ rect = FloatRect(workAreaPos[0], workAreaPos[1], workAreaPos[2], workAreaPos[3]);
+ // rect contains the available space in the whole screen not just in the monitor
+ // containing the widget, so we intersect it with the monitor rectangle.
+ rect.intersect(screenRect(widget));
+ } else
+ rect = screenRect(widget);
+
+ if (workAreaPos)
+ XFree(workAreaPos);
+
+ return rect;
+#else
+ return screenRect(widget);
+#endif
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/gtk/PopupMenuGtk.cpp b/Source/WebCore/platform/gtk/PopupMenuGtk.cpp
new file mode 100644
index 0000000..b2466c5
--- /dev/null
+++ b/Source/WebCore/platform/gtk/PopupMenuGtk.cpp
@@ -0,0 +1,270 @@
+/*
+ * This file is part of the popup menu implementation for <select> elements in WebCore.
+ *
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2008 Collabora Ltd.
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "PopupMenuGtk.h"
+
+#include "FrameView.h"
+#include "GOwnPtr.h"
+#include "GtkVersioning.h"
+#include "HostWindow.h"
+#include "PlatformString.h"
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+static const uint32_t gSearchTimeoutMs = 1000;
+
+PopupMenuGtk::PopupMenuGtk(PopupMenuClient* client)
+ : m_popupClient(client)
+ , m_previousKeyEventCharacter(0)
+ , m_currentlySelectedMenuItem(0)
+{
+}
+
+PopupMenuGtk::~PopupMenuGtk()
+{
+ if (m_popup) {
+ g_signal_handlers_disconnect_matched(m_popup.get(), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
+ hide();
+ }
+}
+
+void PopupMenuGtk::show(const IntRect& rect, FrameView* view, int index)
+{
+ ASSERT(client());
+
+ if (!m_popup) {
+ m_popup = GTK_MENU(gtk_menu_new());
+ g_signal_connect(m_popup.get(), "unmap", G_CALLBACK(PopupMenuGtk::menuUnmapped), this);
+ g_signal_connect(m_popup.get(), "key-press-event", G_CALLBACK(PopupMenuGtk::keyPressEventCallback), this);
+ } else
+ gtk_container_foreach(GTK_CONTAINER(m_popup.get()), reinterpret_cast<GtkCallback>(menuRemoveItem), this);
+
+ int x = 0;
+ int y = 0;
+ GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(view->hostWindow()->platformPageClient()));
+ if (window)
+ gdk_window_get_origin(window, &x, &y);
+ m_menuPosition = view->contentsToWindow(rect.location());
+ m_menuPosition = IntPoint(m_menuPosition.x() + x, m_menuPosition.y() + y + rect.height());
+ m_indexMap.clear();
+
+ const int size = client()->listSize();
+ for (int i = 0; i < size; ++i) {
+ GtkWidget* item;
+ if (client()->itemIsSeparator(i))
+ item = gtk_separator_menu_item_new();
+ else
+ item = gtk_menu_item_new_with_label(client()->itemText(i).utf8().data());
+
+ m_indexMap.add(item, i);
+ g_signal_connect(item, "activate", G_CALLBACK(PopupMenuGtk::menuItemActivated), this);
+ g_signal_connect(item, "select", G_CALLBACK(PopupMenuGtk::selectItemCallback), this);
+
+ // FIXME: Apply the PopupMenuStyle from client()->itemStyle(i)
+ gtk_widget_set_sensitive(item, client()->itemIsEnabled(i));
+ gtk_menu_shell_append(GTK_MENU_SHELL(m_popup.get()), item);
+ gtk_widget_show(item);
+ }
+
+ gtk_menu_set_active(m_popup.get(), index);
+
+
+ // The size calls are directly copied from gtkcombobox.c which is LGPL
+ GtkRequisition requisition;
+ gtk_widget_set_size_request(GTK_WIDGET(m_popup.get()), -1, -1);
+#ifdef GTK_API_VERSION_2
+ gtk_widget_size_request(GTK_WIDGET(m_popup.get()), &requisition);
+#else
+ gtk_widget_get_preferred_size(GTK_WIDGET(m_popup.get()), &requisition, 0);
+#endif
+
+ gtk_widget_set_size_request(GTK_WIDGET(m_popup.get()), std::max(rect.width(), requisition.width), -1);
+
+ GList* children = gtk_container_get_children(GTK_CONTAINER(m_popup.get()));
+ GList* p = children;
+ if (size) {
+ for (int i = 0; i < size; i++) {
+ if (i > index)
+ break;
+
+ GtkWidget* item = reinterpret_cast<GtkWidget*>(p->data);
+ GtkRequisition itemRequisition;
+#ifdef GTK_API_VERSION_2
+ gtk_widget_get_child_requisition(item, &itemRequisition);
+#else
+ gtk_widget_get_preferred_size(item, &itemRequisition, 0);
+#endif
+ m_menuPosition.setY(m_menuPosition.y() - itemRequisition.height);
+
+ p = g_list_next(p);
+ }
+ } else {
+ // Center vertically the empty popup in the combo box area
+ m_menuPosition.setY(m_menuPosition.y() - rect.height() / 2);
+ }
+
+ g_list_free(children);
+ gtk_menu_popup(m_popup.get(), 0, 0, reinterpret_cast<GtkMenuPositionFunc>(menuPositionFunction), this, 0, gtk_get_current_event_time());
+}
+
+void PopupMenuGtk::hide()
+{
+ ASSERT(m_popup);
+ gtk_menu_popdown(m_popup.get());
+}
+
+void PopupMenuGtk::updateFromElement()
+{
+ client()->setTextFromItem(client()->selectedIndex());
+}
+
+void PopupMenuGtk::disconnectClient()
+{
+ m_popupClient = 0;
+}
+
+bool PopupMenuGtk::typeAheadFind(GdkEventKey* event)
+{
+ // If we were given a non-printable character just skip it.
+ gunichar unicodeCharacter = gdk_keyval_to_unicode(event->keyval);
+ if (!unicodeCharacter) {
+ resetTypeAheadFindState();
+ return false;
+ }
+
+ glong charactersWritten;
+ GOwnPtr<gunichar2> utf16String(g_ucs4_to_utf16(&unicodeCharacter, 1, 0, &charactersWritten, 0));
+ if (!utf16String) {
+ resetTypeAheadFindState();
+ return false;
+ }
+
+ // If the character is the same as the last character, the user is probably trying to
+ // cycle through the menulist entries. This matches the WebCore behavior for collapsed
+ // menulists.
+ bool repeatingCharacter = unicodeCharacter != m_previousKeyEventCharacter;
+ if (event->time - m_previousKeyEventTimestamp > gSearchTimeoutMs)
+ m_currentSearchString = String(static_cast<UChar*>(utf16String.get()), charactersWritten);
+ else if (repeatingCharacter)
+ m_currentSearchString.append(String(static_cast<UChar*>(utf16String.get()), charactersWritten));
+
+ m_previousKeyEventTimestamp = event->time;
+ m_previousKeyEventCharacter = unicodeCharacter;
+
+ // Like the Chromium port, we case fold before searching, because
+ // strncmp does not handle non-ASCII characters.
+ GOwnPtr<gchar> searchStringWithCaseFolded(g_utf8_casefold(m_currentSearchString.utf8().data(), -1));
+ size_t prefixLength = strlen(searchStringWithCaseFolded.get());
+
+ GList* children = gtk_container_get_children(GTK_CONTAINER(m_popup.get()));
+ if (!children)
+ return true;
+
+ // If a menu item has already been selected, start searching from the current
+ // item down the list. This will make multiple key presses of the same character
+ // advance the selection.
+ GList* currentChild = children;
+ if (m_currentlySelectedMenuItem) {
+ currentChild = g_list_find(children, m_currentlySelectedMenuItem);
+ if (!currentChild) {
+ m_currentlySelectedMenuItem = 0;
+ currentChild = children;
+ }
+
+ // Repeating characters should iterate.
+ if (repeatingCharacter) {
+ if (GList* nextChild = g_list_next(currentChild))
+ currentChild = nextChild;
+ }
+ }
+
+ GList* firstChild = currentChild;
+ do {
+ currentChild = g_list_next(currentChild);
+ if (!currentChild)
+ currentChild = children;
+
+ GOwnPtr<gchar> itemText(g_utf8_casefold(gtk_menu_item_get_label(GTK_MENU_ITEM(currentChild->data)), -1));
+ if (!strncmp(searchStringWithCaseFolded.get(), itemText.get(), prefixLength)) {
+ gtk_menu_shell_select_item(GTK_MENU_SHELL(m_popup.get()), GTK_WIDGET(currentChild->data));
+ return true;
+ }
+ } while (currentChild != firstChild);
+
+ return true;
+}
+
+void PopupMenuGtk::menuItemActivated(GtkMenuItem* item, PopupMenuGtk* that)
+{
+ ASSERT(that->client());
+ ASSERT(that->m_indexMap.contains(GTK_WIDGET(item)));
+ that->client()->valueChanged(that->m_indexMap.get(GTK_WIDGET(item)));
+}
+
+void PopupMenuGtk::menuUnmapped(GtkWidget*, PopupMenuGtk* that)
+{
+ ASSERT(that->client());
+ that->resetTypeAheadFindState();
+ that->client()->popupDidHide();
+}
+
+void PopupMenuGtk::menuPositionFunction(GtkMenu*, gint* x, gint* y, gboolean* pushIn, PopupMenuGtk* that)
+{
+ *x = that->m_menuPosition.x();
+ *y = that->m_menuPosition.y();
+ *pushIn = true;
+}
+
+void PopupMenuGtk::resetTypeAheadFindState()
+{
+ m_currentlySelectedMenuItem = 0;
+ m_previousKeyEventCharacter = 0;
+ m_currentSearchString = "";
+}
+
+void PopupMenuGtk::menuRemoveItem(GtkWidget* widget, PopupMenuGtk* that)
+{
+ ASSERT(that->m_popup);
+ gtk_container_remove(GTK_CONTAINER(that->m_popup.get()), widget);
+}
+
+int PopupMenuGtk::selectItemCallback(GtkMenuItem* item, PopupMenuGtk* that)
+{
+ that->m_currentlySelectedMenuItem = GTK_WIDGET(item);
+ return FALSE;
+}
+
+int PopupMenuGtk::keyPressEventCallback(GtkWidget* widget, GdkEventKey* event, PopupMenuGtk* that)
+{
+ return that->typeAheadFind(event);
+}
+
+}
+
diff --git a/Source/WebCore/platform/gtk/PopupMenuGtk.h b/Source/WebCore/platform/gtk/PopupMenuGtk.h
new file mode 100644
index 0000000..7f2fc36
--- /dev/null
+++ b/Source/WebCore/platform/gtk/PopupMenuGtk.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef PopupMenuGtk_h
+#define PopupMenuGtk_h
+
+#include "GRefPtrGtk.h"
+#include "IntRect.h"
+#include "PopupMenu.h"
+#include "PopupMenuClient.h"
+#include <wtf/HashMap.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+typedef struct _GdkEventKey GdkEventKey;
+
+namespace WebCore {
+
+class FrameView;
+class Scrollbar;
+
+class PopupMenuGtk : public PopupMenu {
+public:
+ PopupMenuGtk(PopupMenuClient*);
+ ~PopupMenuGtk();
+
+ virtual void show(const IntRect&, FrameView*, int index);
+ virtual void hide();
+ virtual void updateFromElement();
+ virtual void disconnectClient();
+ bool typeAheadFind(GdkEventKey*);
+
+private:
+ PopupMenuClient* client() const { return m_popupClient; }
+ void resetTypeAheadFindState();
+
+ static void menuItemActivated(GtkMenuItem* item, PopupMenuGtk*);
+ static void menuUnmapped(GtkWidget*, PopupMenuGtk*);
+ static void menuPositionFunction(GtkMenu*, gint*, gint*, gboolean*, PopupMenuGtk*);
+ static void menuRemoveItem(GtkWidget*, PopupMenuGtk*);
+ static int selectItemCallback(GtkMenuItem*, PopupMenuGtk*);
+ static int keyPressEventCallback(GtkWidget*, GdkEventKey*, PopupMenuGtk*);
+
+ PopupMenuClient* m_popupClient;
+ IntPoint m_menuPosition;
+ GRefPtr<GtkMenu> m_popup;
+ HashMap<GtkWidget*, int> m_indexMap;
+ String m_currentSearchString;
+ uint32_t m_previousKeyEventTimestamp;
+ unsigned int m_previousKeyEventCharacter;
+ GtkWidget* m_currentlySelectedMenuItem;
+};
+
+}
+
+#endif // PopupMenuGtk_h
diff --git a/Source/WebCore/platform/gtk/RenderThemeGtk.cpp b/Source/WebCore/platform/gtk/RenderThemeGtk.cpp
new file mode 100644
index 0000000..c194946
--- /dev/null
+++ b/Source/WebCore/platform/gtk/RenderThemeGtk.cpp
@@ -0,0 +1,598 @@
+/*
+ * Copyright (C) 2007 Apple Inc.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2008 Collabora Ltd.
+ * Copyright (C) 2009 Kenneth Rohde Christiansen
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "RenderThemeGtk.h"
+
+#include "CSSValueKeywords.h"
+#include "GOwnPtr.h"
+#include "Gradient.h"
+#include "GraphicsContext.h"
+#include "GtkVersioning.h"
+#include "HTMLMediaElement.h"
+#include "HTMLNames.h"
+#include "MediaControlElements.h"
+#include "RenderBox.h"
+#include "RenderObject.h"
+#include "TimeRanges.h"
+#include "UserAgentStyleSheets.h"
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+#if ENABLE(VIDEO)
+static HTMLMediaElement* getMediaElementFromRenderObject(RenderObject* o)
+{
+ Node* node = o->node();
+ Node* mediaNode = node ? node->shadowAncestorNode() : 0;
+ if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
+ return 0;
+
+ return static_cast<HTMLMediaElement*>(mediaNode);
+}
+
+static GtkIconSize getMediaButtonIconSize(int mediaIconSize)
+{
+ GtkIconSize iconSize = gtk_icon_size_from_name("webkit-media-button-size");
+ if (!iconSize)
+ iconSize = gtk_icon_size_register("webkit-media-button-size", mediaIconSize, mediaIconSize);
+ return iconSize;
+}
+
+void RenderThemeGtk::initMediaButtons()
+{
+ static bool iconsInitialized = false;
+
+ if (iconsInitialized)
+ return;
+
+ GRefPtr<GtkIconFactory> iconFactory = adoptGRef(gtk_icon_factory_new());
+ GtkIconSource* iconSource = gtk_icon_source_new();
+ const char* icons[] = { "audio-volume-high", "audio-volume-muted" };
+
+ gtk_icon_factory_add_default(iconFactory.get());
+
+ for (size_t i = 0; i < G_N_ELEMENTS(icons); ++i) {
+ gtk_icon_source_set_icon_name(iconSource, icons[i]);
+ GtkIconSet* iconSet = gtk_icon_set_new();
+ gtk_icon_set_add_source(iconSet, iconSource);
+ gtk_icon_factory_add(iconFactory.get(), icons[i], iconSet);
+ gtk_icon_set_unref(iconSet);
+ }
+
+ gtk_icon_source_free(iconSource);
+
+ iconsInitialized = true;
+}
+#endif
+
+PassRefPtr<RenderTheme> RenderThemeGtk::create()
+{
+ return adoptRef(new RenderThemeGtk());
+}
+
+PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
+{
+ static RenderTheme* rt = RenderThemeGtk::create().releaseRef();
+ return rt;
+}
+
+static int mozGtkRefCount = 0;
+
+RenderThemeGtk::RenderThemeGtk()
+ : m_gtkWindow(0)
+ , m_gtkContainer(0)
+ , m_gtkButton(0)
+ , m_gtkEntry(0)
+ , m_gtkTreeView(0)
+ , m_gtkVScale(0)
+ , m_gtkHScale(0)
+ , m_panelColor(Color::white)
+ , m_sliderColor(Color::white)
+ , m_sliderThumbColor(Color::white)
+ , m_mediaIconSize(16)
+ , m_mediaSliderHeight(14)
+ , m_mediaSliderThumbWidth(12)
+ , m_mediaSliderThumbHeight(12)
+#ifdef GTK_API_VERSION_2
+ , m_themePartsHaveRGBAColormap(true)
+#endif
+{
+
+ memset(&m_themeParts, 0, sizeof(GtkThemeParts));
+#ifdef GTK_API_VERSION_2
+ GdkColormap* colormap = gdk_screen_get_rgba_colormap(gdk_screen_get_default());
+ if (!colormap) {
+ m_themePartsHaveRGBAColormap = false;
+ colormap = gdk_screen_get_default_colormap(gdk_screen_get_default());
+ }
+ m_themeParts.colormap = colormap;
+#endif
+
+ // Initialize the Mozilla theme drawing code.
+ if (!mozGtkRefCount) {
+ moz_gtk_init();
+ moz_gtk_use_theme_parts(&m_themeParts);
+ }
+ ++mozGtkRefCount;
+
+#if ENABLE(VIDEO)
+ initMediaColors();
+ initMediaButtons();
+#endif
+}
+
+RenderThemeGtk::~RenderThemeGtk()
+{
+ --mozGtkRefCount;
+
+ if (!mozGtkRefCount)
+ moz_gtk_shutdown();
+
+ gtk_widget_destroy(m_gtkWindow);
+}
+
+void RenderThemeGtk::getIndicatorMetrics(ControlPart part, int& indicatorSize, int& indicatorSpacing) const
+{
+ ASSERT(part == CheckboxPart || part == RadioPart);
+ if (part == CheckboxPart) {
+ moz_gtk_checkbox_get_metrics(&indicatorSize, &indicatorSpacing);
+ return;
+ }
+
+ // RadioPart
+ moz_gtk_radio_get_metrics(&indicatorSize, &indicatorSpacing);
+}
+
+static bool supportsFocus(ControlPart appearance)
+{
+ switch (appearance) {
+ case PushButtonPart:
+ case ButtonPart:
+ case TextFieldPart:
+ case TextAreaPart:
+ case SearchFieldPart:
+ case MenulistPart:
+ case RadioPart:
+ case CheckboxPart:
+ case SliderHorizontalPart:
+ case SliderVerticalPart:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool RenderThemeGtk::supportsFocusRing(const RenderStyle* style) const
+{
+ return supportsFocus(style->appearance());
+}
+
+bool RenderThemeGtk::controlSupportsTints(const RenderObject* o) const
+{
+ return isEnabled(o);
+}
+
+int RenderThemeGtk::baselinePosition(const RenderObject* o) const
+{
+ if (!o->isBox())
+ return 0;
+
+ // FIXME: This strategy is possibly incorrect for the GTK+ port.
+ if (o->style()->appearance() == CheckboxPart
+ || o->style()->appearance() == RadioPart) {
+ const RenderBox* box = toRenderBox(o);
+ return box->marginTop() + box->height() - 2;
+ }
+
+ return RenderTheme::baselinePosition(o);
+}
+
+// This is used in RenderThemeGtk2 and RenderThemeGtk3. Normally, it would be in
+// the RenderThemeGtk header (perhaps as a static method), but we want to avoid
+// having to include GTK+ headers only for the GtkTextDirection enum.
+GtkTextDirection gtkTextDirection(TextDirection direction)
+{
+ switch (direction) {
+ case RTL:
+ return GTK_TEXT_DIR_RTL;
+ case LTR:
+ return GTK_TEXT_DIR_LTR;
+ default:
+ return GTK_TEXT_DIR_NONE;
+ }
+}
+
+GtkStateType RenderThemeGtk::gtkIconState(RenderObject* renderObject)
+{
+ if (!isEnabled(renderObject))
+ return GTK_STATE_INSENSITIVE;
+ if (isPressed(renderObject))
+ return GTK_STATE_ACTIVE;
+ if (isHovered(renderObject))
+ return GTK_STATE_PRELIGHT;
+
+ return GTK_STATE_NORMAL;
+}
+
+void RenderThemeGtk::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const
+{
+ // Some layout tests check explicitly that buttons ignore line-height.
+ if (style->appearance() == PushButtonPart)
+ style->setLineHeight(RenderStyle::initialLineHeight());
+}
+
+void RenderThemeGtk::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ // The tests check explicitly that select menu buttons ignore line height.
+ style->setLineHeight(RenderStyle::initialLineHeight());
+
+ // We cannot give a proper rendering when border radius is active, unfortunately.
+ style->resetBorderRadius();
+}
+
+void RenderThemeGtk::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ adjustMenuListStyle(selector, style, e);
+}
+
+bool RenderThemeGtk::paintMenuListButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
+{
+ return paintMenuList(object, info, rect);
+}
+
+bool RenderThemeGtk::paintTextArea(RenderObject* o, const PaintInfo& i, const IntRect& r)
+{
+ return paintTextField(o, i, r);
+}
+
+static void paintGdkPixbuf(GraphicsContext* context, const GdkPixbuf* icon, const IntPoint& iconPoint)
+{
+ cairo_t* cr = context->platformContext();
+ cairo_save(cr);
+ gdk_cairo_set_source_pixbuf(cr, icon, iconPoint.x(), iconPoint.y());
+ cairo_paint(cr);
+ cairo_restore(cr);
+}
+
+void RenderThemeGtk::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ adjustSearchFieldCancelButtonStyle(selector, style, e);
+}
+
+bool RenderThemeGtk::paintSearchFieldResultsButton(RenderObject* o, const PaintInfo& i, const IntRect& rect)
+{
+ return paintSearchFieldResultsDecoration(o, i, rect);
+}
+
+void RenderThemeGtk::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ style->resetBorder();
+ style->resetPadding();
+
+ gint width = 0, height = 0;
+ gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
+ style->setWidth(Length(width, Fixed));
+ style->setHeight(Length(height, Fixed));
+}
+
+static IntPoint centerRectVerticallyInParentInputElement(RenderObject* object, const IntRect& rect)
+{
+ Node* input = object->node()->shadowAncestorNode(); // Get the renderer of <input> element.
+ if (!input->renderer()->isBox())
+ return rect.topLeft();
+
+ // If possible center the y-coordinate of the rect vertically in the parent input element.
+ // We also add one pixel here to ensure that the y coordinate is rounded up for box heights
+ // that are even, which looks in relation to the box text.
+ IntRect inputContentBox = toRenderBox(input->renderer())->absoluteContentBox();
+
+ return IntPoint(rect.x(), inputContentBox.y() + (inputContentBox.height() - rect.height() + 1) / 2);
+}
+
+bool RenderThemeGtk::paintSearchFieldResultsDecoration(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
+{
+ GRefPtr<GdkPixbuf> icon = getStockIcon(GTK_TYPE_ENTRY, GTK_STOCK_FIND,
+ gtkTextDirection(renderObject->style()->direction()),
+ gtkIconState(renderObject), GTK_ICON_SIZE_MENU);
+ paintGdkPixbuf(paintInfo.context, icon.get(), centerRectVerticallyInParentInputElement(renderObject, rect));
+ return false;
+}
+
+void RenderThemeGtk::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ style->resetBorder();
+ style->resetPadding();
+
+ gint width = 0, height = 0;
+ gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
+ style->setWidth(Length(width, Fixed));
+ style->setHeight(Length(height, Fixed));
+}
+
+bool RenderThemeGtk::paintSearchFieldCancelButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
+{
+ GRefPtr<GdkPixbuf> icon = getStockIcon(GTK_TYPE_ENTRY, GTK_STOCK_CLEAR,
+ gtkTextDirection(renderObject->style()->direction()),
+ gtkIconState(renderObject), GTK_ICON_SIZE_MENU);
+ paintGdkPixbuf(paintInfo.context, icon.get(), centerRectVerticallyInParentInputElement(renderObject, rect));
+ return false;
+}
+
+void RenderThemeGtk::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ // We cannot give a proper rendering when border radius is active, unfortunately.
+ style->resetBorderRadius();
+ style->setLineHeight(RenderStyle::initialLineHeight());
+}
+
+bool RenderThemeGtk::paintSearchField(RenderObject* o, const PaintInfo& i, const IntRect& rect)
+{
+ return paintTextField(o, i, rect);
+}
+
+void RenderThemeGtk::adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
+{
+ style->setBoxShadow(0);
+}
+
+void RenderThemeGtk::adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
+{
+ style->setBoxShadow(0);
+}
+
+double RenderThemeGtk::caretBlinkInterval() const
+{
+ GtkSettings* settings = gtk_settings_get_default();
+
+ gboolean shouldBlink;
+ gint time;
+
+ g_object_get(settings, "gtk-cursor-blink", &shouldBlink, "gtk-cursor-blink-time", &time, NULL);
+
+ if (!shouldBlink)
+ return 0;
+
+ return time / 2000.;
+}
+
+static double getScreenDPI()
+{
+ // FIXME: Really this should be the widget's screen.
+ GdkScreen* screen = gdk_screen_get_default();
+ if (!screen)
+ return 96; // Default to 96 DPI.
+
+ float dpi = gdk_screen_get_resolution(screen);
+ if (dpi <= 0)
+ return 96;
+ return dpi;
+}
+
+void RenderThemeGtk::systemFont(int, FontDescription& fontDescription) const
+{
+ GtkSettings* settings = gtk_settings_get_default();
+ if (!settings)
+ return;
+
+ // This will be a font selection string like "Sans 10" so we cannot use it as the family name.
+ GOwnPtr<gchar> fontName;
+ g_object_get(settings, "gtk-font-name", &fontName.outPtr(), NULL);
+
+ PangoFontDescription* pangoDescription = pango_font_description_from_string(fontName.get());
+ if (!pangoDescription)
+ return;
+
+ fontDescription.firstFamily().setFamily(pango_font_description_get_family(pangoDescription));
+
+ int size = pango_font_description_get_size(pangoDescription) / PANGO_SCALE;
+ // If the size of the font is in points, we need to convert it to pixels.
+ if (!pango_font_description_get_size_is_absolute(pangoDescription))
+ size = size * (getScreenDPI() / 72.0);
+
+ fontDescription.setSpecifiedSize(size);
+ fontDescription.setIsAbsoluteSize(true);
+ fontDescription.setGenericFamily(FontDescription::NoFamily);
+ fontDescription.setWeight(FontWeightNormal);
+ fontDescription.setItalic(false);
+ pango_font_description_free(pangoDescription);
+}
+
+void RenderThemeGtk::platformColorsDidChange()
+{
+#if ENABLE(VIDEO)
+ initMediaColors();
+#endif
+ RenderTheme::platformColorsDidChange();
+}
+
+#if ENABLE(VIDEO)
+String RenderThemeGtk::extraMediaControlsStyleSheet()
+{
+ return String(mediaControlsGtkUserAgentStyleSheet, sizeof(mediaControlsGtkUserAgentStyleSheet));
+}
+
+void RenderThemeGtk::adjustMediaSliderThumbSize(RenderObject* renderObject) const
+{
+ ControlPart part = renderObject->style()->appearance();
+
+ if (part == MediaSliderThumbPart) {
+ renderObject->style()->setWidth(Length(m_mediaSliderThumbWidth, Fixed));
+ renderObject->style()->setHeight(Length(m_mediaSliderThumbHeight, Fixed));
+ }
+}
+
+bool RenderThemeGtk::paintMediaButton(RenderObject* renderObject, GraphicsContext* context, const IntRect& rect, const char* iconName)
+{
+ GRefPtr<GdkPixbuf> icon = getStockIcon(GTK_TYPE_CONTAINER, iconName,
+ gtkTextDirection(renderObject->style()->direction()),
+ gtkIconState(renderObject),
+ getMediaButtonIconSize(m_mediaIconSize));
+ IntPoint iconPoint(rect.x() + (rect.width() - m_mediaIconSize) / 2,
+ rect.y() + (rect.height() - m_mediaIconSize) / 2);
+ context->fillRect(FloatRect(rect), m_panelColor, ColorSpaceDeviceRGB);
+ paintGdkPixbuf(context, icon.get(), iconPoint);
+ return false;
+}
+
+bool RenderThemeGtk::paintMediaFullscreenButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
+{
+ return paintMediaButton(renderObject, paintInfo.context, rect, GTK_STOCK_FULLSCREEN);
+}
+
+bool RenderThemeGtk::paintMediaMuteButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
+{
+ HTMLMediaElement* mediaElement = getMediaElementFromRenderObject(renderObject);
+ if (!mediaElement)
+ return false;
+
+ return paintMediaButton(renderObject, paintInfo.context, rect, mediaElement->muted() ? "audio-volume-muted" : "audio-volume-high");
+}
+
+bool RenderThemeGtk::paintMediaPlayButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
+{
+ Node* node = renderObject->node();
+ if (!node)
+ return false;
+
+ MediaControlPlayButtonElement* button = static_cast<MediaControlPlayButtonElement*>(node);
+ return paintMediaButton(renderObject, paintInfo.context, rect, button->displayType() == MediaPlayButton ? GTK_STOCK_MEDIA_PLAY : GTK_STOCK_MEDIA_PAUSE);
+}
+
+bool RenderThemeGtk::paintMediaSeekBackButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
+{
+ return paintMediaButton(renderObject, paintInfo.context, rect, GTK_STOCK_MEDIA_REWIND);
+}
+
+bool RenderThemeGtk::paintMediaSeekForwardButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
+{
+ return paintMediaButton(renderObject, paintInfo.context, rect, GTK_STOCK_MEDIA_FORWARD);
+}
+
+bool RenderThemeGtk::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+{
+ GraphicsContext* context = paintInfo.context;
+
+ context->fillRect(FloatRect(r), m_panelColor, ColorSpaceDeviceRGB);
+ context->fillRect(FloatRect(IntRect(r.x(), r.y() + (r.height() - m_mediaSliderHeight) / 2,
+ r.width(), m_mediaSliderHeight)), m_sliderColor, ColorSpaceDeviceRGB);
+
+ RenderStyle* style = o->style();
+ HTMLMediaElement* mediaElement = toParentMediaElement(o);
+
+ if (!mediaElement)
+ return false;
+
+ // Draw the buffered ranges. This code is highly inspired from
+ // Chrome for the gradient code.
+ float mediaDuration = mediaElement->duration();
+ RefPtr<TimeRanges> timeRanges = mediaElement->buffered();
+ IntRect trackRect = r;
+ int totalWidth = trackRect.width();
+
+ trackRect.inflate(-style->borderLeftWidth());
+ context->save();
+ context->setStrokeStyle(NoStroke);
+
+ for (unsigned index = 0; index < timeRanges->length(); ++index) {
+ ExceptionCode ignoredException;
+ float start = timeRanges->start(index, ignoredException);
+ float end = timeRanges->end(index, ignoredException);
+ int width = ((end - start) * totalWidth) / mediaDuration;
+ IntRect rangeRect;
+ if (!index) {
+ rangeRect = trackRect;
+ rangeRect.setWidth(width);
+ } else {
+ rangeRect.setLocation(IntPoint(trackRect.x() + start / mediaDuration* totalWidth, trackRect.y()));
+ rangeRect.setSize(IntSize(width, trackRect.height()));
+ }
+
+ // Don't bother drawing empty range.
+ if (rangeRect.isEmpty())
+ continue;
+
+ IntPoint sliderTopLeft = rangeRect.location();
+ IntPoint sliderTopRight = sliderTopLeft;
+ sliderTopRight.move(0, rangeRect.height());
+
+ RefPtr<Gradient> gradient = Gradient::create(sliderTopLeft, sliderTopRight);
+ Color startColor = m_panelColor;
+ gradient->addColorStop(0.0, startColor);
+ gradient->addColorStop(1.0, Color(startColor.red() / 2, startColor.green() / 2, startColor.blue() / 2, startColor.alpha()));
+
+ context->setFillGradient(gradient);
+ context->fillRect(rangeRect);
+ }
+
+ context->restore();
+ return false;
+}
+
+bool RenderThemeGtk::paintMediaSliderThumb(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r)
+{
+ // Make the thumb nicer with rounded corners.
+ paintInfo.context->fillRoundedRect(r, IntSize(3, 3), IntSize(3, 3), IntSize(3, 3), IntSize(3, 3), m_sliderThumbColor, ColorSpaceDeviceRGB);
+ return false;
+}
+
+String RenderThemeGtk::formatMediaControlsCurrentTime(float currentTime, float duration) const
+{
+ return formatMediaControlsTime(currentTime) + " / " + formatMediaControlsTime(duration);
+}
+
+bool RenderThemeGtk::paintMediaCurrentTime(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
+{
+ GraphicsContext* context = paintInfo.context;
+
+ context->fillRect(FloatRect(rect), m_panelColor, ColorSpaceDeviceRGB);
+ return false;
+}
+#endif
+
+#if ENABLE(PROGRESS_TAG)
+double RenderThemeGtk::animationRepeatIntervalForProgressBar(RenderProgress*) const
+{
+ // FIXME: It doesn't look like there is a good way yet to support animated
+ // progress bars with the Mozilla theme drawing code.
+ return 0;
+}
+
+double RenderThemeGtk::animationDurationForProgressBar(RenderProgress*) const
+{
+ // FIXME: It doesn't look like there is a good way yet to support animated
+ // progress bars with the Mozilla theme drawing code.
+ return 0;
+}
+
+void RenderThemeGtk::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle* style, Element*) const
+{
+ style->setBoxShadow(0);
+}
+#endif
+
+}
diff --git a/Source/WebCore/platform/gtk/RenderThemeGtk.h b/Source/WebCore/platform/gtk/RenderThemeGtk.h
new file mode 100644
index 0000000..ef1df05
--- /dev/null
+++ b/Source/WebCore/platform/gtk/RenderThemeGtk.h
@@ -0,0 +1,209 @@
+/*
+ * This file is part of the WebKit project.
+ *
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2010 Igalia S.L.
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef RenderThemeGtk_h
+#define RenderThemeGtk_h
+
+#include "GRefPtr.h"
+#include "gtkdrawing.h"
+#include "RenderTheme.h"
+
+namespace WebCore {
+
+class RenderThemeGtk : public RenderTheme {
+private:
+ RenderThemeGtk();
+ virtual ~RenderThemeGtk();
+
+public:
+ static PassRefPtr<RenderTheme> create();
+
+ // A method asking if the theme's controls actually care about redrawing when hovered.
+ virtual bool supportsHover(const RenderStyle* style) const { return true; }
+
+ // A method asking if the theme is able to draw the focus ring.
+ virtual bool supportsFocusRing(const RenderStyle*) const;
+
+ // A method asking if the control changes its tint when the window has focus or not.
+ virtual bool controlSupportsTints(const RenderObject*) const;
+
+ // A general method asking if any control tinting is supported at all.
+ virtual bool supportsControlTints() const { return true; }
+
+ virtual void adjustRepaintRect(const RenderObject*, IntRect&);
+
+ // A method to obtain the baseline position for a "leaf" control. This will only be used if a baseline
+ // position cannot be determined by examining child content. Checkboxes and radio buttons are examples of
+ // controls that need to do this.
+ virtual int baselinePosition(const RenderObject*) const;
+
+ // The platform selection color.
+ virtual Color platformActiveSelectionBackgroundColor() const;
+ virtual Color platformInactiveSelectionBackgroundColor() const;
+ virtual Color platformActiveSelectionForegroundColor() const;
+ virtual Color platformInactiveSelectionForegroundColor() const;
+
+ // List Box selection color
+ virtual Color activeListBoxSelectionBackgroundColor() const;
+ virtual Color activeListBoxSelectionForegroundColor() const;
+ virtual Color inactiveListBoxSelectionBackgroundColor() const;
+ virtual Color inactiveListBoxSelectionForegroundColor() const;
+
+ virtual double caretBlinkInterval() const;
+
+ virtual void platformColorsDidChange();
+
+ // System fonts and colors.
+ virtual void systemFont(int propId, FontDescription&) const;
+ virtual Color systemColor(int cssValueId) const;
+
+#if ENABLE(VIDEO)
+ virtual String extraMediaControlsStyleSheet();
+ virtual String formatMediaControlsCurrentTime(float currentTime, float duration) const;
+#endif
+
+ void getIndicatorMetrics(ControlPart, int& indicatorSize, int& indicatorSpacing) const;
+
+#ifdef GTK_API_VERSION_2
+ GtkWidget* gtkScrollbar();
+#else
+ GtkStyleContext* gtkScrollbarStyle();
+#endif
+
+protected:
+ virtual bool paintCheckbox(RenderObject* o, const PaintInfo& i, const IntRect& r);
+ virtual void setCheckboxSize(RenderStyle* style) const;
+
+ virtual bool paintRadio(RenderObject* o, const PaintInfo& i, const IntRect& r);
+ virtual void setRadioSize(RenderStyle* style) const;
+
+ virtual void adjustButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintButton(RenderObject*, const PaintInfo&, const IntRect&);
+
+ virtual bool paintTextField(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual bool paintTextArea(RenderObject*, const PaintInfo&, const IntRect&);
+
+ int popupInternalPaddingLeft(RenderStyle*) const;
+ int popupInternalPaddingRight(RenderStyle*) const;
+ int popupInternalPaddingTop(RenderStyle*) const;
+ int popupInternalPaddingBottom(RenderStyle*) const;
+
+ // The Mac port differentiates between the "menu list" and the "menu list button."
+ // The former is used when a menu list button has been styled. This is used to ensure
+ // Aqua themed controls whenever possible. We always want to use GTK+ theming, so
+ // we don't maintain this differentiation.
+ virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element* e) const;
+ virtual bool paintMenuList(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual bool paintMenuListButton(RenderObject*, const PaintInfo&, const IntRect&);
+
+ virtual void adjustSearchFieldResultsDecorationStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintSearchFieldResultsDecoration(RenderObject*, const PaintInfo&, const IntRect&);
+
+ virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintSearchField(RenderObject*, const PaintInfo&, const IntRect&);
+
+ virtual void adjustSearchFieldResultsButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintSearchFieldResultsButton(RenderObject*, const PaintInfo&, const IntRect&);
+
+ virtual void adjustSearchFieldCancelButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintSearchFieldCancelButton(RenderObject*, const PaintInfo&, const IntRect&);
+
+ virtual bool paintSliderTrack(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual void adjustSliderTrackStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+
+ virtual bool paintSliderThumb(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual void adjustSliderThumbStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+
+ virtual void adjustSliderThumbSize(RenderObject* object) const;
+
+#if ENABLE(VIDEO)
+ void initMediaColors();
+ void initMediaButtons();
+ void adjustMediaSliderThumbSize(RenderObject*) const;
+ virtual bool paintMediaFullscreenButton(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual bool paintMediaPlayButton(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual bool paintMediaMuteButton(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual bool paintMediaSeekBackButton(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual bool paintMediaSeekForwardButton(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual bool paintMediaSliderTrack(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual bool paintMediaSliderThumb(RenderObject*, const PaintInfo&, const IntRect&);
+ virtual bool paintMediaCurrentTime(RenderObject*, const PaintInfo&, const IntRect&);
+#endif
+
+#if ENABLE(PROGRESS_TAG)
+ virtual double animationRepeatIntervalForProgressBar(RenderProgress*) const;
+ virtual double animationDurationForProgressBar(RenderProgress*) const;
+ virtual void adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintProgressBar(RenderObject*, const PaintInfo&, const IntRect&);
+#endif
+
+private:
+ GtkWidget* gtkButton() const;
+ GtkWidget* gtkEntry() const;
+ GtkWidget* gtkTreeView() const;
+ GtkWidget* gtkVScale() const;
+ GtkWidget* gtkHScale() const;
+ GtkWidget* gtkContainer() const;
+
+ void setupWidgetAndAddToContainer(GtkWidget*, GtkWidget*) const;
+ GtkStateType getGtkStateType(RenderObject* object);
+ bool paintRenderObject(GtkThemeWidgetType, RenderObject*, GraphicsContext*, const IntRect& rect, int flags = 0);
+#if ENABLE(VIDEO)
+ bool paintMediaButton(RenderObject*, GraphicsContext*, const IntRect&, const char* iconName);
+#endif
+ GtkStateType gtkIconState(RenderObject*);
+ static void setTextInputBorders(RenderStyle*);
+ GRefPtr<GdkPixbuf> getStockIcon(GType, const char* iconName, gint direction, gint state, gint iconSize);
+
+ mutable GtkWidget* m_gtkWindow;
+ mutable GtkWidget* m_gtkContainer;
+ mutable GtkWidget* m_gtkButton;
+ mutable GtkWidget* m_gtkEntry;
+ mutable GtkWidget* m_gtkTreeView;
+ mutable GtkWidget* m_gtkVScale;
+ mutable GtkWidget* m_gtkHScale;
+
+ mutable Color m_panelColor;
+ mutable Color m_sliderColor;
+ mutable Color m_sliderThumbColor;
+
+ const int m_mediaIconSize;
+ const int m_mediaSliderHeight;
+ const int m_mediaSliderThumbWidth;
+ const int m_mediaSliderThumbHeight;
+
+ GtkThemeParts m_themeParts;
+#ifdef GTK_API_VERSION_2
+ bool m_themePartsHaveRGBAColormap;
+#endif
+ friend class WidgetRenderingContext;
+};
+
+}
+
+#endif // RenderThemeGtk_h
diff --git a/Source/WebCore/platform/gtk/RenderThemeGtk2.cpp b/Source/WebCore/platform/gtk/RenderThemeGtk2.cpp
new file mode 100644
index 0000000..fd391b7
--- /dev/null
+++ b/Source/WebCore/platform/gtk/RenderThemeGtk2.cpp
@@ -0,0 +1,517 @@
+/*
+ * Copyright (C) 2007 Apple Inc.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2008 Collabora Ltd.
+ * Copyright (C) 2009 Kenneth Rohde Christiansen
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "RenderThemeGtk.h"
+
+#ifdef GTK_API_VERSION_2
+
+#include "CSSValueKeywords.h"
+#include "GraphicsContext.h"
+#include "GtkVersioning.h"
+#include "HTMLNames.h"
+#include "MediaControlElements.h"
+#include "RenderObject.h"
+#include "TextDirection.h"
+#include "UserAgentStyleSheets.h"
+#include "WidgetRenderingContext.h"
+#include "gtkdrawing.h"
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+#if ENABLE(PROGRESS_TAG)
+#include "RenderProgress.h"
+#endif
+
+namespace WebCore {
+
+// This is not a static method, because we want to avoid having GTK+ headers in RenderThemeGtk.h.
+extern GtkTextDirection gtkTextDirection(TextDirection);
+
+#if ENABLE(VIDEO)
+void RenderThemeGtk::initMediaColors()
+{
+ GtkStyle* style = gtk_widget_get_style(GTK_WIDGET(gtkContainer()));
+ m_panelColor = style->bg[GTK_STATE_NORMAL];
+ m_sliderColor = style->bg[GTK_STATE_ACTIVE];
+ m_sliderThumbColor = style->bg[GTK_STATE_SELECTED];
+}
+#endif
+
+void RenderThemeGtk::adjustRepaintRect(const RenderObject*, IntRect&)
+{
+}
+
+GtkStateType RenderThemeGtk::getGtkStateType(RenderObject* object)
+{
+ if (!isEnabled(object) || isReadOnlyControl(object))
+ return GTK_STATE_INSENSITIVE;
+ if (isPressed(object))
+ return GTK_STATE_ACTIVE;
+ if (isHovered(object))
+ return GTK_STATE_PRELIGHT;
+ return GTK_STATE_NORMAL;
+}
+
+bool RenderThemeGtk::paintRenderObject(GtkThemeWidgetType type, RenderObject* renderObject, GraphicsContext* context, const IntRect& rect, int flags)
+{
+ // Painting is disabled so just claim to have succeeded
+ if (context->paintingDisabled())
+ return false;
+
+ GtkWidgetState widgetState;
+ widgetState.active = isPressed(renderObject);
+ widgetState.focused = isFocused(renderObject);
+
+ // https://bugs.webkit.org/show_bug.cgi?id=18364
+ // The Mozilla theme drawing code, only paints a button as pressed when it's pressed
+ // while hovered. Until we move away from the Mozila code, work-around the issue by
+ // forcing a pressed button into the hovered state. This ensures that buttons activated
+ // via the keyboard have the proper rendering.
+ widgetState.inHover = isHovered(renderObject) || (type == MOZ_GTK_BUTTON && isPressed(renderObject));
+
+ // FIXME: Disabled does not always give the correct appearance for ReadOnly
+ widgetState.disabled = !isEnabled(renderObject) || isReadOnlyControl(renderObject);
+ widgetState.isDefault = false;
+ widgetState.canDefault = false;
+ widgetState.depressed = false;
+
+ WidgetRenderingContext widgetContext(context, rect);
+ return !widgetContext.paintMozillaWidget(type, &widgetState, flags,
+ gtkTextDirection(renderObject->style()->direction()));
+}
+
+static void setToggleSize(const RenderThemeGtk* theme, RenderStyle* style, ControlPart appearance)
+{
+ // The width and height are both specified, so we shouldn't change them.
+ if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
+ return;
+
+ // FIXME: This is probably not correct use of indicatorSize and indicatorSpacing.
+ gint indicatorSize, indicatorSpacing;
+ theme->getIndicatorMetrics(appearance, indicatorSize, indicatorSpacing);
+
+ // Other ports hard-code this to 13, but GTK+ users tend to demand the native look.
+ // It could be made a configuration option values other than 13 actually break site compatibility.
+ int length = indicatorSize + indicatorSpacing;
+ if (style->width().isIntrinsicOrAuto())
+ style->setWidth(Length(length, Fixed));
+
+ if (style->height().isAuto())
+ style->setHeight(Length(length, Fixed));
+}
+
+void RenderThemeGtk::setCheckboxSize(RenderStyle* style) const
+{
+ setToggleSize(this, style, RadioPart);
+}
+
+bool RenderThemeGtk::paintCheckbox(RenderObject* object, const PaintInfo& info, const IntRect& rect)
+{
+ return paintRenderObject(MOZ_GTK_CHECKBUTTON, object, info.context, rect, isChecked(object));
+}
+
+void RenderThemeGtk::setRadioSize(RenderStyle* style) const
+{
+ setToggleSize(this, style, RadioPart);
+}
+
+bool RenderThemeGtk::paintRadio(RenderObject* object, const PaintInfo& info, const IntRect& rect)
+{
+ return paintRenderObject(MOZ_GTK_RADIOBUTTON, object, info.context, rect, isChecked(object));
+}
+
+bool RenderThemeGtk::paintButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
+{
+ if (info.context->paintingDisabled())
+ return false;
+
+ GtkWidget* widget = gtkButton();
+ IntRect buttonRect(IntPoint(), rect.size());
+ IntRect focusRect(buttonRect);
+
+ GtkStateType state = getGtkStateType(object);
+ gtk_widget_set_state(widget, state);
+ gtk_widget_set_direction(widget, gtkTextDirection(object->style()->direction()));
+
+ if (isFocused(object)) {
+ if (isEnabled(object)) {
+#if !GTK_CHECK_VERSION(2, 22, 0)
+ GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
+#endif
+ g_object_set(widget, "has-focus", TRUE, NULL);
+ }
+
+ gboolean interiorFocus = 0, focusWidth = 0, focusPadding = 0;
+ gtk_widget_style_get(widget,
+ "interior-focus", &interiorFocus,
+ "focus-line-width", &focusWidth,
+ "focus-padding", &focusPadding, NULL);
+ // If we are using exterior focus, we shrink the button rect down before
+ // drawing. If we are using interior focus we shrink the focus rect. This
+ // approach originates from the Mozilla theme drawing code (gtk2drawing.c).
+ if (interiorFocus) {
+ GtkStyle* style = gtk_widget_get_style(widget);
+ focusRect.inflateX(-style->xthickness - focusPadding);
+ focusRect.inflateY(-style->ythickness - focusPadding);
+ } else {
+ buttonRect.inflateX(-focusWidth - focusPadding);
+ buttonRect.inflateY(-focusPadding - focusPadding);
+ }
+ }
+
+ WidgetRenderingContext widgetContext(info.context, rect);
+ GtkShadowType shadowType = state == GTK_STATE_ACTIVE ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
+ widgetContext.gtkPaintBox(buttonRect, widget, state, shadowType, "button");
+ if (isFocused(object))
+ widgetContext.gtkPaintFocus(focusRect, widget, state, "button");
+
+#if !GTK_CHECK_VERSION(2, 22, 0)
+ GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
+#endif
+ g_object_set(widget, "has-focus", FALSE, NULL);
+ return false;
+}
+
+static void getComboBoxPadding(RenderStyle* style, int& left, int& top, int& right, int& bottom)
+{
+ // If this menu list button isn't drawn using the native theme, we
+ // don't add any extra padding beyond what WebCore already uses.
+ if (style->appearance() == NoControlPart)
+ return;
+ moz_gtk_get_widget_border(MOZ_GTK_DROPDOWN, &left, &top, &right, &bottom,
+ gtkTextDirection(style->direction()), TRUE);
+}
+
+int RenderThemeGtk::popupInternalPaddingLeft(RenderStyle* style) const
+{
+ int left = 0, top = 0, right = 0, bottom = 0;
+ getComboBoxPadding(style, left, top, right, bottom);
+ return left;
+}
+
+int RenderThemeGtk::popupInternalPaddingRight(RenderStyle* style) const
+{
+ int left = 0, top = 0, right = 0, bottom = 0;
+ getComboBoxPadding(style, left, top, right, bottom);
+ return right;
+}
+
+int RenderThemeGtk::popupInternalPaddingTop(RenderStyle* style) const
+{
+ int left = 0, top = 0, right = 0, bottom = 0;
+ getComboBoxPadding(style, left, top, right, bottom);
+ return top;
+}
+
+int RenderThemeGtk::popupInternalPaddingBottom(RenderStyle* style) const
+{
+ int left = 0, top = 0, right = 0, bottom = 0;
+ getComboBoxPadding(style, left, top, right, bottom);
+ return bottom;
+}
+
+bool RenderThemeGtk::paintMenuList(RenderObject* object, const PaintInfo& info, const IntRect& rect)
+{
+ return paintRenderObject(MOZ_GTK_DROPDOWN, object, info.context, rect);
+}
+
+bool RenderThemeGtk::paintTextField(RenderObject* object, const PaintInfo& info, const IntRect& rect)
+{
+ return paintRenderObject(MOZ_GTK_ENTRY, object, info.context, rect);
+}
+
+bool RenderThemeGtk::paintSliderTrack(RenderObject* object, const PaintInfo& info, const IntRect& rect)
+{
+ if (info.context->paintingDisabled())
+ return false;
+
+ ControlPart part = object->style()->appearance();
+ ASSERT(part == SliderHorizontalPart || part == SliderVerticalPart);
+
+ // We shrink the trough rect slightly to make room for the focus indicator.
+ IntRect troughRect(IntPoint(), rect.size()); // This is relative to rect.
+ GtkWidget* widget = 0;
+ if (part == SliderVerticalPart) {
+ widget = gtkVScale();
+ troughRect.inflateY(-gtk_widget_get_style(widget)->ythickness);
+ } else {
+ widget = gtkHScale();
+ troughRect.inflateX(-gtk_widget_get_style(widget)->xthickness);
+ }
+ gtk_widget_set_direction(widget, gtkTextDirection(object->style()->direction()));
+
+ WidgetRenderingContext widgetContext(info.context, rect);
+ widgetContext.gtkPaintBox(troughRect, widget, GTK_STATE_ACTIVE, GTK_SHADOW_OUT, "trough");
+ if (isFocused(object))
+ widgetContext.gtkPaintFocus(IntRect(IntPoint(), rect.size()), widget, getGtkStateType(object), "trough");
+
+ return false;
+}
+
+bool RenderThemeGtk::paintSliderThumb(RenderObject* object, const PaintInfo& info, const IntRect& rect)
+{
+ if (info.context->paintingDisabled())
+ return false;
+
+ ControlPart part = object->style()->appearance();
+ ASSERT(part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart);
+
+ GtkWidget* widget = 0;
+ const char* detail = 0;
+ GtkOrientation orientation;
+ if (part == SliderThumbVerticalPart) {
+ widget = gtkVScale();
+ detail = "vscale";
+ orientation = GTK_ORIENTATION_VERTICAL;
+ } else {
+ widget = gtkHScale();
+ detail = "hscale";
+ orientation = GTK_ORIENTATION_HORIZONTAL;
+ }
+ gtk_widget_set_direction(widget, gtkTextDirection(object->style()->direction()));
+
+ // Only some themes have slider thumbs respond to clicks and some don't. This information is
+ // gathered via the 'activate-slider' property, but it's deprecated in GTK+ 2.22 and removed in
+ // GTK+ 3.x. The drawback of not honoring it is that slider thumbs change color when you click
+ // on them.
+ IntRect thumbRect(IntPoint(), rect.size());
+ WidgetRenderingContext widgetContext(info.context, rect);
+ widgetContext.gtkPaintSlider(thumbRect, widget, getGtkStateType(object), GTK_SHADOW_OUT, detail, orientation);
+ return false;
+}
+
+void RenderThemeGtk::adjustSliderThumbSize(RenderObject* o) const
+{
+ ControlPart part = o->style()->appearance();
+#if ENABLE(VIDEO)
+ if (part == MediaSliderThumbPart || part == MediaVolumeSliderThumbPart) {
+ adjustMediaSliderThumbSize(o);
+ return;
+ }
+#endif
+
+ GtkWidget* widget = part == SliderThumbHorizontalPart ? gtkHScale() : gtkVScale();
+ int length = 0, width = 0;
+ gtk_widget_style_get(widget,
+ "slider_length", &length,
+ "slider_width", &width,
+ NULL);
+
+ if (part == SliderThumbHorizontalPart) {
+ o->style()->setWidth(Length(length, Fixed));
+ o->style()->setHeight(Length(width, Fixed));
+ return;
+ }
+ ASSERT(part == SliderThumbVerticalPart);
+ o->style()->setWidth(Length(width, Fixed));
+ o->style()->setHeight(Length(length, Fixed));
+}
+
+#if ENABLE(PROGRESS_TAG)
+bool RenderThemeGtk::paintProgressBar(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
+{
+ if (!renderObject->isProgress())
+ return true;
+
+ GtkWidget* progressBarWidget = moz_gtk_get_progress_widget();
+ if (!progressBarWidget)
+ return true;
+
+ if (paintRenderObject(MOZ_GTK_PROGRESSBAR, renderObject, paintInfo.context, rect))
+ return true;
+
+ IntRect chunkRect(rect);
+ RenderProgress* renderProgress = toRenderProgress(renderObject);
+
+ GtkStyle* style = gtk_widget_get_style(progressBarWidget);
+ chunkRect.setHeight(chunkRect.height() - (2 * style->ythickness));
+ chunkRect.setY(chunkRect.y() + style->ythickness);
+ chunkRect.setWidth((chunkRect.width() - (2 * style->xthickness)) * renderProgress->position());
+ if (renderObject->style()->direction() == RTL)
+ chunkRect.setX(rect.x() + rect.width() - chunkRect.width() - style->xthickness);
+ else
+ chunkRect.setX(chunkRect.x() + style->xthickness);
+
+ return paintRenderObject(MOZ_GTK_PROGRESS_CHUNK, renderObject, paintInfo.context, chunkRect);
+}
+#endif
+
+GRefPtr<GdkPixbuf> RenderThemeGtk::getStockIcon(GType widgetType, const char* iconName, gint direction, gint state, gint iconSize)
+{
+ ASSERT(widgetType == GTK_TYPE_CONTAINER || widgetType == GTK_TYPE_ENTRY);
+ GtkWidget* widget = widgetType == GTK_TYPE_CONTAINER ? GTK_WIDGET(gtkContainer()) : gtkEntry();
+ GtkStyle* style = gtk_widget_get_style(widget);
+ GtkIconSet* iconSet = gtk_style_lookup_icon_set(style, iconName);
+ return adoptGRef(gtk_icon_set_render_icon(iconSet, style,
+ static_cast<GtkTextDirection>(direction),
+ static_cast<GtkStateType>(state),
+ static_cast<GtkIconSize>(iconSize), 0, 0));
+}
+
+
+Color RenderThemeGtk::platformActiveSelectionBackgroundColor() const
+{
+ GtkWidget* widget = gtkEntry();
+ return gtk_widget_get_style(widget)->base[GTK_STATE_SELECTED];
+}
+
+Color RenderThemeGtk::platformInactiveSelectionBackgroundColor() const
+{
+ GtkWidget* widget = gtkEntry();
+ return gtk_widget_get_style(widget)->base[GTK_STATE_ACTIVE];
+}
+
+Color RenderThemeGtk::platformActiveSelectionForegroundColor() const
+{
+ GtkWidget* widget = gtkEntry();
+ return gtk_widget_get_style(widget)->text[GTK_STATE_SELECTED];
+}
+
+Color RenderThemeGtk::platformInactiveSelectionForegroundColor() const
+{
+ GtkWidget* widget = gtkEntry();
+ return gtk_widget_get_style(widget)->text[GTK_STATE_ACTIVE];
+}
+
+Color RenderThemeGtk::activeListBoxSelectionBackgroundColor() const
+{
+ GtkWidget* widget = gtkTreeView();
+ return gtk_widget_get_style(widget)->base[GTK_STATE_SELECTED];
+}
+
+Color RenderThemeGtk::inactiveListBoxSelectionBackgroundColor() const
+{
+ GtkWidget* widget = gtkTreeView();
+ return gtk_widget_get_style(widget)->base[GTK_STATE_ACTIVE];
+}
+
+Color RenderThemeGtk::activeListBoxSelectionForegroundColor() const
+{
+ GtkWidget* widget = gtkTreeView();
+ return gtk_widget_get_style(widget)->text[GTK_STATE_SELECTED];
+}
+
+Color RenderThemeGtk::inactiveListBoxSelectionForegroundColor() const
+{
+ GtkWidget* widget = gtkTreeView();
+ return gtk_widget_get_style(widget)->text[GTK_STATE_ACTIVE];
+}
+
+Color RenderThemeGtk::systemColor(int cssValueId) const
+{
+ switch (cssValueId) {
+ case CSSValueButtontext:
+ return Color(gtk_widget_get_style(gtkButton())->fg[GTK_STATE_NORMAL]);
+ case CSSValueCaptiontext:
+ return Color(gtk_widget_get_style(gtkEntry())->fg[GTK_STATE_NORMAL]);
+ default:
+ return RenderTheme::systemColor(cssValueId);
+ }
+}
+
+static void gtkStyleSetCallback(GtkWidget* widget, GtkStyle* previous, RenderTheme* renderTheme)
+{
+ // FIXME: Make sure this function doesn't get called many times for a single GTK+ style change signal.
+ renderTheme->platformColorsDidChange();
+}
+
+void RenderThemeGtk::setupWidgetAndAddToContainer(GtkWidget* widget, GtkWidget* window) const
+{
+ gtk_container_add(GTK_CONTAINER(window), widget);
+ gtk_widget_realize(widget);
+ g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
+
+ // FIXME: Perhaps this should only be called for the containing window or parent container.
+ g_signal_connect(widget, "style-set", G_CALLBACK(gtkStyleSetCallback), const_cast<RenderThemeGtk*>(this));
+}
+
+GtkWidget* RenderThemeGtk::gtkContainer() const
+{
+ if (m_gtkContainer)
+ return m_gtkContainer;
+
+ m_gtkWindow = gtk_window_new(GTK_WINDOW_POPUP);
+ gtk_widget_set_colormap(m_gtkWindow, m_themeParts.colormap);
+ gtk_widget_realize(m_gtkWindow);
+ gtk_widget_set_name(m_gtkWindow, "MozillaGtkWidget");
+
+ m_gtkContainer = gtk_fixed_new();
+ setupWidgetAndAddToContainer(m_gtkContainer, m_gtkWindow);
+ return m_gtkContainer;
+}
+
+GtkWidget* RenderThemeGtk::gtkButton() const
+{
+ if (m_gtkButton)
+ return m_gtkButton;
+ m_gtkButton = gtk_button_new();
+ setupWidgetAndAddToContainer(m_gtkButton, gtkContainer());
+ return m_gtkButton;
+}
+
+GtkWidget* RenderThemeGtk::gtkEntry() const
+{
+ if (m_gtkEntry)
+ return m_gtkEntry;
+ m_gtkEntry = gtk_entry_new();
+ setupWidgetAndAddToContainer(m_gtkEntry, gtkContainer());
+ return m_gtkEntry;
+}
+
+GtkWidget* RenderThemeGtk::gtkTreeView() const
+{
+ if (m_gtkTreeView)
+ return m_gtkTreeView;
+ m_gtkTreeView = gtk_tree_view_new();
+ setupWidgetAndAddToContainer(m_gtkTreeView, gtkContainer());
+ return m_gtkTreeView;
+}
+
+GtkWidget* RenderThemeGtk::gtkVScale() const
+{
+ if (m_gtkVScale)
+ return m_gtkVScale;
+ m_gtkVScale = gtk_vscale_new(0);
+ setupWidgetAndAddToContainer(m_gtkVScale, gtkContainer());
+ return m_gtkVScale;
+}
+
+GtkWidget* RenderThemeGtk::gtkHScale() const
+{
+ if (m_gtkHScale)
+ return m_gtkHScale;
+ m_gtkHScale = gtk_hscale_new(0);
+ setupWidgetAndAddToContainer(m_gtkHScale, gtkContainer());
+ return m_gtkHScale;
+}
+
+GtkWidget* RenderThemeGtk::gtkScrollbar()
+{
+ return moz_gtk_get_scrollbar_widget();
+}
+
+} // namespace WebCore
+
+#endif // GTK_API_VERSION_2
diff --git a/Source/WebCore/platform/gtk/RenderThemeGtk3.cpp b/Source/WebCore/platform/gtk/RenderThemeGtk3.cpp
new file mode 100644
index 0000000..663404d
--- /dev/null
+++ b/Source/WebCore/platform/gtk/RenderThemeGtk3.cpp
@@ -0,0 +1,643 @@
+/*
+ * Copyright (C) 2007 Apple Inc.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2008 Collabora Ltd.
+ * Copyright (C) 2009 Kenneth Rohde Christiansen
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "RenderThemeGtk.h"
+
+#ifndef GTK_API_VERSION_2
+
+#include "CSSValueKeywords.h"
+#include "GraphicsContext.h"
+#include "GtkVersioning.h"
+#include "HTMLNames.h"
+#include "MediaControlElements.h"
+#include "Page.h"
+#include "RenderObject.h"
+#include "TextDirection.h"
+#include "UserAgentStyleSheets.h"
+#include "WidgetRenderingContext.h"
+#include "gtkdrawing.h"
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+#if ENABLE(PROGRESS_TAG)
+#include "RenderProgress.h"
+#endif
+
+namespace WebCore {
+
+typedef HashMap<GType, GRefPtr<GtkStyleContext> > StyleContextMap;
+static StyleContextMap& styleContextMap();
+
+static void gtkStyleChangedCallback(GObject*, GParamSpec*)
+{
+ StyleContextMap::const_iterator end = styleContextMap().end();
+ for (StyleContextMap::const_iterator iter = styleContextMap().begin(); iter != end; ++iter)
+ gtk_style_context_invalidate(iter->second.get());
+
+ Page::scheduleForcedStyleRecalcForAllPages();
+}
+
+static StyleContextMap& styleContextMap()
+{
+ DEFINE_STATIC_LOCAL(StyleContextMap, map, ());
+
+ static bool initialized = false;
+ if (!initialized) {
+ GtkSettings* settings = gtk_settings_get_default();
+ g_signal_connect(settings, "notify::gtk-theme-name", G_CALLBACK(gtkStyleChangedCallback), 0);
+ g_signal_connect(settings, "notify::gtk-color-scheme", G_CALLBACK(gtkStyleChangedCallback), 0);
+ initialized = true;
+ }
+ return map;
+}
+
+static GtkStyleContext* getStyleContext(GType widgetType)
+{
+ std::pair<StyleContextMap::iterator, bool> result = styleContextMap().add(widgetType, 0);
+ if (!result.second)
+ return result.first->second.get();
+
+ GtkWidgetPath* path = gtk_widget_path_new();
+ gtk_widget_path_append_type(path, widgetType);
+
+ GRefPtr<GtkStyleContext> context = adoptGRef(gtk_style_context_new());
+ gtk_style_context_set_path(context.get(), path);
+ gtk_widget_path_free(path);
+
+ result.first->second = context;
+ return context.get();
+}
+
+// This is not a static method, because we want to avoid having GTK+ headers in RenderThemeGtk.h.
+extern GtkTextDirection gtkTextDirection(TextDirection);
+
+void RenderThemeGtk::initMediaColors()
+{
+ GtkStyle* style = gtk_widget_get_style(GTK_WIDGET(gtkContainer()));
+ m_panelColor = style->bg[GTK_STATE_NORMAL];
+ m_sliderColor = style->bg[GTK_STATE_ACTIVE];
+ m_sliderThumbColor = style->bg[GTK_STATE_SELECTED];
+}
+
+static void adjustRectForFocus(GtkStyleContext* context, IntRect& rect)
+{
+ gint focusWidth, focusPad;
+ gtk_style_context_get_style(context,
+ "focus-line-width", &focusWidth,
+ "focus-padding", &focusPad, NULL);
+ rect.inflate(focusWidth + focusPad);
+}
+
+void RenderThemeGtk::adjustRepaintRect(const RenderObject* renderObject, IntRect& rect)
+{
+ GtkStyleContext* context = 0;
+ ControlPart part = renderObject->style()->appearance();
+ switch (part) {
+ case SliderVerticalPart:
+ case SliderHorizontalPart:
+ context = getStyleContext(part == SliderThumbHorizontalPart ? GTK_TYPE_HSCALE : GTK_TYPE_VSCALE);
+ break;
+ case ButtonPart:
+ context = getStyleContext(GTK_TYPE_BUTTON);
+
+ gboolean interiorFocus;
+ gtk_style_context_get_style(context, "interior-focus", &interiorFocus, NULL);
+ if (interiorFocus)
+ return;
+
+ break;
+ default:
+ return;
+ }
+
+ ASSERT(context);
+ adjustRectForFocus(context, rect);
+}
+
+GtkStateType RenderThemeGtk::getGtkStateType(RenderObject* object)
+{
+ if (!isEnabled(object) || isReadOnlyControl(object))
+ return GTK_STATE_INSENSITIVE;
+ if (isPressed(object))
+ return GTK_STATE_ACTIVE;
+ if (isHovered(object))
+ return GTK_STATE_PRELIGHT;
+ return GTK_STATE_NORMAL;
+}
+
+bool RenderThemeGtk::paintRenderObject(GtkThemeWidgetType type, RenderObject* renderObject, GraphicsContext* context, const IntRect& rect, int flags)
+{
+ // Painting is disabled so just claim to have succeeded
+ if (context->paintingDisabled())
+ return false;
+
+ GtkWidgetState widgetState;
+ widgetState.active = isPressed(renderObject);
+ widgetState.focused = isFocused(renderObject);
+
+ // https://bugs.webkit.org/show_bug.cgi?id=18364
+ // The Mozilla theme drawing code, only paints a button as pressed when it's pressed
+ // while hovered. Until we move away from the Mozila code, work-around the issue by
+ // forcing a pressed button into the hovered state. This ensures that buttons activated
+ // via the keyboard have the proper rendering.
+ widgetState.inHover = isHovered(renderObject) || (type == MOZ_GTK_BUTTON && isPressed(renderObject));
+
+ // FIXME: Disabled does not always give the correct appearance for ReadOnly
+ widgetState.disabled = !isEnabled(renderObject) || isReadOnlyControl(renderObject);
+ widgetState.isDefault = false;
+ widgetState.canDefault = false;
+ widgetState.depressed = false;
+
+ WidgetRenderingContext widgetContext(context, rect);
+ return !widgetContext.paintMozillaWidget(type, &widgetState, flags,
+ gtkTextDirection(renderObject->style()->direction()));
+}
+
+static void setToggleSize(const RenderThemeGtk* theme, RenderStyle* style, ControlPart appearance)
+{
+ // The width and height are both specified, so we shouldn't change them.
+ if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto())
+ return;
+
+ // FIXME: This is probably not correct use of indicatorSize and indicatorSpacing.
+ gint indicatorSize, indicatorSpacing;
+ theme->getIndicatorMetrics(appearance, indicatorSize, indicatorSpacing);
+
+ // Other ports hard-code this to 13, but GTK+ users tend to demand the native look.
+ // It could be made a configuration option values other than 13 actually break site compatibility.
+ int length = indicatorSize + indicatorSpacing;
+ if (style->width().isIntrinsicOrAuto())
+ style->setWidth(Length(length, Fixed));
+
+ if (style->height().isAuto())
+ style->setHeight(Length(length, Fixed));
+}
+
+void RenderThemeGtk::setCheckboxSize(RenderStyle* style) const
+{
+ setToggleSize(this, style, RadioPart);
+}
+
+bool RenderThemeGtk::paintCheckbox(RenderObject* object, const PaintInfo& info, const IntRect& rect)
+{
+ return paintRenderObject(MOZ_GTK_CHECKBUTTON, object, info.context, rect, isChecked(object));
+}
+
+void RenderThemeGtk::setRadioSize(RenderStyle* style) const
+{
+ setToggleSize(this, style, RadioPart);
+}
+
+bool RenderThemeGtk::paintRadio(RenderObject* object, const PaintInfo& info, const IntRect& rect)
+{
+ return paintRenderObject(MOZ_GTK_RADIOBUTTON, object, info.context, rect, isChecked(object));
+}
+
+bool RenderThemeGtk::paintButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
+{
+ GtkStyleContext* context = getStyleContext(GTK_TYPE_BUTTON);
+ gtk_style_context_save(context);
+
+ gtk_style_context_set_direction(context, static_cast<GtkTextDirection>(gtkTextDirection(renderObject->style()->direction())));
+ gtk_style_context_add_class(context, GTK_STYLE_CLASS_BUTTON);
+
+ IntRect buttonRect(rect);
+
+ if (isDefault(renderObject)) {
+ GtkBorder* borderPtr = 0;
+ GtkBorder border = { 1, 1, 1, 1 };
+
+ gtk_style_context_get_style(context, "default-border", &borderPtr, NULL);
+ if (borderPtr) {
+ border = *borderPtr;
+ gtk_border_free(borderPtr);
+ }
+
+ buttonRect.move(border.left, border.top);
+ buttonRect.setWidth(buttonRect.width() - (border.left + border.right));
+ buttonRect.setHeight(buttonRect.height() - (border.top + border.bottom));
+
+ gtk_style_context_add_class(context, GTK_STYLE_CLASS_DEFAULT);
+ }
+
+ guint flags = 0;
+ if (!isEnabled(renderObject) || isReadOnlyControl(renderObject))
+ flags |= GTK_STATE_FLAG_INSENSITIVE;
+ else if (isHovered(renderObject))
+ flags |= GTK_STATE_FLAG_PRELIGHT;
+ if (isPressed(renderObject))
+ flags |= GTK_STATE_FLAG_ACTIVE;
+ gtk_style_context_set_state(context, static_cast<GtkStateFlags>(flags));
+
+ gtk_render_background(context, paintInfo.context->platformContext(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height());
+ gtk_render_frame(context, paintInfo.context->platformContext(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height());
+
+ if (isFocused(renderObject)) {
+ gint focusWidth, focusPad;
+ gboolean displaceFocus, interiorFocus;
+ gtk_style_context_get_style(context,
+ "focus-line-width", &focusWidth,
+ "focus-padding", &focusPad,
+ "interior-focus", &interiorFocus,
+ "displace-focus", &displaceFocus,
+ NULL);
+
+ if (interiorFocus) {
+ GtkBorder borderWidth;
+ gtk_style_context_get_border(context, static_cast<GtkStateFlags>(flags), &borderWidth);
+
+ buttonRect = IntRect(buttonRect.x() + borderWidth.left + focusPad, buttonRect.y() + borderWidth.top + focusPad,
+ buttonRect.width() - (2 * focusPad + borderWidth.left + borderWidth.right),
+ buttonRect.height() - (2 * focusPad + borderWidth.top + borderWidth.bottom));
+ } else
+ buttonRect.inflate(focusWidth + focusPad);
+
+ if (displaceFocus && isPressed(renderObject)) {
+ gint childDisplacementX;
+ gint childDisplacementY;
+ gtk_style_context_get_style(context,
+ "child-displacement-x", &childDisplacementX,
+ "child-displacement-y", &childDisplacementY,
+ NULL);
+ buttonRect.move(childDisplacementX, childDisplacementY);
+ }
+
+ gtk_render_focus(context, paintInfo.context->platformContext(), buttonRect.x(), buttonRect.y(), buttonRect.width(), buttonRect.height());
+ }
+
+ gtk_style_context_restore(context);
+
+ return false;
+}
+
+static void getComboBoxPadding(RenderStyle* style, int& left, int& top, int& right, int& bottom)
+{
+ // If this menu list button isn't drawn using the native theme, we
+ // don't add any extra padding beyond what WebCore already uses.
+ if (style->appearance() == NoControlPart)
+ return;
+ moz_gtk_get_widget_border(MOZ_GTK_DROPDOWN, &left, &top, &right, &bottom,
+ gtkTextDirection(style->direction()), TRUE);
+}
+
+int RenderThemeGtk::popupInternalPaddingLeft(RenderStyle* style) const
+{
+ int left = 0, top = 0, right = 0, bottom = 0;
+ getComboBoxPadding(style, left, top, right, bottom);
+ return left;
+}
+
+int RenderThemeGtk::popupInternalPaddingRight(RenderStyle* style) const
+{
+ int left = 0, top = 0, right = 0, bottom = 0;
+ getComboBoxPadding(style, left, top, right, bottom);
+ return right;
+}
+
+int RenderThemeGtk::popupInternalPaddingTop(RenderStyle* style) const
+{
+ int left = 0, top = 0, right = 0, bottom = 0;
+ getComboBoxPadding(style, left, top, right, bottom);
+ return top;
+}
+
+int RenderThemeGtk::popupInternalPaddingBottom(RenderStyle* style) const
+{
+ int left = 0, top = 0, right = 0, bottom = 0;
+ getComboBoxPadding(style, left, top, right, bottom);
+ return bottom;
+}
+
+bool RenderThemeGtk::paintMenuList(RenderObject* object, const PaintInfo& info, const IntRect& rect)
+{
+ return paintRenderObject(MOZ_GTK_DROPDOWN, object, info.context, rect);
+}
+
+bool RenderThemeGtk::paintTextField(RenderObject* object, const PaintInfo& info, const IntRect& rect)
+{
+ return paintRenderObject(MOZ_GTK_ENTRY, object, info.context, rect);
+}
+
+bool RenderThemeGtk::paintSliderTrack(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
+{
+ ControlPart part = renderObject->style()->appearance();
+ ASSERT(part == SliderHorizontalPart || part == SliderVerticalPart);
+
+ GtkStyleContext* context = getStyleContext(part == SliderThumbHorizontalPart ? GTK_TYPE_HSCALE : GTK_TYPE_VSCALE);
+ gtk_style_context_save(context);
+
+ gtk_style_context_set_direction(context, gtkTextDirection(renderObject->style()->direction()));
+ gtk_style_context_add_class(context, GTK_STYLE_CLASS_SCALE);
+ gtk_style_context_add_class(context, GTK_STYLE_CLASS_TROUGH);
+
+ if (!isEnabled(renderObject) || isReadOnlyControl(renderObject))
+ gtk_style_context_set_state(context, GTK_STATE_FLAG_INSENSITIVE);
+
+ gtk_render_background(context, paintInfo.context->platformContext(),
+ rect.x(), rect.y(), rect.width(), rect.height());
+ gtk_render_frame(context, paintInfo.context->platformContext(),
+ rect.x(), rect.y(), rect.width(), rect.height());
+
+ if (isFocused(renderObject)) {
+ gint focusWidth, focusPad;
+ gtk_style_context_get_style(context,
+ "focus-line-width", &focusWidth,
+ "focus-padding", &focusPad, NULL);
+ IntRect focusRect(rect);
+ focusRect.inflate(focusWidth + focusPad);
+ gtk_render_focus(context, paintInfo.context->platformContext(),
+ focusRect.x(), focusRect.y(), focusRect.width(), focusRect.height());
+ }
+
+ gtk_style_context_restore(context);
+ return false;
+}
+
+bool RenderThemeGtk::paintSliderThumb(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
+{
+ ControlPart part = renderObject->style()->appearance();
+ ASSERT(part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart);
+
+ GtkStyleContext* context = getStyleContext(part == SliderThumbHorizontalPart ? GTK_TYPE_HSCALE : GTK_TYPE_VSCALE);
+ gtk_style_context_save(context);
+
+ gtk_style_context_set_direction(context, gtkTextDirection(renderObject->style()->direction()));
+ gtk_style_context_add_class(context, GTK_STYLE_CLASS_SCALE);
+ gtk_style_context_add_class(context, GTK_STYLE_CLASS_SLIDER);
+
+ gint troughBorder;
+ gtk_style_context_get_style(context, "trough-border", &troughBorder, NULL);
+
+ IntRect sliderRect(rect);
+ sliderRect.inflate(-troughBorder);
+
+ guint flags = 0;
+ if (!isEnabled(renderObject) || isReadOnlyControl(renderObject))
+ flags |= GTK_STATE_FLAG_INSENSITIVE;
+ else if (isHovered(renderObject))
+ flags |= GTK_STATE_FLAG_PRELIGHT;
+ if (isPressed(renderObject))
+ flags |= GTK_STATE_FLAG_ACTIVE;
+ gtk_style_context_set_state(context, static_cast<GtkStateFlags>(flags));
+
+ gtk_render_slider(context, paintInfo.context->platformContext(), sliderRect.x(), sliderRect.y(), sliderRect.width(), sliderRect.height(),
+ part == SliderThumbHorizontalPart ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
+
+ gtk_style_context_restore(context);
+
+ return false;
+}
+
+void RenderThemeGtk::adjustSliderThumbSize(RenderObject* renderObject) const
+{
+ ControlPart part = renderObject->style()->appearance();
+#if ENABLE(VIDEO)
+ if (part == MediaSliderThumbPart || part == MediaVolumeSliderThumbPart) {
+ adjustMediaSliderThumbSize(renderObject);
+ return;
+ }
+#endif
+
+ gint sliderWidth, sliderLength;
+ gtk_style_context_get_style(getStyleContext(part == SliderThumbHorizontalPart ? GTK_TYPE_HSCALE : GTK_TYPE_VSCALE),
+ "slider-width", &sliderWidth,
+ "slider-length", &sliderLength,
+ NULL);
+ if (part == SliderThumbHorizontalPart) {
+ renderObject->style()->setWidth(Length(sliderLength, Fixed));
+ renderObject->style()->setHeight(Length(sliderWidth, Fixed));
+ return;
+ }
+ ASSERT(part == SliderThumbVerticalPart);
+ renderObject->style()->setWidth(Length(sliderWidth, Fixed));
+ renderObject->style()->setHeight(Length(sliderLength, Fixed));
+}
+
+#if ENABLE(PROGRESS_TAG)
+bool RenderThemeGtk::paintProgressBar(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect)
+{
+ if (!renderObject->isProgress())
+ return true;
+
+ GtkWidget* progressBarWidget = moz_gtk_get_progress_widget();
+ if (!progressBarWidget)
+ return true;
+
+ if (paintRenderObject(MOZ_GTK_PROGRESSBAR, renderObject, paintInfo.context, rect))
+ return true;
+
+ IntRect chunkRect(rect);
+ RenderProgress* renderProgress = toRenderProgress(renderObject);
+
+ GtkStyle* style = gtk_widget_get_style(progressBarWidget);
+ chunkRect.setHeight(chunkRect.height() - (2 * style->ythickness));
+ chunkRect.setY(chunkRect.y() + style->ythickness);
+ chunkRect.setWidth((chunkRect.width() - (2 * style->xthickness)) * renderProgress->position());
+ if (renderObject->style()->direction() == RTL)
+ chunkRect.setX(rect.x() + rect.width() - chunkRect.width() - style->xthickness);
+ else
+ chunkRect.setX(chunkRect.x() + style->xthickness);
+
+ return paintRenderObject(MOZ_GTK_PROGRESS_CHUNK, renderObject, paintInfo.context, chunkRect);
+}
+#endif
+
+GRefPtr<GdkPixbuf> RenderThemeGtk::getStockIcon(GType widgetType, const char* iconName, gint direction, gint state, gint iconSize)
+{
+ GtkStyleContext* context = getStyleContext(widgetType);
+ GtkIconSet* iconSet = gtk_style_context_lookup_icon_set(context, iconName);
+
+ gtk_style_context_save(context);
+
+ guint flags = 0;
+ if (state == GTK_STATE_PRELIGHT)
+ flags |= GTK_STATE_FLAG_PRELIGHT;
+ else if (state == GTK_STATE_INSENSITIVE)
+ flags |= GTK_STATE_FLAG_INSENSITIVE;
+
+ gtk_style_context_set_state(context, static_cast<GtkStateFlags>(flags));
+ gtk_style_context_set_direction(context, static_cast<GtkTextDirection>(direction));
+ GdkPixbuf* icon = gtk_icon_set_render_icon_pixbuf(iconSet, context, static_cast<GtkIconSize>(iconSize));
+
+ gtk_style_context_restore(context);
+
+ return adoptGRef(icon);
+}
+
+Color RenderThemeGtk::platformActiveSelectionBackgroundColor() const
+{
+ GdkRGBA gdkRGBAColor;
+ gtk_style_context_get_background_color(getStyleContext(GTK_TYPE_ENTRY), GTK_STATE_FLAG_SELECTED, &gdkRGBAColor);
+ return gdkRGBAColor;
+}
+
+Color RenderThemeGtk::platformInactiveSelectionBackgroundColor() const
+{
+ GdkRGBA gdkRGBAColor;
+ gtk_style_context_get_background_color(getStyleContext(GTK_TYPE_ENTRY), GTK_STATE_FLAG_ACTIVE, &gdkRGBAColor);
+ return gdkRGBAColor;
+}
+
+Color RenderThemeGtk::platformActiveSelectionForegroundColor() const
+{
+ GdkRGBA gdkRGBAColor;
+ gtk_style_context_get_color(getStyleContext(GTK_TYPE_ENTRY), GTK_STATE_FLAG_SELECTED, &gdkRGBAColor);
+ return gdkRGBAColor;
+}
+
+Color RenderThemeGtk::platformInactiveSelectionForegroundColor() const
+{
+ GdkRGBA gdkRGBAColor;
+ gtk_style_context_get_color(getStyleContext(GTK_TYPE_ENTRY), GTK_STATE_FLAG_ACTIVE, &gdkRGBAColor);
+ return gdkRGBAColor;
+}
+
+Color RenderThemeGtk::activeListBoxSelectionBackgroundColor() const
+{
+ GdkRGBA gdkRGBAColor;
+ gtk_style_context_get_background_color(getStyleContext(GTK_TYPE_TREE_VIEW), GTK_STATE_FLAG_SELECTED, &gdkRGBAColor);
+ return gdkRGBAColor;
+}
+
+Color RenderThemeGtk::inactiveListBoxSelectionBackgroundColor() const
+{
+ GdkRGBA gdkRGBAColor;
+ gtk_style_context_get_background_color(getStyleContext(GTK_TYPE_TREE_VIEW), GTK_STATE_FLAG_ACTIVE, &gdkRGBAColor);
+ return gdkRGBAColor;
+}
+
+Color RenderThemeGtk::activeListBoxSelectionForegroundColor() const
+{
+ GdkRGBA gdkRGBAColor;
+ gtk_style_context_get_color(getStyleContext(GTK_TYPE_TREE_VIEW), GTK_STATE_FLAG_SELECTED, &gdkRGBAColor);
+ return gdkRGBAColor;
+}
+
+Color RenderThemeGtk::inactiveListBoxSelectionForegroundColor() const
+{
+ GdkRGBA gdkRGBAColor;
+ gtk_style_context_get_color(getStyleContext(GTK_TYPE_TREE_VIEW), GTK_STATE_FLAG_ACTIVE, &gdkRGBAColor);
+ return gdkRGBAColor;
+}
+
+Color RenderThemeGtk::systemColor(int cssValueId) const
+{
+ GdkRGBA gdkRGBAColor;
+
+ switch (cssValueId) {
+ case CSSValueButtontext:
+ gtk_style_context_get_color(getStyleContext(GTK_TYPE_BUTTON), static_cast<GtkStateFlags>(0), &gdkRGBAColor);
+ return gdkRGBAColor;
+ case CSSValueCaptiontext:
+ gtk_style_context_get_color(getStyleContext(GTK_TYPE_ENTRY), static_cast<GtkStateFlags>(0), &gdkRGBAColor);
+ return gdkRGBAColor;
+ default:
+ return RenderTheme::systemColor(cssValueId);
+ }
+}
+
+static void gtkStyleSetCallback(GtkWidget* widget, GtkStyle* previous, RenderTheme* renderTheme)
+{
+ // FIXME: Make sure this function doesn't get called many times for a single GTK+ style change signal.
+ renderTheme->platformColorsDidChange();
+}
+
+void RenderThemeGtk::setupWidgetAndAddToContainer(GtkWidget* widget, GtkWidget* window) const
+{
+ gtk_container_add(GTK_CONTAINER(window), widget);
+ gtk_widget_realize(widget);
+ g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
+
+ // FIXME: Perhaps this should only be called for the containing window or parent container.
+ g_signal_connect(widget, "style-set", G_CALLBACK(gtkStyleSetCallback), const_cast<RenderThemeGtk*>(this));
+}
+
+GtkWidget* RenderThemeGtk::gtkContainer() const
+{
+ if (m_gtkContainer)
+ return m_gtkContainer;
+
+ m_gtkWindow = gtk_window_new(GTK_WINDOW_POPUP);
+ gtk_widget_realize(m_gtkWindow);
+ gtk_widget_set_name(m_gtkWindow, "MozillaGtkWidget");
+
+ m_gtkContainer = gtk_fixed_new();
+ setupWidgetAndAddToContainer(m_gtkContainer, m_gtkWindow);
+ return m_gtkContainer;
+}
+
+GtkWidget* RenderThemeGtk::gtkButton() const
+{
+ if (m_gtkButton)
+ return m_gtkButton;
+ m_gtkButton = gtk_button_new();
+ setupWidgetAndAddToContainer(m_gtkButton, gtkContainer());
+ return m_gtkButton;
+}
+
+GtkWidget* RenderThemeGtk::gtkEntry() const
+{
+ if (m_gtkEntry)
+ return m_gtkEntry;
+ m_gtkEntry = gtk_entry_new();
+ setupWidgetAndAddToContainer(m_gtkEntry, gtkContainer());
+ return m_gtkEntry;
+}
+
+GtkWidget* RenderThemeGtk::gtkTreeView() const
+{
+ if (m_gtkTreeView)
+ return m_gtkTreeView;
+ m_gtkTreeView = gtk_tree_view_new();
+ setupWidgetAndAddToContainer(m_gtkTreeView, gtkContainer());
+ return m_gtkTreeView;
+}
+
+GtkWidget* RenderThemeGtk::gtkVScale() const
+{
+ if (m_gtkVScale)
+ return m_gtkVScale;
+ m_gtkVScale = gtk_vscale_new(0);
+ setupWidgetAndAddToContainer(m_gtkVScale, gtkContainer());
+ return m_gtkVScale;
+}
+
+GtkWidget* RenderThemeGtk::gtkHScale() const
+{
+ if (m_gtkHScale)
+ return m_gtkHScale;
+ m_gtkHScale = gtk_hscale_new(0);
+ setupWidgetAndAddToContainer(m_gtkHScale, gtkContainer());
+ return m_gtkHScale;
+}
+
+GtkStyleContext* RenderThemeGtk::gtkScrollbarStyle()
+{
+ return getStyleContext(GTK_TYPE_SCROLLBAR);
+}
+
+} // namespace WebCore
+
+#endif // !GTK_API_VERSION_2
diff --git a/Source/WebCore/platform/gtk/ScrollViewGtk.cpp b/Source/WebCore/platform/gtk/ScrollViewGtk.cpp
new file mode 100644
index 0000000..a8c7562
--- /dev/null
+++ b/Source/WebCore/platform/gtk/ScrollViewGtk.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007, 2009 Holger Hans Peter Freyther
+ * Copyright (C) 2008, 2010 Collabora Ltd.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScrollView.h"
+
+#include "ChromeClient.h"
+#include "FloatRect.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "GtkVersioning.h"
+#include "HostWindow.h"
+#include "IntRect.h"
+#include "MainFrameScrollbarGtk.h"
+#include "Page.h"
+#include "PlatformMouseEvent.h"
+#include "PlatformWheelEvent.h"
+#include "ScrollbarTheme.h"
+
+#include <gtk/gtk.h>
+
+using namespace std;
+
+namespace WebCore {
+
+void ScrollView::platformInit()
+{
+}
+
+void ScrollView::platformDestroy()
+{
+ m_horizontalAdjustment = 0;
+ m_verticalAdjustment = 0;
+}
+
+PassRefPtr<Scrollbar> ScrollView::createScrollbar(ScrollbarOrientation orientation)
+{
+ // If this is an interior frame scrollbar, we want to create a totally fake
+ // scrollbar with no GtkAdjustment backing it.
+ if (parent())
+ return Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
+
+ // If this is the main frame, we want to create a Scrollbar that does no painting
+ // and defers to our GtkAdjustment for all of its state. Note that the GtkAdjustment
+ // may be null here.
+ if (orientation == HorizontalScrollbar)
+ return MainFrameScrollbarGtk::create(this, orientation, m_horizontalAdjustment.get());
+
+ // VerticalScrollbar
+ return MainFrameScrollbarGtk::create(this, orientation, m_verticalAdjustment.get());
+}
+
+void ScrollView::setHorizontalAdjustment(GtkAdjustment* hadj, bool resetValues)
+{
+ ASSERT(!parent() || !hadj);
+ if (parent())
+ return;
+
+ m_horizontalAdjustment = hadj;
+
+ if (!m_horizontalAdjustment) {
+ MainFrameScrollbarGtk* hScrollbar = reinterpret_cast<MainFrameScrollbarGtk*>(horizontalScrollbar());
+ if (hScrollbar)
+ hScrollbar->detachAdjustment();
+
+ return;
+ }
+
+ // We may be lacking scrollbars when returning to a cached
+ // page, this kicks the page to recreate the scrollbars.
+ setHasHorizontalScrollbar(true);
+
+ MainFrameScrollbarGtk* hScrollbar = reinterpret_cast<MainFrameScrollbarGtk*>(horizontalScrollbar());
+ hScrollbar->attachAdjustment(m_horizontalAdjustment.get());
+
+ // We used to reset everything to 0 here, but when page cache
+ // is enabled we reuse FrameViews that are cached. Since their
+ // size is not going to change when being restored, (which is
+ // what would cause the upper limit in the adjusments to be
+ // set in the normal case), we make sure they are up-to-date
+ // here. This is needed for the parent scrolling widget to be
+ // able to report correct values.
+ int horizontalPageStep = max(max<int>(frameRect().width() * Scrollbar::minFractionToStepWhenPaging(), frameRect().width() - Scrollbar::maxOverlapBetweenPages()), 1);
+ gtk_adjustment_configure(m_horizontalAdjustment.get(),
+ resetValues ? 0 : scrollOffset().width(), 0,
+ resetValues ? 0 : contentsSize().width(),
+ resetValues ? 0 : Scrollbar::pixelsPerLineStep(),
+ resetValues ? 0 : horizontalPageStep,
+ resetValues ? 0 : frameRect().width());
+}
+
+void ScrollView::setVerticalAdjustment(GtkAdjustment* vadj, bool resetValues)
+{
+ ASSERT(!parent() || !vadj);
+ if (parent())
+ return;
+
+ m_verticalAdjustment = vadj;
+
+ if (!m_verticalAdjustment) {
+ MainFrameScrollbarGtk* vScrollbar = reinterpret_cast<MainFrameScrollbarGtk*>(verticalScrollbar());
+ if (vScrollbar)
+ vScrollbar->detachAdjustment();
+
+ return;
+ }
+
+ // We may be lacking scrollbars when returning to a cached
+ // page, this kicks the page to recreate the scrollbars.
+ setHasVerticalScrollbar(true);
+
+ MainFrameScrollbarGtk* vScrollbar = reinterpret_cast<MainFrameScrollbarGtk*>(verticalScrollbar());
+ vScrollbar->attachAdjustment(m_verticalAdjustment.get());
+
+ // We used to reset everything to 0 here, but when page cache
+ // is enabled we reuse FrameViews that are cached. Since their
+ // size is not going to change when being restored, (which is
+ // what would cause the upper limit in the adjusments to be
+ // set in the normal case), we make sure they are up-to-date
+ // here. This is needed for the parent scrolling widget to be
+ // able to report correct values.
+ int verticalPageStep = max(max<int>(frameRect().width() * Scrollbar::minFractionToStepWhenPaging(), frameRect().width() - Scrollbar::maxOverlapBetweenPages()), 1);
+ gtk_adjustment_configure(m_verticalAdjustment.get(),
+ resetValues ? 0 : scrollOffset().height(), 0,
+ resetValues ? 0 : contentsSize().height(),
+ resetValues ? 0 : Scrollbar::pixelsPerLineStep(),
+ resetValues ? 0 : verticalPageStep,
+ resetValues ? 0 : frameRect().height());
+}
+
+void ScrollView::setGtkAdjustments(GtkAdjustment* hadj, GtkAdjustment* vadj, bool resetValues)
+{
+ setHorizontalAdjustment(hadj, resetValues);
+ setVerticalAdjustment(vadj, resetValues);
+}
+
+void ScrollView::platformAddChild(Widget* child)
+{
+}
+
+void ScrollView::platformRemoveChild(Widget* child)
+{
+}
+
+IntRect ScrollView::visibleContentRect(bool includeScrollbars) const
+{
+ // If we are an interior frame scrollbar or are in some sort of transition
+ // state, just calculate our size based on what the GTK+ theme says the
+ // scrollbar width should be.
+ if (parent() || !hostWindow() || !hostWindow()->platformPageClient()) {
+ return IntRect(IntPoint(m_scrollOffset.width(), m_scrollOffset.height()),
+ IntSize(max(0, width() - (verticalScrollbar() && !includeScrollbars ? verticalScrollbar()->width() : 0)),
+ max(0, height() - (horizontalScrollbar() && !includeScrollbars ? horizontalScrollbar()->height() : 0))));
+ }
+
+ // We don't have a parent, so we are the main frame and thus have
+ // a parent widget which we can use to measure the visible region.
+ GtkWidget* measuredWidget = hostWindow()->platformPageClient();
+ GtkWidget* parentWidget = gtk_widget_get_parent(measuredWidget);
+
+ // We may not be in a widget that displays scrollbars, but we may
+ // have other kinds of decoration that make us smaller.
+ if (parentWidget && includeScrollbars)
+ measuredWidget = parentWidget;
+
+ GtkAllocation allocation;
+ gtk_widget_get_allocation(measuredWidget, &allocation);
+ return IntRect(IntPoint(m_scrollOffset.width(), m_scrollOffset.height()),
+ IntSize(allocation.width, allocation.height));
+}
+
+void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode, bool horizontalLock, bool verticalLock)
+{
+ // FIXME: Restructure the ScrollView abstraction so that we do not have to
+ // copy this verbatim from ScrollView.cpp. Until then, we should make sure this
+ // is kept in sync.
+ bool needsUpdate = false;
+
+ if (horizontalMode != horizontalScrollbarMode() && !m_horizontalScrollbarLock) {
+ m_horizontalScrollbarMode = horizontalMode;
+ needsUpdate = true;
+ }
+
+ if (verticalMode != verticalScrollbarMode() && !m_verticalScrollbarLock) {
+ m_verticalScrollbarMode = verticalMode;
+ needsUpdate = true;
+ }
+
+ if (horizontalLock)
+ setHorizontalScrollbarLock();
+
+ if (verticalLock)
+ setVerticalScrollbarLock();
+
+ if (needsUpdate)
+ updateScrollbars(scrollOffset());
+
+ // We don't need to report policy changes on ScrollView's unless this
+ // one has an adjustment attached and it is a main frame.
+ if (!m_horizontalAdjustment || parent() || !isFrameView())
+ return;
+
+ // For frames that do have adjustments attached, we want to report
+ // policy changes, so that they may be applied to the widget to
+ // which the WebView's container (e.g. GtkScrolledWindow).
+ if (hostWindow())
+ hostWindow()->scrollbarsModeDidChange();
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/ScrollbarThemeGtk.cpp b/Source/WebCore/platform/gtk/ScrollbarThemeGtk.cpp
new file mode 100644
index 0000000..cb9b0f8
--- /dev/null
+++ b/Source/WebCore/platform/gtk/ScrollbarThemeGtk.cpp
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScrollbarThemeGtk.h"
+
+#include "PlatformMouseEvent.h"
+#include "RenderThemeGtk.h"
+#include "ScrollView.h"
+#include "Scrollbar.h"
+
+namespace WebCore {
+
+static HashSet<Scrollbar*>* gScrollbars;
+
+ScrollbarTheme* ScrollbarTheme::nativeTheme()
+{
+ static ScrollbarThemeGtk theme;
+ return &theme;
+}
+
+ScrollbarThemeGtk::~ScrollbarThemeGtk()
+{
+}
+
+void ScrollbarThemeGtk::registerScrollbar(Scrollbar* scrollbar)
+{
+ if (!gScrollbars)
+ gScrollbars = new HashSet<Scrollbar*>;
+ gScrollbars->add(scrollbar);
+}
+
+void ScrollbarThemeGtk::unregisterScrollbar(Scrollbar* scrollbar)
+{
+ gScrollbars->remove(scrollbar);
+ if (gScrollbars->isEmpty()) {
+ delete gScrollbars;
+ gScrollbars = 0;
+ }
+}
+
+void ScrollbarThemeGtk::updateScrollbarsFrameThickness()
+{
+ if (!gScrollbars)
+ return;
+
+ // Update the thickness of every interior frame scrollbar widget. The
+ // platform-independent scrollbar them code isn't yet smart enough to get
+ // this information when it paints.
+ HashSet<Scrollbar*>::iterator end = gScrollbars->end();
+ for (HashSet<Scrollbar*>::iterator it = gScrollbars->begin(); it != end; ++it) {
+ Scrollbar* scrollbar = (*it);
+
+ // Top-level scrollbar i.e. scrollbars who have a parent ScrollView
+ // with no parent are native, and thus do not need to be resized.
+ if (!scrollbar->parent() || !scrollbar->parent()->parent())
+ return;
+
+ int thickness = scrollbarThickness(scrollbar->controlSize());
+ if (scrollbar->orientation() == HorizontalScrollbar)
+ scrollbar->setFrameRect(IntRect(0, scrollbar->parent()->height() - thickness, scrollbar->width(), thickness));
+ else
+ scrollbar->setFrameRect(IntRect(scrollbar->parent()->width() - thickness, 0, thickness, scrollbar->height()));
+ }
+}
+
+bool ScrollbarThemeGtk::hasThumb(Scrollbar* scrollbar)
+{
+ // This method is just called as a paint-time optimization to see if
+ // painting the thumb can be skipped. We don't have to be exact here.
+ return thumbLength(scrollbar) > 0;
+}
+
+IntRect ScrollbarThemeGtk::backButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool)
+{
+ if (part == BackButtonEndPart && !m_hasBackButtonEndPart)
+ return IntRect();
+
+ int x = scrollbar->x() + m_troughBorderWidth;
+ int y = scrollbar->y() + m_troughBorderWidth;
+ IntSize size = buttonSize(scrollbar);
+ if (part == BackButtonStartPart)
+ return IntRect(x, y, size.width(), size.height());
+
+ // BackButtonEndPart (alternate button)
+ if (scrollbar->orientation() == HorizontalScrollbar)
+ return IntRect(scrollbar->x() + scrollbar->width() - m_troughBorderWidth - (2 * size.width()), y, size.width(), size.height());
+
+ // VerticalScrollbar alternate button
+ return IntRect(x, scrollbar->y() + scrollbar->height() - m_troughBorderWidth - (2 * size.height()), size.width(), size.height());
+}
+
+IntRect ScrollbarThemeGtk::forwardButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool)
+{
+ if (part == ForwardButtonStartPart && !m_hasForwardButtonStartPart)
+ return IntRect();
+
+ IntSize size = buttonSize(scrollbar);
+ if (scrollbar->orientation() == HorizontalScrollbar) {
+ int y = scrollbar->y() + m_troughBorderWidth;
+ if (part == ForwardButtonEndPart)
+ return IntRect(scrollbar->x() + scrollbar->width() - size.width() - m_troughBorderWidth, y, size.width(), size.height());
+
+ // ForwardButtonStartPart (alternate button)
+ return IntRect(scrollbar->x() + m_troughBorderWidth + size.width(), y, size.width(), size.height());
+ }
+
+ // VerticalScrollbar
+ int x = scrollbar->x() + m_troughBorderWidth;
+ if (part == ForwardButtonEndPart)
+ return IntRect(x, scrollbar->y() + scrollbar->height() - size.height() - m_troughBorderWidth, size.width(), size.height());
+
+ // ForwardButtonStartPart (alternate button)
+ return IntRect(x, scrollbar->y() + m_troughBorderWidth + size.height(), size.width(), size.height());
+}
+
+IntRect ScrollbarThemeGtk::trackRect(Scrollbar* scrollbar, bool)
+{
+ // The padding along the thumb movement axis (from outside to in)
+ // is the size of trough border plus the size of the stepper (button)
+ // plus the size of stepper spacing (the space between the stepper and
+ // the place where the thumb stops). There is often no stepper spacing.
+ int movementAxisPadding = m_troughBorderWidth + m_stepperSize + m_stepperSpacing;
+
+ // The fatness of the scrollbar on the non-movement axis.
+ int thickness = scrollbarThickness(scrollbar->controlSize());
+
+ int alternateButtonOffset = 0;
+ int alternateButtonWidth = 0;
+ if (m_hasForwardButtonStartPart) {
+ alternateButtonOffset += m_stepperSize;
+ alternateButtonWidth += m_stepperSize;
+ }
+ if (m_hasBackButtonEndPart)
+ alternateButtonWidth += m_stepperSize;
+
+ if (scrollbar->orientation() == HorizontalScrollbar) {
+ // Once the scrollbar becomes smaller than the natural size of the
+ // two buttons, the track disappears.
+ if (scrollbar->width() < 2 * thickness)
+ return IntRect();
+ return IntRect(scrollbar->x() + movementAxisPadding + alternateButtonOffset, scrollbar->y(),
+ scrollbar->width() - (2 * movementAxisPadding) - alternateButtonWidth, thickness);
+ }
+
+ if (scrollbar->height() < 2 * thickness)
+ return IntRect();
+ return IntRect(scrollbar->x(), scrollbar->y() + movementAxisPadding + alternateButtonOffset,
+ thickness, scrollbar->height() - (2 * movementAxisPadding) - alternateButtonWidth);
+}
+
+IntRect ScrollbarThemeGtk::thumbRect(Scrollbar* scrollbar, const IntRect& unconstrainedTrackRect)
+{
+ IntRect trackRect = constrainTrackRectToTrackPieces(scrollbar, unconstrainedTrackRect);
+ int thumbPos = thumbPosition(scrollbar);
+ if (scrollbar->orientation() == HorizontalScrollbar)
+ return IntRect(trackRect.x() + thumbPos, trackRect.y() + (trackRect.height() - m_thumbFatness) / 2, thumbLength(scrollbar), m_thumbFatness);
+
+ // VerticalScrollbar
+ return IntRect(trackRect.x() + (trackRect.width() - m_thumbFatness) / 2, trackRect.y() + thumbPos, m_thumbFatness, thumbLength(scrollbar));
+}
+
+bool ScrollbarThemeGtk::paint(Scrollbar* scrollbar, GraphicsContext* graphicsContext, const IntRect& damageRect)
+{
+ if (graphicsContext->paintingDisabled())
+ return false;
+
+ // Create the ScrollbarControlPartMask based on the damageRect
+ ScrollbarControlPartMask scrollMask = NoPart;
+
+ IntRect backButtonStartPaintRect;
+ IntRect backButtonEndPaintRect;
+ IntRect forwardButtonStartPaintRect;
+ IntRect forwardButtonEndPaintRect;
+ if (hasButtons(scrollbar)) {
+ backButtonStartPaintRect = backButtonRect(scrollbar, BackButtonStartPart, true);
+ if (damageRect.intersects(backButtonStartPaintRect))
+ scrollMask |= BackButtonStartPart;
+ backButtonEndPaintRect = backButtonRect(scrollbar, BackButtonEndPart, true);
+ if (damageRect.intersects(backButtonEndPaintRect))
+ scrollMask |= BackButtonEndPart;
+ forwardButtonStartPaintRect = forwardButtonRect(scrollbar, ForwardButtonStartPart, true);
+ if (damageRect.intersects(forwardButtonStartPaintRect))
+ scrollMask |= ForwardButtonStartPart;
+ forwardButtonEndPaintRect = forwardButtonRect(scrollbar, ForwardButtonEndPart, true);
+ if (damageRect.intersects(forwardButtonEndPaintRect))
+ scrollMask |= ForwardButtonEndPart;
+ }
+
+ IntRect trackPaintRect = trackRect(scrollbar, true);
+ if (damageRect.intersects(trackPaintRect))
+ scrollMask |= TrackBGPart;
+
+ if (m_troughUnderSteppers && (scrollMask & BackButtonStartPart
+ || scrollMask & BackButtonEndPart
+ || scrollMask & ForwardButtonStartPart
+ || scrollMask & ForwardButtonEndPart))
+ scrollMask |= TrackBGPart;
+
+ bool thumbPresent = hasThumb(scrollbar);
+ IntRect currentThumbRect;
+ if (thumbPresent) {
+ IntRect track = trackRect(scrollbar, false);
+ currentThumbRect = thumbRect(scrollbar, track);
+ if (damageRect.intersects(currentThumbRect))
+ scrollMask |= ThumbPart;
+ }
+
+ paintScrollbarBackground(graphicsContext, scrollbar);
+
+ if (scrollMask & TrackBGPart)
+ paintTrackBackground(graphicsContext, scrollbar, trackPaintRect);
+
+ // Paint the back and forward buttons.
+ if (scrollMask & BackButtonStartPart)
+ paintButton(graphicsContext, scrollbar, backButtonStartPaintRect, BackButtonStartPart);
+ if (scrollMask & BackButtonEndPart)
+ paintButton(graphicsContext, scrollbar, backButtonEndPaintRect, BackButtonEndPart);
+ if (scrollMask & ForwardButtonStartPart)
+ paintButton(graphicsContext, scrollbar, forwardButtonStartPaintRect, ForwardButtonStartPart);
+ if (scrollMask & ForwardButtonEndPart)
+ paintButton(graphicsContext, scrollbar, forwardButtonEndPaintRect, ForwardButtonEndPart);
+
+ // Paint the thumb.
+ if (scrollMask & ThumbPart)
+ paintThumb(graphicsContext, scrollbar, currentThumbRect);
+
+ return true;
+}
+
+void ScrollbarThemeGtk::paintScrollCorner(ScrollView* view, GraphicsContext* context, const IntRect& cornerRect)
+{
+ // ScrollbarThemeComposite::paintScrollCorner incorrectly assumes that the
+ // ScrollView is a FrameView (see FramelessScrollView), so we cannot let
+ // that code run. For FrameView's this is correct since we don't do custom
+ // scrollbar corner rendering, which ScrollbarThemeComposite supports.
+ ScrollbarTheme::paintScrollCorner(view, context, cornerRect);
+}
+
+bool ScrollbarThemeGtk::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& event)
+{
+ return (event.shiftKey() && event.button() == LeftButton) || (event.button() == MiddleButton);
+}
+
+int ScrollbarThemeGtk::scrollbarThickness(ScrollbarControlSize)
+{
+ return m_thumbFatness + (m_troughBorderWidth * 2);
+}
+
+IntSize ScrollbarThemeGtk::buttonSize(Scrollbar* scrollbar)
+{
+ if (scrollbar->orientation() == VerticalScrollbar)
+ return IntSize(m_thumbFatness, m_stepperSize);
+
+ // HorizontalScrollbar
+ return IntSize(m_stepperSize, m_thumbFatness);
+}
+
+int ScrollbarThemeGtk::minimumThumbLength(Scrollbar* scrollbar)
+{
+ return m_minThumbLength;
+}
+
+}
+
diff --git a/Source/WebCore/platform/gtk/ScrollbarThemeGtk.h b/Source/WebCore/platform/gtk/ScrollbarThemeGtk.h
new file mode 100644
index 0000000..207ec1f
--- /dev/null
+++ b/Source/WebCore/platform/gtk/ScrollbarThemeGtk.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ScrollbarThemeGtk_h
+#define ScrollbarThemeGtk_h
+
+#include "ScrollbarThemeComposite.h"
+
+namespace WebCore {
+
+class Scrollbar;
+
+class ScrollbarThemeGtk : public ScrollbarThemeComposite {
+public:
+ ScrollbarThemeGtk();
+ virtual ~ScrollbarThemeGtk();
+
+ virtual bool hasButtons(Scrollbar*) { return true; }
+ virtual bool hasThumb(Scrollbar*);
+ virtual IntRect backButtonRect(Scrollbar*, ScrollbarPart, bool);
+ virtual IntRect forwardButtonRect(Scrollbar*, ScrollbarPart, bool);
+ virtual IntRect trackRect(Scrollbar*, bool);
+ IntRect thumbRect(Scrollbar*, const IntRect& unconstrainedTrackRect);
+ bool paint(Scrollbar*, GraphicsContext*, const IntRect& damageRect);
+ void paintScrollbarBackground(GraphicsContext*, Scrollbar*);
+ void paintTrackBackground(GraphicsContext*, Scrollbar*, const IntRect&);
+ void paintThumb(GraphicsContext*, Scrollbar*, const IntRect&);
+ virtual void paintButton(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart);
+ virtual void paintScrollCorner(ScrollView*, GraphicsContext*, const IntRect&);
+ virtual bool shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent&);
+ virtual int scrollbarThickness(ScrollbarControlSize);
+ virtual IntSize buttonSize(Scrollbar*);
+ virtual int minimumThumbLength(Scrollbar*);
+
+ // TODO: These are the default GTK+ values. At some point we should pull these from the theme itself.
+ virtual double initialAutoscrollTimerDelay() { return 0.20; }
+ virtual double autoscrollTimerDelay() { return 0.02; }
+ void updateThemeProperties();
+ void updateScrollbarsFrameThickness();
+ void registerScrollbar(Scrollbar*);
+ void unregisterScrollbar(Scrollbar*);
+
+protected:
+#ifndef GTK_API_VERSION_2
+ GtkStyleContext* m_context;
+#endif
+ int m_thumbFatness;
+ int m_troughBorderWidth;
+ int m_stepperSize;
+ int m_stepperSpacing;
+ int m_minThumbLength;
+ gboolean m_troughUnderSteppers;
+ gboolean m_hasForwardButtonStartPart;
+ gboolean m_hasBackButtonEndPart;
+};
+
+}
+#endif
diff --git a/Source/WebCore/platform/gtk/ScrollbarThemeGtk2.cpp b/Source/WebCore/platform/gtk/ScrollbarThemeGtk2.cpp
new file mode 100644
index 0000000..79295c1
--- /dev/null
+++ b/Source/WebCore/platform/gtk/ScrollbarThemeGtk2.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScrollbarThemeGtk.h"
+
+#ifdef GTK_API_VERSION_2
+
+#include "PlatformMouseEvent.h"
+#include "RenderThemeGtk.h"
+#include "ScrollView.h"
+#include "Scrollbar.h"
+#include "WidgetRenderingContext.h"
+#include "gtkdrawing.h"
+#include <gtk/gtk.h>
+
+namespace WebCore {
+
+static void gtkStyleSetCallback(GtkWidget* widget, GtkStyle* previous, ScrollbarThemeGtk* scrollbarTheme)
+{
+ scrollbarTheme->updateThemeProperties();
+}
+
+ScrollbarThemeGtk::ScrollbarThemeGtk()
+{
+ updateThemeProperties();
+ g_signal_connect(static_cast<RenderThemeGtk*>(RenderTheme::defaultTheme().get())->gtkScrollbar(),
+ "style-set", G_CALLBACK(gtkStyleSetCallback), this);
+}
+
+void ScrollbarThemeGtk::updateThemeProperties()
+{
+ MozGtkScrollbarMetrics metrics;
+ moz_gtk_get_scrollbar_metrics(&metrics);
+
+ m_thumbFatness = metrics.slider_width;
+ m_troughBorderWidth = metrics.trough_border;
+ m_stepperSize = metrics.stepper_size;
+ m_stepperSpacing = metrics.stepper_spacing;
+ m_minThumbLength = metrics.min_slider_size;
+ m_troughUnderSteppers = metrics.trough_under_steppers;
+ m_hasForwardButtonStartPart = metrics.has_secondary_forward_stepper;
+ m_hasBackButtonEndPart = metrics.has_secondary_backward_stepper;
+
+ updateScrollbarsFrameThickness();
+}
+
+void ScrollbarThemeGtk::paintTrackBackground(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect)
+{
+ GtkWidgetState state;
+ state.focused = FALSE;
+ state.isDefault = FALSE;
+ state.canDefault = FALSE;
+ state.disabled = FALSE;
+ state.active = FALSE;
+ state.inHover = FALSE;
+
+ // Paint the track background. If the trough-under-steppers property is true, this
+ // should be the full size of the scrollbar, but if is false, it should only be the
+ // track rect.
+ IntRect fullScrollbarRect = rect;
+ if (m_troughUnderSteppers)
+ fullScrollbarRect = IntRect(scrollbar->x(), scrollbar->y(), scrollbar->width(), scrollbar->height());
+
+ GtkThemeWidgetType type = scrollbar->orientation() == VerticalScrollbar ? MOZ_GTK_SCROLLBAR_TRACK_VERTICAL : MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL;
+ WidgetRenderingContext widgetContext(context, fullScrollbarRect);
+ widgetContext.paintMozillaWidget(type, &state, 0);
+}
+
+void ScrollbarThemeGtk::paintScrollbarBackground(GraphicsContext* context, Scrollbar* scrollbar)
+{
+ // This is unused by the moz_gtk_scrollecd_window_paint.
+ GtkWidgetState state;
+ IntRect fullScrollbarRect = IntRect(scrollbar->x(), scrollbar->y(), scrollbar->width(), scrollbar->height());
+ WidgetRenderingContext widgetContext(context, fullScrollbarRect);
+ widgetContext.paintMozillaWidget(MOZ_GTK_SCROLLED_WINDOW, &state, 0);
+}
+
+void ScrollbarThemeGtk::paintThumb(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect)
+{
+ GtkWidgetState state;
+ state.focused = FALSE;
+ state.isDefault = FALSE;
+ state.canDefault = FALSE;
+ state.disabled = FALSE;
+ state.active = scrollbar->pressedPart() == ThumbPart;
+ state.inHover = scrollbar->hoveredPart() == ThumbPart;
+ state.maxpos = scrollbar->maximum();
+ state.curpos = scrollbar->currentPos();
+
+ GtkThemeWidgetType type = scrollbar->orientation() == VerticalScrollbar ? MOZ_GTK_SCROLLBAR_THUMB_VERTICAL : MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL;
+ WidgetRenderingContext widgetContext(context, rect);
+ widgetContext.paintMozillaWidget(type, &state, 0);
+}
+
+void ScrollbarThemeGtk::paintButton(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part)
+{
+ int flags = 0;
+ if (scrollbar->orientation() == VerticalScrollbar)
+ flags |= MOZ_GTK_STEPPER_VERTICAL;
+
+ if (part == ForwardButtonEndPart)
+ flags |= (MOZ_GTK_STEPPER_DOWN | MOZ_GTK_STEPPER_BOTTOM);
+ if (part == ForwardButtonStartPart)
+ flags |= MOZ_GTK_STEPPER_DOWN;
+
+ GtkWidgetState state;
+ state.focused = TRUE;
+ state.isDefault = TRUE;
+ state.canDefault = TRUE;
+ state.depressed = FALSE;
+
+ if ((BackButtonStartPart == part && scrollbar->currentPos())
+ || (BackButtonEndPart == part && scrollbar->currentPos())
+ || (ForwardButtonEndPart == part && scrollbar->currentPos() != scrollbar->maximum())
+ || (ForwardButtonStartPart == part && scrollbar->currentPos() != scrollbar->maximum())) {
+ state.disabled = FALSE;
+ state.active = part == scrollbar->pressedPart();
+ state.inHover = part == scrollbar->hoveredPart();
+ } else {
+ state.disabled = TRUE;
+ state.active = FALSE;
+ state.inHover = FALSE;
+ }
+
+ WidgetRenderingContext widgetContext(context, rect);
+ widgetContext.paintMozillaWidget(MOZ_GTK_SCROLLBAR_BUTTON, &state, flags);
+}
+
+} // namespace WebCore
+
+#endif // GTK_API_VERSION_2
diff --git a/Source/WebCore/platform/gtk/ScrollbarThemeGtk3.cpp b/Source/WebCore/platform/gtk/ScrollbarThemeGtk3.cpp
new file mode 100644
index 0000000..d000063
--- /dev/null
+++ b/Source/WebCore/platform/gtk/ScrollbarThemeGtk3.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScrollbarThemeGtk.h"
+
+#ifndef GTK_API_VERSION_2
+
+#include "PlatformMouseEvent.h"
+#include "RenderThemeGtk.h"
+#include "ScrollView.h"
+#include "Scrollbar.h"
+#include <gtk/gtk.h>
+
+namespace WebCore {
+
+static void gtkStyleChangedCallback(GtkWidget*, ScrollbarThemeGtk* scrollbarTheme)
+{
+ scrollbarTheme->updateThemeProperties();
+}
+
+ScrollbarThemeGtk::ScrollbarThemeGtk()
+ : m_context(static_cast<RenderThemeGtk*>(RenderTheme::defaultTheme().get())->gtkScrollbarStyle())
+{
+ updateThemeProperties();
+ g_signal_connect(m_context, "changed", G_CALLBACK(gtkStyleChangedCallback), this);
+}
+
+void ScrollbarThemeGtk::updateThemeProperties()
+{
+ gtk_style_context_get_style(m_context,
+ "min-slider-length", &m_minThumbLength,
+ "slider-width", &m_thumbFatness,
+ "trough-border", &m_troughBorderWidth,
+ "stepper-size", &m_stepperSize,
+ "stepper-spacing", &m_stepperSpacing,
+ "trough-under-steppers", &m_troughUnderSteppers,
+ "has-secondary-backward-stepper", &m_hasBackButtonEndPart,
+ "has-secondary-forward-stepper", &m_hasForwardButtonStartPart,
+ NULL);
+ updateScrollbarsFrameThickness();
+}
+
+void ScrollbarThemeGtk::paintTrackBackground(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect)
+{
+ // Paint the track background. If the trough-under-steppers property is true, this
+ // should be the full size of the scrollbar, but if is false, it should only be the
+ // track rect.
+ IntRect fullScrollbarRect(rect);
+ if (m_troughUnderSteppers)
+ fullScrollbarRect = IntRect(scrollbar->x(), scrollbar->y(), scrollbar->width(), scrollbar->height());
+
+ gtk_style_context_save(m_context);
+
+ gtk_style_context_add_class(m_context, GTK_STYLE_CLASS_SCROLLBAR);
+ gtk_style_context_add_class(m_context, GTK_STYLE_CLASS_TROUGH);
+
+ gtk_render_background(m_context, context->platformContext(),
+ fullScrollbarRect.x(), fullScrollbarRect.y(), fullScrollbarRect.width(), fullScrollbarRect.height());
+ gtk_render_frame(m_context, context->platformContext(),
+ fullScrollbarRect.x(), fullScrollbarRect.y(), fullScrollbarRect.width(), fullScrollbarRect.height());
+
+ gtk_style_context_restore(m_context);
+}
+
+void ScrollbarThemeGtk::paintScrollbarBackground(GraphicsContext* context, Scrollbar* scrollbar)
+{
+ gtk_style_context_save(m_context);
+
+ gtk_style_context_add_class(m_context, GTK_STYLE_CLASS_SCROLLBAR);
+ gtk_style_context_add_class(m_context, "scrolled-window");
+ gtk_render_frame(m_context, context->platformContext(), scrollbar->x(), scrollbar->y(), scrollbar->width(), scrollbar->height());
+
+ gtk_style_context_restore(m_context);
+}
+
+void ScrollbarThemeGtk::paintThumb(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect)
+{
+ gtk_style_context_save(m_context);
+
+ gtk_style_context_add_class(m_context, GTK_STYLE_CLASS_SCROLLBAR);
+ gtk_style_context_add_class(m_context, GTK_STYLE_CLASS_SLIDER);
+
+ guint flags = 0;
+ if (scrollbar->pressedPart() == ThumbPart)
+ flags |= GTK_STATE_FLAG_ACTIVE;
+ if (scrollbar->hoveredPart() == ThumbPart)
+ flags |= GTK_STATE_FLAG_PRELIGHT;
+ gtk_style_context_set_state(m_context, static_cast<GtkStateFlags>(flags));
+
+ gtk_render_slider(m_context, context->platformContext(), rect.x(), rect.y(), rect.width(), rect.height(),
+ scrollbar->orientation() == VerticalScrollbar ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL);
+
+ gtk_style_context_restore(m_context);
+}
+
+void ScrollbarThemeGtk::paintButton(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part)
+{
+ gtk_style_context_save(m_context);
+
+ gtk_style_context_add_class(m_context, GTK_STYLE_CLASS_SCROLLBAR);
+
+ guint flags = 0;
+ if ((BackButtonStartPart == part && scrollbar->currentPos())
+ || (BackButtonEndPart == part && scrollbar->currentPos())
+ || (ForwardButtonEndPart == part && scrollbar->currentPos() != scrollbar->maximum())
+ || (ForwardButtonStartPart == part && scrollbar->currentPos() != scrollbar->maximum())) {
+ if (part == scrollbar->pressedPart())
+ flags |= GTK_STATE_FLAG_ACTIVE;
+ if (part == scrollbar->hoveredPart())
+ flags |= GTK_STATE_FLAG_PRELIGHT;
+ } else
+ flags |= GTK_STATE_FLAG_INSENSITIVE;
+ gtk_style_context_set_state(m_context, static_cast<GtkStateFlags>(flags));
+
+ guint sides = gtk_style_context_get_junction_sides(m_context);
+ if (scrollbar->orientation() == VerticalScrollbar)
+ sides &= ~(GTK_JUNCTION_TOP | GTK_JUNCTION_BOTTOM);
+ else
+ sides &= ~(GTK_JUNCTION_LEFT | GTK_JUNCTION_RIGHT);
+
+ switch (part) {
+ case BackButtonStartPart:
+ sides |= (scrollbar->orientation() == VerticalScrollbar) ? GTK_JUNCTION_BOTTOM : GTK_JUNCTION_RIGHT;
+ break;
+ case BackButtonEndPart:
+ case ForwardButtonEndPart:
+ sides |= (scrollbar->orientation() == VerticalScrollbar) ?
+ GTK_JUNCTION_TOP | GTK_JUNCTION_BOTTOM : GTK_JUNCTION_RIGHT | GTK_JUNCTION_LEFT;
+ break;
+ case ForwardButtonStartPart:
+ sides |= (scrollbar->orientation() == VerticalScrollbar) ? GTK_JUNCTION_TOP : GTK_JUNCTION_LEFT;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ gtk_style_context_set_junction_sides(m_context, static_cast<GtkJunctionSides>(sides));
+ gtk_style_context_add_class(m_context, GTK_STYLE_CLASS_BUTTON);
+
+ gtk_render_background(m_context, context->platformContext(), rect.x(), rect.y(), rect.width(), rect.height());
+ gtk_render_frame(m_context, context->platformContext(), rect.x(), rect.y(), rect.width(), rect.height());
+
+ gfloat arrowScaling;
+ gtk_style_context_get_style(m_context, "arrow-scaling", &arrowScaling, NULL);
+
+ IntSize arrowSize = rect.size();
+ arrowSize.scale(arrowScaling);
+ IntPoint arrowPoint(rect.x() + (rect.width() - arrowSize.width()) / 2,
+ rect.y() + (rect.height() - arrowSize.height()) / 2);
+
+ if (flags & GTK_STATE_FLAG_ACTIVE) {
+ gint arrowDisplacementX, arrowDisplacementY;
+ gtk_style_context_get_style(m_context,
+ "arrow-displacement-x", &arrowDisplacementX,
+ "arrow-displacement-y", &arrowDisplacementY,
+ NULL);
+ arrowPoint.move(arrowDisplacementX, arrowDisplacementY);
+ }
+
+ gdouble angle, size;
+ if (scrollbar->orientation() == VerticalScrollbar) {
+ size = arrowSize.width();
+ angle = (part == ForwardButtonEndPart || part == ForwardButtonStartPart) ? G_PI : 0;
+ } else {
+ size = arrowSize.height();
+ angle = (part == ForwardButtonEndPart || part == ForwardButtonStartPart) ? G_PI / 2 : 3 * (G_PI / 2);
+ }
+
+ gtk_render_arrow(m_context, context->platformContext(), angle, arrowPoint.x(), arrowPoint.y(), size);
+
+ gtk_style_context_restore(m_context);
+}
+
+} // namespace WebCore
+
+#endif // !GTK_API_VERSION_2
diff --git a/Source/WebCore/platform/gtk/SearchPopupMenuGtk.cpp b/Source/WebCore/platform/gtk/SearchPopupMenuGtk.cpp
new file mode 100644
index 0000000..2413773
--- /dev/null
+++ b/Source/WebCore/platform/gtk/SearchPopupMenuGtk.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * 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 "SearchPopupMenuGtk.h"
+
+#include "NotImplemented.h"
+
+namespace WebCore {
+
+SearchPopupMenuGtk::SearchPopupMenuGtk(PopupMenuClient* client)
+ : m_popup(adoptRef(new PopupMenuGtk(client)))
+{
+ notImplemented();
+}
+
+PopupMenu* SearchPopupMenuGtk::popupMenu()
+{
+ return m_popup.get();
+}
+
+void SearchPopupMenuGtk::saveRecentSearches(const AtomicString&, const Vector<String>&)
+{
+ notImplemented();
+}
+
+void SearchPopupMenuGtk::loadRecentSearches(const AtomicString&, Vector<String>&)
+{
+ notImplemented();
+}
+
+bool SearchPopupMenuGtk::enabled()
+{
+ notImplemented();
+ return false;
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/SearchPopupMenuGtk.h b/Source/WebCore/platform/gtk/SearchPopupMenuGtk.h
new file mode 100644
index 0000000..453c63d
--- /dev/null
+++ b/Source/WebCore/platform/gtk/SearchPopupMenuGtk.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SearchPopupMenuGtk_h
+#define SearchPopupMenuGtk_h
+
+#include "PopupMenuGtk.h"
+#include "SearchPopupMenu.h"
+
+namespace WebCore {
+
+class SearchPopupMenuGtk : public SearchPopupMenu {
+public:
+ SearchPopupMenuGtk(PopupMenuClient*);
+
+ virtual PopupMenu* popupMenu();
+ virtual void saveRecentSearches(const AtomicString& name, const Vector<String>& searchItems);
+ virtual void loadRecentSearches(const AtomicString& name, Vector<String>& searchItems);
+ virtual bool enabled();
+
+private:
+ RefPtr<PopupMenuGtk> m_popup;
+};
+
+}
+
+#endif // SearchPopupMenuGtk_h
diff --git a/Source/WebCore/platform/gtk/SharedBufferGtk.cpp b/Source/WebCore/platform/gtk/SharedBufferGtk.cpp
new file mode 100644
index 0000000..c7040f2
--- /dev/null
+++ b/Source/WebCore/platform/gtk/SharedBufferGtk.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * 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 "SharedBuffer.h"
+
+#include "FileSystem.h"
+#include <wtf/text/CString.h>
+
+#include <glib.h>
+
+
+namespace WebCore {
+
+PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String& filePath)
+{
+ if (filePath.isEmpty())
+ return 0;
+
+ CString filename = fileSystemRepresentation(filePath);
+ gchar* contents;
+ gsize size;
+ GError* error = 0;
+ if (!g_file_get_contents(filename.data(), &contents, &size, &error)) {
+ LOG_ERROR("Failed to fully read contents of file %s - %s", filenameForDisplay(filePath).utf8().data(), error->message);
+ g_error_free(error);
+ return 0;
+ }
+
+ RefPtr<SharedBuffer> result = SharedBuffer::create(contents, size);
+ g_free(contents);
+
+ return result.release();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/gtk/SharedTimerGtk.cpp b/Source/WebCore/platform/gtk/SharedTimerGtk.cpp
new file mode 100644
index 0000000..ee4d75b
--- /dev/null
+++ b/Source/WebCore/platform/gtk/SharedTimerGtk.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SharedTimer.h"
+
+#include <wtf/Assertions.h>
+#include <wtf/CurrentTime.h>
+#include <gdk/gdk.h>
+#include <glib.h>
+
+namespace WebCore {
+
+static guint sharedTimer;
+static void (*sharedTimerFiredFunction)();
+
+void setSharedTimerFiredFunction(void (*f)())
+{
+ sharedTimerFiredFunction = f;
+}
+
+static gboolean timeout_cb(gpointer)
+{
+ if (sharedTimerFiredFunction)
+ sharedTimerFiredFunction();
+ return FALSE;
+}
+
+void setSharedTimerFireTime(double fireTime)
+{
+ ASSERT(sharedTimerFiredFunction);
+
+ double interval = fireTime - currentTime();
+ guint intervalInMS;
+ if (interval < 0)
+ intervalInMS = 0;
+ else {
+ interval *= 1000;
+ intervalInMS = (guint)interval;
+ }
+
+ stopSharedTimer();
+ sharedTimer = g_timeout_add_full(GDK_PRIORITY_REDRAW, intervalInMS, timeout_cb, 0, 0);
+}
+
+void stopSharedTimer()
+{
+ gboolean s = FALSE;
+ if (sharedTimer == 0)
+ return;
+
+ s = g_source_remove(sharedTimer);
+ ASSERT(s);
+ sharedTimer = 0;
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/SoundGtk.cpp b/Source/WebCore/platform/gtk/SoundGtk.cpp
new file mode 100644
index 0000000..2f7316c
--- /dev/null
+++ b/Source/WebCore/platform/gtk/SoundGtk.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "Sound.h"
+
+#include <gdk/gdk.h>
+
+namespace WebCore {
+
+void systemBeep()
+{
+ gdk_beep();
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/gtk/TemporaryLinkStubs.cpp b/Source/WebCore/platform/gtk/TemporaryLinkStubs.cpp
new file mode 100644
index 0000000..5c27080
--- /dev/null
+++ b/Source/WebCore/platform/gtk/TemporaryLinkStubs.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "AXObjectCache.h"
+#include "CookieStorage.h"
+#include "DNS.h"
+#include "Editor.h"
+#include "FrameView.h"
+#include "FTPDirectoryDocument.h"
+#include "NotImplemented.h"
+#include "PluginView.h"
+#include <float.h>
+
+using namespace WebCore;
+
+/********************************************************/
+/* Completely empty stubs (mostly to allow DRT to run): */
+/********************************************************/
+
+namespace WebCore {
+void getSupportedKeySizes(Vector<String>&) { notImplemented(); }
+String signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String &challengeString, const KURL &url) { return String(); }
+float userIdleTime() { notImplemented(); return FLT_MAX; } // return an arbitrarily high userIdleTime so that releasing pages from the page cache isn't postponed
+void setCookieStoragePrivateBrowsingEnabled(bool) { notImplemented(); }
+
+}
diff --git a/Source/WebCore/platform/gtk/WheelEventGtk.cpp b/Source/WebCore/platform/gtk/WheelEventGtk.cpp
new file mode 100644
index 0000000..fc6206f
--- /dev/null
+++ b/Source/WebCore/platform/gtk/WheelEventGtk.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PlatformWheelEvent.h"
+#include "Scrollbar.h"
+
+#include <gdk/gdk.h>
+
+namespace WebCore {
+
+// Keep this in sync with the other platform event constructors
+PlatformWheelEvent::PlatformWheelEvent(GdkEventScroll* event)
+{
+ static const float delta = 1;
+
+ m_deltaX = 0;
+ m_deltaY = 0;
+
+ // Docs say an upwards scroll (away from the user) has a positive delta
+ switch (event->direction) {
+ case GDK_SCROLL_UP:
+ m_deltaY = delta;
+ break;
+ case GDK_SCROLL_DOWN:
+ m_deltaY = -delta;
+ break;
+ case GDK_SCROLL_LEFT:
+ m_deltaX = delta;
+ break;
+ case GDK_SCROLL_RIGHT:
+ m_deltaX = -delta;
+ break;
+ }
+ m_wheelTicksX = m_deltaX;
+ m_wheelTicksY = m_deltaY;
+
+ m_position = IntPoint(static_cast<int>(event->x), static_cast<int>(event->y));
+ m_globalPosition = IntPoint(static_cast<int>(event->x_root), static_cast<int>(event->y_root));
+ m_granularity = ScrollByPixelWheelEvent;
+ m_isAccepted = false;
+ m_shiftKey = event->state & GDK_SHIFT_MASK;
+ m_ctrlKey = event->state & GDK_CONTROL_MASK;
+ m_altKey = event->state & GDK_MOD1_MASK;
+ m_metaKey = event->state & GDK_META_MASK;
+
+ // FIXME: retrieve the user setting for the number of lines to scroll on each wheel event
+ m_deltaX *= static_cast<float>(Scrollbar::pixelsPerLineStep());
+ m_deltaY *= static_cast<float>(Scrollbar::pixelsPerLineStep());
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/WidgetGtk.cpp b/Source/WebCore/platform/gtk/WidgetGtk.cpp
new file mode 100644
index 0000000..ee1005c
--- /dev/null
+++ b/Source/WebCore/platform/gtk/WidgetGtk.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007, 2009 Holger Hans Peter Freyther
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Widget.h"
+
+#include "Cursor.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "GtkVersioning.h"
+#include "HostWindow.h"
+#include "IntRect.h"
+#include "RenderObject.h"
+
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+namespace WebCore {
+
+static GdkCursor* lastSetCursor;
+
+Widget::Widget(PlatformWidget widget)
+{
+ init(widget);
+}
+
+Widget::~Widget()
+{
+ ASSERT(!parent());
+ releasePlatformWidget();
+}
+
+void Widget::setFocus(bool focused)
+{
+ if (focused)
+ gtk_widget_grab_focus(platformWidget() ? platformWidget() : GTK_WIDGET(root()->hostWindow()->platformPageClient()));
+}
+
+static GdkWindow* gdkWindow(PlatformWidget widget)
+{
+ return widget ? gtk_widget_get_window(widget) : 0;
+}
+
+void Widget::setCursor(const Cursor& cursor)
+{
+ GdkCursor* platformCursor = cursor.platformCursor().get();
+
+ // http://bugs.webkit.org/show_bug.cgi?id=16388
+ // [GTK] Widget::setCursor() gets called frequently
+ //
+ // gdk_window_set_cursor() in certain GDK backends seems to be an
+ // expensive operation, so avoid it if possible.
+
+ if (platformCursor == lastSetCursor)
+ return;
+
+ gdk_window_set_cursor(gdkWindow(platformWidget()) ? gdkWindow(platformWidget()) : gtk_widget_get_window(GTK_WIDGET(root()->hostWindow()->platformPageClient())), platformCursor);
+ lastSetCursor = platformCursor;
+}
+
+void Widget::show()
+{
+ setSelfVisible(true);
+
+ if (isParentVisible() && platformWidget())
+ gtk_widget_show(platformWidget());
+}
+
+void Widget::hide()
+{
+ setSelfVisible(false);
+
+ if (isParentVisible() && platformWidget())
+ gtk_widget_hide(platformWidget());
+}
+
+void Widget::paint(GraphicsContext* context, const IntRect& rect)
+{
+}
+
+void Widget::setIsSelected(bool isSelected)
+{
+ if (!platformWidget())
+ return;
+
+ // See if the platformWidget has a webkit-widget-is-selected property
+ // and set it afterwards.
+ GParamSpec* spec = g_object_class_find_property(G_OBJECT_GET_CLASS(platformWidget()),
+ "webkit-widget-is-selected");
+ if (!spec)
+ return;
+
+ g_object_set(platformWidget(), "webkit-widget-is-selected", isSelected, NULL);
+}
+
+IntRect Widget::frameRect() const
+{
+ return m_frame;
+}
+
+void Widget::setFrameRect(const IntRect& rect)
+{
+ m_frame = rect;
+}
+
+void Widget::releasePlatformWidget()
+{
+ if (!platformWidget())
+ return;
+ g_object_unref(platformWidget());
+}
+
+void Widget::retainPlatformWidget()
+{
+ if (!platformWidget())
+ return;
+ g_object_ref_sink(platformWidget());
+}
+
+}
diff --git a/Source/WebCore/platform/gtk/WidgetRenderingContext.h b/Source/WebCore/platform/gtk/WidgetRenderingContext.h
new file mode 100644
index 0000000..7334656
--- /dev/null
+++ b/Source/WebCore/platform/gtk/WidgetRenderingContext.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef WidgetRenderingContext_h
+#define WidgetRenderingContext_h
+
+#include "IntRect.h"
+#include "gtkdrawing.h"
+
+namespace WebCore {
+
+class GraphicsContext;
+class RenderThemeGtk;
+
+class WidgetRenderingContext {
+public:
+ WidgetRenderingContext(GraphicsContext*, const IntRect&);
+ ~WidgetRenderingContext();
+
+ bool paintMozillaWidget(GtkThemeWidgetType, GtkWidgetState*, int flags, GtkTextDirection = GTK_TEXT_DIR_NONE);
+ void gtkPaintBox(const IntRect&, GtkWidget*, GtkStateType, GtkShadowType, const gchar*);
+ void gtkPaintFocus(const IntRect&, GtkWidget*, GtkStateType, const gchar*);
+ void gtkPaintSlider(const IntRect&, GtkWidget*, GtkStateType, GtkShadowType, const gchar*, GtkOrientation);
+
+private:
+ GraphicsContext* m_graphicsContext;
+ IntRect m_targetRect;
+ GdkRectangle m_paintRect;
+ IntSize m_extraSpace;
+ bool m_hadError;
+
+#ifdef GTK_API_VERSION_2
+ GdkDrawable* m_target;
+#else
+ cairo_t* m_target;
+#endif
+
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/gtk/WidgetRenderingContextGtk2.cpp b/Source/WebCore/platform/gtk/WidgetRenderingContextGtk2.cpp
new file mode 100644
index 0000000..e85c570
--- /dev/null
+++ b/Source/WebCore/platform/gtk/WidgetRenderingContextGtk2.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2010 Sencha, Inc.
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef GTK_API_VERSION_2
+
+#include "config.h"
+#include "WidgetRenderingContext.h"
+
+#include "GraphicsContext.h"
+#include "RefPtrCairo.h"
+#include "RenderThemeGtk.h"
+#include "Timer.h"
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+namespace WebCore {
+
+static GdkPixmap* gScratchBuffer = 0;
+static void purgeScratchBuffer()
+{
+ if (gScratchBuffer)
+ g_object_unref(gScratchBuffer);
+ gScratchBuffer = 0;
+}
+
+// FIXME: Perhaps we can share some of this code with the ContextShadowCairo.
+// Widget rendering needs a scratch image as the buffer for the intermediate
+// render. Instead of creating and destroying the buffer for every operation,
+// we create a buffer which will be automatically purged via a timer.
+class PurgeScratchBufferTimer : public TimerBase {
+private:
+ virtual void fired() { purgeScratchBuffer(); }
+};
+static PurgeScratchBufferTimer purgeScratchBufferTimer;
+static void scheduleScratchBufferPurge()
+{
+ if (purgeScratchBufferTimer.isActive())
+ purgeScratchBufferTimer.stop();
+ purgeScratchBufferTimer.startOneShot(2);
+}
+
+static IntSize getExtraSpaceForWidget(RenderThemeGtk* theme)
+{
+ // Checkboxes and scrollbar thumbs often draw outside their boundaries. Here we figure out
+ // the maximum amount of space we need for any type of widget and use that to increase the
+ // size of the scratch buffer, while preserving the final widget position.
+
+ // The checkbox extra space is calculated by looking at the widget style.
+ int indicatorSize, indicatorSpacing;
+ theme->getIndicatorMetrics(CheckboxPart, indicatorSize, indicatorSpacing);
+ IntSize extraSpace(indicatorSpacing, indicatorSpacing);
+
+ // Scrollbar thumbs need at least an extra pixel along their movement axis.
+ return extraSpace.expandedTo(IntSize(1, 1));
+}
+
+WidgetRenderingContext::WidgetRenderingContext(GraphicsContext* graphicsContext, const IntRect& targetRect)
+ : m_graphicsContext(graphicsContext)
+ , m_targetRect(targetRect)
+ , m_hadError(false)
+{
+ RenderThemeGtk* theme = static_cast<RenderThemeGtk*>(RenderTheme::defaultTheme().get());
+
+ // Fallback: We failed to create an RGBA colormap earlier, so we cannot properly paint
+ // to a temporary surface and preserve transparency. To ensure decent widget rendering, just
+ // paint directly to the target drawable. This will not render CSS rotational transforms properly.
+ if (!theme->m_themePartsHaveRGBAColormap && graphicsContext->gdkWindow()) {
+ m_paintRect = graphicsContext->getCTM().mapRect(targetRect);
+ m_target = graphicsContext->gdkWindow();
+ return;
+ }
+
+ // Some widgets render outside their rectangles. We need to account for this.
+ m_extraSpace = getExtraSpaceForWidget(theme);
+
+ // Offset the target rectangle so that the extra space is within the boundaries of the scratch buffer.
+ m_paintRect = IntRect(IntPoint(m_extraSpace.width(), m_extraSpace.height()),
+ m_targetRect.size());
+
+ int width = m_targetRect.width() + (m_extraSpace.width() * 2);
+ int height = m_targetRect.height() + (m_extraSpace.height() * 2);
+ int scratchWidth = 0;
+ int scratchHeight = 0;
+ if (gScratchBuffer)
+ gdk_drawable_get_size(gScratchBuffer, &scratchWidth, &scratchHeight);
+
+ // We do not need to recreate the buffer if the current buffer is large enough.
+ if (!gScratchBuffer || scratchWidth < width || scratchHeight < height) {
+ purgeScratchBuffer();
+ // Round to the nearest 32 pixels so we do not grow the buffer for similar sized requests.
+ width = (1 + (width >> 5)) << 5;
+ height = (1 + (height >> 5)) << 5;
+
+ gScratchBuffer = gdk_pixmap_new(0, width, height, gdk_colormap_get_visual(theme->m_themeParts.colormap)->depth);
+ gdk_drawable_set_colormap(gScratchBuffer, theme->m_themeParts.colormap);
+ }
+ m_target = gScratchBuffer;
+
+ // Clear the scratch buffer.
+ RefPtr<cairo_t> scratchBufferContext = adoptRef(gdk_cairo_create(gScratchBuffer));
+ cairo_set_operator(scratchBufferContext.get(), CAIRO_OPERATOR_CLEAR);
+ cairo_paint(scratchBufferContext.get());
+}
+
+WidgetRenderingContext::~WidgetRenderingContext()
+{
+ // We do not need to blit back to the target in the fallback case. See above.
+ RenderThemeGtk* theme = static_cast<RenderThemeGtk*>(RenderTheme::defaultTheme().get());
+ if (!theme->m_themePartsHaveRGBAColormap && m_graphicsContext->gdkWindow())
+ return;
+
+ // Don't paint the results back if there was an error.
+ if (m_hadError) {
+ scheduleScratchBufferPurge();
+ return;
+ }
+
+ // FIXME: It's unclear if it is necessary to preserve the current source here.
+ cairo_t* cairoContext = m_graphicsContext->platformContext();
+ RefPtr<cairo_pattern_t> previousSource(cairo_get_source(cairoContext));
+
+ // The blit rectangle is the original target rectangle adjusted for any extra space.
+ IntRect fullTargetRect(m_targetRect);
+ fullTargetRect.inflateX(m_extraSpace.width());
+ fullTargetRect.inflateY(m_extraSpace.height());
+
+ gdk_cairo_set_source_pixmap(cairoContext, gScratchBuffer, fullTargetRect.x(), fullTargetRect.y());
+ cairo_rectangle(cairoContext, fullTargetRect.x(), fullTargetRect.y(), fullTargetRect.width(), fullTargetRect.height());
+ cairo_fill(cairoContext);
+ cairo_set_source(cairoContext, previousSource.get());
+ scheduleScratchBufferPurge();
+}
+
+bool WidgetRenderingContext::paintMozillaWidget(GtkThemeWidgetType type, GtkWidgetState* state, int flags, GtkTextDirection textDirection)
+{
+ // Sometimes moz_gtk_widget_paint modifies the clipping rectangle, so we must use a copy.
+ GdkRectangle clipRect = m_paintRect;
+ m_hadError = moz_gtk_widget_paint(type, m_target, &clipRect, &m_paintRect,
+ state, flags, textDirection) != MOZ_GTK_SUCCESS;
+ return !m_hadError;
+}
+
+void WidgetRenderingContext::gtkPaintBox(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, GtkShadowType shadowType, const gchar* detail)
+{
+ GdkRectangle paintRect = { m_paintRect.x + rect.x(), m_paintRect.y + rect.y(), rect.width(), rect.height() };
+ gtk_paint_box(gtk_widget_get_style(widget), m_target, stateType, shadowType, &m_paintRect,
+ widget, detail, paintRect.x, paintRect.y, paintRect.width, paintRect.height);
+}
+
+void WidgetRenderingContext::gtkPaintFocus(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, const gchar* detail)
+{
+ GdkRectangle paintRect = { m_paintRect.x + rect.x(), m_paintRect.y + rect.y(), rect.width(), rect.height() };
+ gtk_paint_focus(gtk_widget_get_style(widget), m_target, stateType, &m_paintRect, widget,
+ detail, paintRect.x, paintRect.y, paintRect.width, paintRect.height);
+}
+
+void WidgetRenderingContext::gtkPaintSlider(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, GtkShadowType shadowType, const gchar* detail, GtkOrientation orientation)
+{
+ GdkRectangle paintRect = { m_paintRect.x + rect.x(), m_paintRect.y + rect.y(), rect.width(), rect.height() };
+ gtk_paint_slider(gtk_widget_get_style(widget), m_target, stateType, shadowType, &m_paintRect, widget,
+ detail, paintRect.x, paintRect.y, paintRect.width, paintRect.height, orientation);
+}
+
+}
+
+#endif // GTK_API_VERSION_2
diff --git a/Source/WebCore/platform/gtk/WidgetRenderingContextGtk3.cpp b/Source/WebCore/platform/gtk/WidgetRenderingContextGtk3.cpp
new file mode 100644
index 0000000..69c4af5
--- /dev/null
+++ b/Source/WebCore/platform/gtk/WidgetRenderingContextGtk3.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "WidgetRenderingContext.h"
+
+#include "GraphicsContext.h"
+#include "IntRect.h"
+
+#ifndef GTK_API_VERSION_2
+
+namespace WebCore {
+
+WidgetRenderingContext::WidgetRenderingContext(GraphicsContext* context, const IntRect& targetRect)
+ : m_graphicsContext(context)
+ , m_targetRect(targetRect)
+ , m_paintRect(targetRect)
+ , m_hadError(false)
+ , m_target(context->platformContext())
+{
+}
+
+WidgetRenderingContext::~WidgetRenderingContext()
+{
+}
+
+bool WidgetRenderingContext::paintMozillaWidget(GtkThemeWidgetType type, GtkWidgetState* state, int flags, GtkTextDirection textDirection)
+{
+ m_hadError = moz_gtk_widget_paint(type, m_target, &m_paintRect, state, flags, textDirection) != MOZ_GTK_SUCCESS;
+ return !m_hadError;
+}
+
+void WidgetRenderingContext::gtkPaintBox(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, GtkShadowType shadowType, const gchar* detail)
+{
+ GdkRectangle paintRect = { m_paintRect.x + rect.x(), m_paintRect.y + rect.y(), rect.width(), rect.height() };
+ gtk_paint_box(gtk_widget_get_style(widget), m_target, stateType, shadowType, widget,
+ detail, paintRect.x, paintRect.y, paintRect.width, paintRect.height);
+}
+
+void WidgetRenderingContext::gtkPaintFocus(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, const gchar* detail)
+{
+ GdkRectangle paintRect = { m_paintRect.x + rect.x(), m_paintRect.y + rect.y(), rect.width(), rect.height() };
+ gtk_paint_focus(gtk_widget_get_style(widget), m_target, stateType, widget,
+ detail, paintRect.x, paintRect.y, paintRect.width, paintRect.height);
+}
+
+void WidgetRenderingContext::gtkPaintSlider(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, GtkShadowType shadowType, const gchar* detail, GtkOrientation orientation)
+{
+ GdkRectangle paintRect = { m_paintRect.x + rect.x(), m_paintRect.y + rect.y(), rect.width(), rect.height() };
+ gtk_paint_slider(gtk_widget_get_style(widget), m_target, stateType, shadowType, widget,
+ detail, paintRect.x, paintRect.y, paintRect.width, paintRect.height, orientation);
+}
+
+}
+
+#endif // !GTK_API_VERSION_2
diff --git a/Source/WebCore/platform/gtk/gtk2drawing.c b/Source/WebCore/platform/gtk/gtk2drawing.c
new file mode 100644
index 0000000..3ebd332
--- /dev/null
+++ b/Source/WebCore/platform/gtk/gtk2drawing.c
@@ -0,0 +1,1372 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Brian Ryner <bryner@brianryner.com> (Original Author)
+ * Pierre Chanial <p_ch@verizon.net>
+ * Michael Ventnor <m.ventnor@gmail.com>
+ * Alp Toker <alp@nuanti.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * This file contains painting functions for each of the gtk2 widgets.
+ * Adapted from the gtkdrawing.c, and gtk+2.0 source.
+ */
+
+#ifdef GTK_API_VERSION_2
+
+#undef GTK_DISABLE_DEPRECATED
+#undef GDK_DISABLE_DEPRECATED
+
+#include <gdk/gdkprivate.h>
+#include "gtkdrawing.h"
+#include "GtkVersioning.h"
+#include <math.h>
+#include <string.h>
+
+#define XTHICKNESS(style) (style->xthickness)
+#define YTHICKNESS(style) (style->ythickness)
+
+static GtkThemeParts *gParts = NULL;
+static style_prop_t style_prop_func;
+static gboolean have_arrow_scaling;
+static gboolean is_initialized;
+
+void
+moz_gtk_use_theme_parts(GtkThemeParts* parts)
+{
+ gParts = parts;
+}
+
+/* Because we have such an unconventional way of drawing widgets, signal to the GTK theme engine
+ that they are drawing for Mozilla instead of a conventional GTK app so they can do any specific
+ things they may want to do. */
+static void
+moz_gtk_set_widget_name(GtkWidget* widget)
+{
+ gtk_widget_set_name(widget, "MozillaGtkWidget");
+}
+
+gint
+moz_gtk_enable_style_props(style_prop_t styleGetProp)
+{
+ style_prop_func = styleGetProp;
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_window_widget()
+{
+ if (!gParts->protoWindow) {
+ gParts->protoWindow = gtk_window_new(GTK_WINDOW_POPUP);
+
+ if (gParts->colormap)
+ gtk_widget_set_colormap(gParts->protoWindow, gParts->colormap);
+
+ gtk_widget_realize(gParts->protoWindow);
+ moz_gtk_set_widget_name(gParts->protoWindow);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+setup_widget_prototype(GtkWidget* widget)
+{
+ ensure_window_widget();
+ if (!gParts->protoLayout) {
+ gParts->protoLayout = gtk_fixed_new();
+ gtk_container_add(GTK_CONTAINER(gParts->protoWindow), gParts->protoLayout);
+ }
+
+ gtk_container_add(GTK_CONTAINER(gParts->protoLayout), widget);
+ gtk_widget_realize(widget);
+ g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_button_widget()
+{
+ if (!gParts->buttonWidget) {
+ gParts->buttonWidget = gtk_button_new_with_label("M");
+ setup_widget_prototype(gParts->buttonWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_toggle_button_widget()
+{
+ if (!gParts->toggleButtonWidget) {
+ gParts->toggleButtonWidget = gtk_toggle_button_new();
+ setup_widget_prototype(gParts->toggleButtonWidget);
+ /* toggle button must be set active to get the right style on hover. */
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gParts->toggleButtonWidget), TRUE);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_button_arrow_widget()
+{
+ if (!gParts->buttonArrowWidget) {
+ ensure_toggle_button_widget();
+
+ gParts->buttonArrowWidget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
+ gtk_container_add(GTK_CONTAINER(gParts->toggleButtonWidget), gParts->buttonArrowWidget);
+ gtk_widget_realize(gParts->buttonArrowWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_checkbox_widget()
+{
+ if (!gParts->checkboxWidget) {
+ gParts->checkboxWidget = gtk_check_button_new_with_label("M");
+ setup_widget_prototype(gParts->checkboxWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_radiobutton_widget()
+{
+ if (!gParts->radiobuttonWidget) {
+ gParts->radiobuttonWidget = gtk_radio_button_new_with_label(NULL, "M");
+ setup_widget_prototype(gParts->radiobuttonWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_scrollbar_widget()
+{
+ if (!gParts->vertScrollbarWidget) {
+ gParts->vertScrollbarWidget = gtk_vscrollbar_new(NULL);
+ setup_widget_prototype(gParts->vertScrollbarWidget);
+ }
+ if (!gParts->horizScrollbarWidget) {
+ gParts->horizScrollbarWidget = gtk_hscrollbar_new(NULL);
+ setup_widget_prototype(gParts->horizScrollbarWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_entry_widget()
+{
+ if (!gParts->entryWidget) {
+ gParts->entryWidget = gtk_entry_new();
+ setup_widget_prototype(gParts->entryWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+/* We need to have pointers to the inner widgets (button, separator, arrow)
+ * of the ComboBox to get the correct rendering from theme engines which
+ * special cases their look. Since the inner layout can change, we ask GTK
+ * to NULL our pointers when they are about to become invalid because the
+ * corresponding widgets don't exist anymore. It's the role of
+ * g_object_add_weak_pointer().
+ * Note that if we don't find the inner widgets (which shouldn't happen), we
+ * fallback to use generic "non-inner" widgets, and they don't need that kind
+ * of weak pointer since they are explicit children of gParts->protoWindow and as
+ * such GTK holds a strong reference to them. */
+static void
+moz_gtk_get_combo_box_inner_button(GtkWidget *widget, gpointer client_data)
+{
+ if (GTK_IS_TOGGLE_BUTTON(widget)) {
+ gParts->comboBoxButtonWidget = widget;
+ g_object_add_weak_pointer(G_OBJECT(widget),
+ (gpointer) &gParts->comboBoxButtonWidget);
+ gtk_widget_realize(widget);
+ g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
+ }
+}
+
+static void
+moz_gtk_get_combo_box_button_inner_widgets(GtkWidget *widget,
+ gpointer client_data)
+{
+ if (GTK_IS_SEPARATOR(widget)) {
+ gParts->comboBoxSeparatorWidget = widget;
+ g_object_add_weak_pointer(G_OBJECT(widget),
+ (gpointer) &gParts->comboBoxSeparatorWidget);
+ } else if (GTK_IS_ARROW(widget)) {
+ gParts->comboBoxArrowWidget = widget;
+ g_object_add_weak_pointer(G_OBJECT(widget),
+ (gpointer) &gParts->comboBoxArrowWidget);
+ } else
+ return;
+ gtk_widget_realize(widget);
+ g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
+}
+
+static gint
+ensure_combo_box_widgets()
+{
+ GtkWidget* buttonChild;
+
+ if (gParts->comboBoxButtonWidget && gParts->comboBoxArrowWidget)
+ return MOZ_GTK_SUCCESS;
+
+ /* Create a ComboBox if needed */
+ if (!gParts->comboBoxWidget) {
+ gParts->comboBoxWidget = gtk_combo_box_new();
+ setup_widget_prototype(gParts->comboBoxWidget);
+ }
+
+ /* Get its inner Button */
+ gtk_container_forall(GTK_CONTAINER(gParts->comboBoxWidget),
+ moz_gtk_get_combo_box_inner_button,
+ NULL);
+
+ if (gParts->comboBoxButtonWidget) {
+ /* Get the widgets inside the Button */
+ buttonChild = gtk_bin_get_child(GTK_BIN(gParts->comboBoxButtonWidget));
+ if (GTK_IS_HBOX(buttonChild)) {
+ /* appears-as-list = FALSE, cell-view = TRUE; the button
+ * contains an hbox. This hbox is there because the ComboBox
+ * needs to place a cell renderer, a separator, and an arrow in
+ * the button when appears-as-list is FALSE. */
+ gtk_container_forall(GTK_CONTAINER(buttonChild),
+ moz_gtk_get_combo_box_button_inner_widgets,
+ NULL);
+ } else if(GTK_IS_ARROW(buttonChild)) {
+ /* appears-as-list = TRUE, or cell-view = FALSE;
+ * the button only contains an arrow */
+ gParts->comboBoxArrowWidget = buttonChild;
+ g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer)
+ &gParts->comboBoxArrowWidget);
+ gtk_widget_realize(gParts->comboBoxArrowWidget);
+ g_object_set_data(G_OBJECT(gParts->comboBoxArrowWidget),
+ "transparent-bg-hint", GINT_TO_POINTER(TRUE));
+ }
+ } else {
+ /* Shouldn't be reached with current internal gtk implementation; we
+ * use a generic toggle button as last resort fallback to avoid
+ * crashing. */
+ ensure_toggle_button_widget();
+ gParts->comboBoxButtonWidget = gParts->toggleButtonWidget;
+ }
+
+ if (!gParts->comboBoxArrowWidget) {
+ /* Shouldn't be reached with current internal gtk implementation;
+ * we gParts->buttonArrowWidget as last resort fallback to avoid
+ * crashing. */
+ ensure_button_arrow_widget();
+ gParts->comboBoxArrowWidget = gParts->buttonArrowWidget;
+ }
+
+ /* We don't test the validity of gParts->comboBoxSeparatorWidget since there
+ * is none when "appears-as-list" = TRUE or "cell-view" = FALSE; if it
+ * is invalid we just won't paint it. */
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_progress_widget()
+{
+ if (!gParts->progresWidget) {
+ gParts->progresWidget = gtk_progress_bar_new();
+ setup_widget_prototype(gParts->progresWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_scrolled_window_widget()
+{
+ if (!gParts->scrolledWindowWidget) {
+ gParts->scrolledWindowWidget = gtk_scrolled_window_new(NULL, NULL);
+ setup_widget_prototype(gParts->scrolledWindowWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static GtkStateType
+ConvertGtkState(GtkWidgetState* state)
+{
+ if (state->disabled)
+ return GTK_STATE_INSENSITIVE;
+ else if (state->depressed)
+ return (state->inHover ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE);
+ else if (state->inHover)
+ return (state->active ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT);
+ else
+ return GTK_STATE_NORMAL;
+}
+
+static gint
+TSOffsetStyleGCArray(GdkGC** gcs, gint xorigin, gint yorigin)
+{
+ int i;
+ /* there are 5 gc's in each array, for each of the widget states */
+ for (i = 0; i < 5; ++i)
+ gdk_gc_set_ts_origin(gcs[i], xorigin, yorigin);
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+TSOffsetStyleGCs(GtkStyle* style, gint xorigin, gint yorigin)
+{
+ TSOffsetStyleGCArray(style->fg_gc, xorigin, yorigin);
+ TSOffsetStyleGCArray(style->bg_gc, xorigin, yorigin);
+ TSOffsetStyleGCArray(style->light_gc, xorigin, yorigin);
+ TSOffsetStyleGCArray(style->dark_gc, xorigin, yorigin);
+ TSOffsetStyleGCArray(style->mid_gc, xorigin, yorigin);
+ TSOffsetStyleGCArray(style->text_gc, xorigin, yorigin);
+ TSOffsetStyleGCArray(style->base_gc, xorigin, yorigin);
+ gdk_gc_set_ts_origin(style->black_gc, xorigin, yorigin);
+ gdk_gc_set_ts_origin(style->white_gc, xorigin, yorigin);
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_button_paint(GdkDrawable* drawable, GdkRectangle* rect,
+ GdkRectangle* cliprect, GtkWidgetState* state,
+ GtkReliefStyle relief, GtkWidget* widget,
+ GtkTextDirection direction)
+{
+ GtkShadowType shadow_type;
+ GtkStyle* style = gtk_widget_get_style(widget);
+ GtkStateType button_state = ConvertGtkState(state);
+ gint x = rect->x, y=rect->y, width=rect->width, height=rect->height;
+
+ gboolean interior_focus;
+ gint focus_width, focus_pad;
+
+ moz_gtk_widget_get_focus(widget, &interior_focus, &focus_width, &focus_pad);
+
+ gtk_widget_set_state(widget, button_state);
+ gtk_widget_set_direction(widget, direction);
+
+ if (state->isDefault)
+ GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_DEFAULT);
+
+ gtk_button_set_relief(GTK_BUTTON(widget), relief);
+
+ /* Some theme engines love to cause us pain in that gtk_paint_focus is a
+ no-op on buttons and button-like widgets. They only listen to this flag. */
+ if (state->focused && !state->disabled)
+ GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
+
+ if (!interior_focus && state->focused) {
+ x += focus_width + focus_pad;
+ y += focus_width + focus_pad;
+ width -= 2 * (focus_width + focus_pad);
+ height -= 2 * (focus_width + focus_pad);
+ }
+
+ shadow_type = button_state == GTK_STATE_ACTIVE ||
+ state->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
+
+ if (state->isDefault && relief == GTK_RELIEF_NORMAL) {
+ gtk_paint_box(style, drawable, button_state, shadow_type, cliprect,
+ widget, "buttondefault", x, y, width, height);
+ }
+
+ if (relief != GTK_RELIEF_NONE || state->depressed ||
+ (button_state != GTK_STATE_NORMAL &&
+ button_state != GTK_STATE_INSENSITIVE)) {
+ TSOffsetStyleGCs(style, x, y);
+ /* the following line can trigger an assertion (Crux theme)
+ file ../../gdk/gdkwindow.c: line 1846 (gdk_window_clear_area):
+ assertion `GDK_IS_WINDOW (window)' failed */
+ gtk_paint_box(style, drawable, button_state, shadow_type, cliprect,
+ widget, "button", x, y, width, height);
+ }
+
+ if (state->focused) {
+ if (interior_focus) {
+ GtkStyle* style = gtk_widget_get_style(widget);
+ x += style->xthickness + focus_pad;
+ y += style->ythickness + focus_pad;
+ width -= 2 * (style->xthickness + focus_pad);
+ height -= 2 * (style->ythickness + focus_pad);
+ } else {
+ x -= focus_width + focus_pad;
+ y -= focus_width + focus_pad;
+ width += 2 * (focus_width + focus_pad);
+ height += 2 * (focus_width + focus_pad);
+ }
+
+ TSOffsetStyleGCs(style, x, y);
+ gtk_paint_focus(style, drawable, button_state, cliprect,
+ widget, "button", x, y, width, height);
+ }
+
+ GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_DEFAULT);
+ GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_init()
+{
+ GtkWidgetClass *entry_class;
+
+ is_initialized = TRUE;
+ have_arrow_scaling = (gtk_major_version > 2 ||
+ (gtk_major_version == 2 && gtk_minor_version >= 12));
+
+ /* Add style property to GtkEntry.
+ * Adding the style property to the normal GtkEntry class means that it
+ * will work without issues inside GtkComboBox and for Spinbuttons. */
+ entry_class = g_type_class_ref(GTK_TYPE_ENTRY);
+ gtk_widget_class_install_style_property(entry_class,
+ g_param_spec_boolean("honors-transparent-bg-hint",
+ "Transparent BG enabling flag",
+ "If TRUE, the theme is able to draw the GtkEntry on non-prefilled background.",
+ FALSE,
+ G_PARAM_READWRITE));
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing)
+{
+ ensure_checkbox_widget();
+
+ gtk_widget_style_get (gParts->checkboxWidget,
+ "indicator_size", indicator_size,
+ "indicator_spacing", indicator_spacing,
+ NULL);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing)
+{
+ ensure_radiobutton_widget();
+
+ gtk_widget_style_get (gParts->radiobuttonWidget,
+ "indicator_size", indicator_size,
+ "indicator_spacing", indicator_spacing,
+ NULL);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_widget_get_focus(GtkWidget* widget, gboolean* interior_focus,
+ gint* focus_width, gint* focus_pad)
+{
+ gtk_widget_style_get (widget,
+ "interior-focus", interior_focus,
+ "focus-line-width", focus_width,
+ "focus-padding", focus_pad,
+ NULL);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_button_get_inner_border(GtkWidget* widget, GtkBorder* inner_border)
+{
+ static const GtkBorder default_inner_border = { 1, 1, 1, 1 };
+ GtkBorder *tmp_border;
+
+ gtk_widget_style_get (widget, "inner-border", &tmp_border, NULL);
+
+ if (tmp_border) {
+ *inner_border = *tmp_border;
+ gtk_border_free(tmp_border);
+ }
+ else
+ *inner_border = default_inner_border;
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_toggle_paint(GdkDrawable* drawable, GdkRectangle* rect,
+ GdkRectangle* cliprect, GtkWidgetState* state,
+ gboolean selected, gboolean inconsistent,
+ gboolean isradio, GtkTextDirection direction)
+{
+ GtkStateType state_type = ConvertGtkState(state);
+ GtkShadowType shadow_type = (selected)?GTK_SHADOW_IN:GTK_SHADOW_OUT;
+ gint indicator_size, indicator_spacing;
+ gint x, y, width, height;
+ gint focus_x, focus_y, focus_width, focus_height;
+ GtkWidget *w;
+ GtkStyle *style;
+
+ if (isradio) {
+ moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing);
+ w = gParts->radiobuttonWidget;
+ } else {
+ moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing);
+ w = gParts->checkboxWidget;
+ }
+
+ // "GetMinimumWidgetSize was ignored"
+ // FIXME: This assert causes a build failure in WebKitGTK+ debug
+ // builds, because it uses 'false' in its definition. We may want
+ // to force this file to be built with g++, by renaming it.
+ // ASSERT(rect->width == indicator_size);
+
+ /*
+ * vertically center in the box, since XUL sometimes ignores our
+ * GetMinimumWidgetSize in the vertical dimension
+ */
+ x = rect->x;
+ y = rect->y + (rect->height - indicator_size) / 2;
+ width = indicator_size;
+ height = indicator_size;
+
+ focus_x = x - indicator_spacing;
+ focus_y = y - indicator_spacing;
+ focus_width = width + 2 * indicator_spacing;
+ focus_height = height + 2 * indicator_spacing;
+
+ style = gtk_widget_get_style(w);
+ TSOffsetStyleGCs(style, x, y);
+
+ gtk_widget_set_sensitive(w, !state->disabled);
+ gtk_widget_set_direction(w, direction);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), selected);
+
+ if (isradio) {
+ gtk_paint_option(style, drawable, state_type, shadow_type, cliprect,
+ gParts->radiobuttonWidget, "radiobutton", x, y,
+ width, height);
+ if (state->focused) {
+ gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect,
+ gParts->radiobuttonWidget, "radiobutton", focus_x, focus_y,
+ focus_width, focus_height);
+ }
+ }
+ else {
+ /*
+ * 'indeterminate' type on checkboxes. In GTK, the shadow type
+ * must also be changed for the state to be drawn.
+ */
+ if (inconsistent) {
+ gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gParts->checkboxWidget), TRUE);
+ shadow_type = GTK_SHADOW_ETCHED_IN;
+ } else {
+ gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gParts->checkboxWidget), FALSE);
+ }
+
+ gtk_paint_check(style, drawable, state_type, shadow_type, cliprect,
+ gParts->checkboxWidget, "checkbutton", x, y, width, height);
+ if (state->focused) {
+ gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect,
+ gParts->checkboxWidget, "checkbutton", focus_x, focus_y,
+ focus_width, focus_height);
+ }
+ }
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+calculate_button_inner_rect(GtkWidget* button, GdkRectangle* rect,
+ GdkRectangle* inner_rect,
+ GtkTextDirection direction,
+ gboolean ignore_focus)
+{
+ GtkBorder inner_border;
+ gboolean interior_focus;
+ gint focus_width, focus_pad;
+ GtkStyle* style;
+
+ style = gtk_widget_get_style(button);
+
+ /* This mirrors gtkbutton's child positioning */
+ moz_gtk_button_get_inner_border(button, &inner_border);
+ moz_gtk_widget_get_focus(button, &interior_focus,
+ &focus_width, &focus_pad);
+
+ if (ignore_focus)
+ focus_width = focus_pad = 0;
+
+ inner_rect->x = rect->x + XTHICKNESS(style) + focus_width + focus_pad;
+ inner_rect->x += direction == GTK_TEXT_DIR_LTR ?
+ inner_border.left : inner_border.right;
+ inner_rect->y = rect->y + inner_border.top + YTHICKNESS(style) +
+ focus_width + focus_pad;
+ inner_rect->width = MAX(1, rect->width - inner_border.left -
+ inner_border.right - (XTHICKNESS(style) + focus_pad + focus_width) * 2);
+ inner_rect->height = MAX(1, rect->height - inner_border.top -
+ inner_border.bottom - (YTHICKNESS(style) + focus_pad + focus_width) * 2);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+
+static gint
+calculate_arrow_rect(GtkWidget* arrow, GdkRectangle* rect,
+ GdkRectangle* arrow_rect, GtkTextDirection direction)
+{
+ /* defined in gtkarrow.c */
+ gfloat arrow_scaling = 0.7;
+ gfloat xalign, xpad;
+ gint extent;
+ GtkMisc* misc = GTK_MISC(arrow);
+ gfloat misc_xalign, misc_yalign;
+ gint misc_xpad, misc_ypad;
+
+ if (have_arrow_scaling)
+ gtk_widget_style_get(arrow, "arrow_scaling", &arrow_scaling, NULL);
+
+ gtk_misc_get_padding(misc, &misc_xpad, &misc_ypad);
+ gtk_misc_get_alignment(misc, &misc_xalign, &misc_yalign);
+
+ extent = MIN((rect->width - misc_xpad * 2),
+ (rect->height - misc_ypad * 2)) * arrow_scaling;
+
+ xalign = direction == GTK_TEXT_DIR_LTR ? misc_xalign : 1.0 - misc_xalign;
+ xpad = misc_xpad + (rect->width - extent) * xalign;
+
+ arrow_rect->x = direction == GTK_TEXT_DIR_LTR ?
+ floor(rect->x + xpad) : ceil(rect->x + xpad);
+ arrow_rect->y = floor(rect->y + misc_ypad +
+ ((rect->height - extent) * misc_yalign));
+
+ arrow_rect->width = arrow_rect->height = extent;
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_scrolled_window_paint(GdkDrawable* drawable, GdkRectangle* rect,
+ GdkRectangle* cliprect, GtkWidgetState* state)
+{
+ GtkStyle* style;
+ GtkAllocation allocation;
+ GtkWidget* widget;
+
+ ensure_scrolled_window_widget();
+ widget = gParts->scrolledWindowWidget;
+
+ gtk_widget_get_allocation(widget, &allocation);
+ allocation.x = rect->x;
+ allocation.y = rect->y;
+ allocation.width = rect->width;
+ allocation.height = rect->height;
+ gtk_widget_set_allocation(widget, &allocation);
+
+ style = gtk_widget_get_style(widget);
+ TSOffsetStyleGCs(style, rect->x - 1, rect->y - 1);
+ gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
+ cliprect, gParts->scrolledWindowWidget, "scrolled_window",
+ rect->x, rect->y, rect->width, rect->height);
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_scrollbar_button_paint(GdkDrawable* drawable, GdkRectangle* rect,
+ GdkRectangle* cliprect, GtkWidgetState* state,
+ GtkScrollbarButtonFlags flags,
+ GtkTextDirection direction)
+{
+ GtkStateType state_type = ConvertGtkState(state);
+ GtkShadowType shadow_type = (state->active) ?
+ GTK_SHADOW_IN : GTK_SHADOW_OUT;
+ GdkRectangle arrow_rect;
+ GtkStyle* style;
+ GtkWidget *scrollbar;
+ GtkAllocation allocation;
+ GtkArrowType arrow_type;
+ gint arrow_displacement_x, arrow_displacement_y;
+ const char* detail = (flags & MOZ_GTK_STEPPER_VERTICAL) ?
+ "vscrollbar" : "hscrollbar";
+
+ ensure_scrollbar_widget();
+
+ if (flags & MOZ_GTK_STEPPER_VERTICAL)
+ scrollbar = gParts->vertScrollbarWidget;
+ else
+ scrollbar = gParts->horizScrollbarWidget;
+
+ gtk_widget_set_direction(scrollbar, direction);
+
+ /* Some theme engines (i.e., ClearLooks) check the scrollbar's allocation
+ to determine where it should paint rounded corners on the buttons.
+ We need to trick them into drawing the buttons the way we want them. */
+
+ gtk_widget_get_allocation(scrollbar, &allocation);
+ allocation.x = rect->x;
+ allocation.y = rect->y;
+ allocation.width = rect->width;
+ allocation.height = rect->height;
+
+ if (flags & MOZ_GTK_STEPPER_VERTICAL) {
+ allocation.height *= 5;
+ if (flags & MOZ_GTK_STEPPER_DOWN) {
+ arrow_type = GTK_ARROW_DOWN;
+ if (flags & MOZ_GTK_STEPPER_BOTTOM)
+ allocation.y -= 4 * rect->height;
+ else
+ allocation.y -= rect->height;
+
+ } else {
+ arrow_type = GTK_ARROW_UP;
+ if (flags & MOZ_GTK_STEPPER_BOTTOM)
+ allocation.y -= 3 * rect->height;
+ }
+ } else {
+ allocation.width *= 5;
+ if (flags & MOZ_GTK_STEPPER_DOWN) {
+ arrow_type = GTK_ARROW_RIGHT;
+ if (flags & MOZ_GTK_STEPPER_BOTTOM)
+ allocation.x -= 4 * rect->width;
+ else
+ allocation.x -= rect->width;
+ } else {
+ arrow_type = GTK_ARROW_LEFT;
+ if (flags & MOZ_GTK_STEPPER_BOTTOM)
+ allocation.x -= 3 * rect->width;
+ }
+ }
+
+ gtk_widget_set_allocation(scrollbar, &allocation);
+ style = gtk_widget_get_style(scrollbar);
+
+ TSOffsetStyleGCs(style, rect->x, rect->y);
+
+ gtk_paint_box(style, drawable, state_type, shadow_type, cliprect,
+ scrollbar, detail, rect->x, rect->y,
+ rect->width, rect->height);
+
+ arrow_rect.width = rect->width / 2;
+ arrow_rect.height = rect->height / 2;
+ arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
+ arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2;
+
+ if (state_type == GTK_STATE_ACTIVE) {
+ gtk_widget_style_get(scrollbar,
+ "arrow-displacement-x", &arrow_displacement_x,
+ "arrow-displacement-y", &arrow_displacement_y,
+ NULL);
+
+ arrow_rect.x += arrow_displacement_x;
+ arrow_rect.y += arrow_displacement_y;
+ }
+
+ gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect,
+ scrollbar, detail, arrow_type, TRUE, arrow_rect.x,
+ arrow_rect.y, arrow_rect.width, arrow_rect.height);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_scrollbar_trough_paint(GtkThemeWidgetType widget,
+ GdkDrawable* drawable, GdkRectangle* rect,
+ GdkRectangle* cliprect, GtkWidgetState* state,
+ GtkTextDirection direction)
+{
+ GtkStyle* style;
+ GtkScrollbar *scrollbar;
+
+ ensure_scrollbar_widget();
+
+ if (widget == MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL)
+ scrollbar = GTK_SCROLLBAR(gParts->horizScrollbarWidget);
+ else
+ scrollbar = GTK_SCROLLBAR(gParts->vertScrollbarWidget);
+
+ gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction);
+
+ style = gtk_widget_get_style(GTK_WIDGET(scrollbar));
+
+ TSOffsetStyleGCs(style, rect->x, rect->y);
+ gtk_paint_box(style, drawable, GTK_STATE_ACTIVE, GTK_SHADOW_IN, cliprect,
+ GTK_WIDGET(scrollbar), "trough", rect->x, rect->y,
+ rect->width, rect->height);
+
+ if (state->focused) {
+ gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect,
+ GTK_WIDGET(scrollbar), "trough",
+ rect->x, rect->y, rect->width, rect->height);
+ }
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget,
+ GdkDrawable* drawable, GdkRectangle* rect,
+ GdkRectangle* cliprect, GtkWidgetState* state,
+ GtkTextDirection direction)
+{
+ GtkStateType state_type = (state->inHover || state->active) ?
+ GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
+ GtkShadowType shadow_type = GTK_SHADOW_OUT;
+ GtkStyle* style;
+ GtkScrollbar *scrollbar;
+ GtkAdjustment *adj;
+ gboolean activate_slider;
+
+ ensure_scrollbar_widget();
+
+ if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL)
+ scrollbar = GTK_SCROLLBAR(gParts->horizScrollbarWidget);
+ else
+ scrollbar = GTK_SCROLLBAR(gParts->vertScrollbarWidget);
+
+ gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction);
+
+ /* Make sure to set the scrollbar range before painting so that
+ everything is drawn properly. At least the bluecurve (and
+ maybe other) themes don't draw the top or bottom black line
+ surrounding the scrollbar if the theme thinks that it's butted
+ up against the scrollbar arrows. Note the increases of the
+ clip rect below. */
+ /* Changing the cliprect is pretty bogus. This lets themes draw
+ outside the frame, which means we don't invalidate them
+ correctly. See bug 297508. But some themes do seem to need
+ it. So we modify the frame's overflow area to account for what
+ we're doing here; see nsNativeThemeGTK::GetWidgetOverflow. */
+ adj = gtk_range_get_adjustment(GTK_RANGE(scrollbar));
+
+ if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) {
+ cliprect->x -= 1;
+ cliprect->width += 2;
+ gtk_adjustment_set_page_size(adj, rect->width);
+ }
+ else {
+ cliprect->y -= 1;
+ cliprect->height += 2;
+ gtk_adjustment_set_page_size(adj, rect->height);
+ }
+
+#if GTK_CHECK_VERSION(2, 14, 0)
+ gtk_adjustment_configure(adj,
+ state->curpos,
+ 0,
+ state->maxpos,
+ gtk_adjustment_get_step_increment(adj),
+ gtk_adjustment_get_page_increment(adj),
+ gtk_adjustment_get_page_size(adj));
+#else
+ adj->lower = 0;
+ adj->value = state->curpos;
+ adj->upper = state->maxpos;
+ gtk_adjustment_changed(adj);
+#endif
+
+ style = gtk_widget_get_style(GTK_WIDGET(scrollbar));
+
+ gtk_widget_style_get(GTK_WIDGET(scrollbar), "activate-slider",
+ &activate_slider, NULL);
+
+ if (activate_slider && state->active) {
+ shadow_type = GTK_SHADOW_IN;
+ state_type = GTK_STATE_ACTIVE;
+ }
+
+ TSOffsetStyleGCs(style, rect->x, rect->y);
+
+ gtk_paint_slider(style, drawable, state_type, shadow_type, cliprect,
+ GTK_WIDGET(scrollbar), "slider", rect->x, rect->y,
+ rect->width, rect->height,
+ (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) ?
+ GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_entry_paint(GdkDrawable* drawable, GdkRectangle* rect,
+ GdkRectangle* cliprect, GtkWidgetState* state,
+ GtkWidget* widget, GtkTextDirection direction)
+{
+ GtkStateType bg_state = state->disabled ?
+ GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL;
+ gint x, y, width = rect->width, height = rect->height;
+ GtkStyle* style;
+ gboolean interior_focus;
+ gboolean theme_honors_transparency = FALSE;
+ gint focus_width;
+
+ gtk_widget_set_direction(widget, direction);
+
+ style = gtk_widget_get_style(widget);
+
+ gtk_widget_style_get(widget,
+ "interior-focus", &interior_focus,
+ "focus-line-width", &focus_width,
+ "honors-transparent-bg-hint", &theme_honors_transparency,
+ NULL);
+
+ /* gtkentry.c uses two windows, one for the entire widget and one for the
+ * text area inside it. The background of both windows is set to the "base"
+ * color of the new state in gtk_entry_state_changed, but only the inner
+ * textarea window uses gtk_paint_flat_box when exposed */
+
+ TSOffsetStyleGCs(style, rect->x, rect->y);
+
+ /* This gets us a lovely greyish disabledish look */
+ gtk_widget_set_sensitive(widget, !state->disabled);
+
+ /* GTK fills the outer widget window with the base color before drawing the widget.
+ * Some older themes rely on this behavior, but many themes nowadays use rounded
+ * corners on their widgets. While most GTK apps are blissfully unaware of this
+ * problem due to their use of the default window background, we render widgets on
+ * many kinds of backgrounds on the web.
+ * If the theme is able to cope with transparency, then we can skip pre-filling
+ * and notify the theme it will paint directly on the canvas. */
+ if (theme_honors_transparency) {
+ g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
+ } else {
+ gdk_draw_rectangle(drawable, style->base_gc[bg_state], TRUE,
+ cliprect->x, cliprect->y, cliprect->width, cliprect->height);
+ g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(FALSE));
+ }
+
+ /* Get the position of the inner window, see _gtk_entry_get_borders */
+ x = XTHICKNESS(style);
+ y = YTHICKNESS(style);
+
+ if (!interior_focus) {
+ x += focus_width;
+ y += focus_width;
+ }
+
+ /* Simulate an expose of the inner window */
+ gtk_paint_flat_box(style, drawable, bg_state, GTK_SHADOW_NONE,
+ cliprect, widget, "entry_bg", rect->x + x,
+ rect->y + y, rect->width - 2*x, rect->height - 2*y);
+
+ /* Now paint the shadow and focus border.
+ * We do like in gtk_entry_draw_frame, we first draw the shadow, a tad
+ * smaller when focused if the focus is not interior, then the focus. */
+ x = rect->x;
+ y = rect->y;
+
+ if (state->focused && !state->disabled) {
+ /* This will get us the lit borders that focused textboxes enjoy on
+ * some themes. */
+ GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
+
+ if (!interior_focus) {
+ /* Indent the border a little bit if we have exterior focus
+ (this is what GTK does to draw native entries) */
+ x += focus_width;
+ y += focus_width;
+ width -= 2 * focus_width;
+ height -= 2 * focus_width;
+ }
+ }
+
+ gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
+ cliprect, widget, "entry", x, y, width, height);
+
+ if (state->focused && !state->disabled) {
+ if (!interior_focus) {
+ gtk_paint_focus(style, drawable, GTK_STATE_NORMAL, cliprect,
+ widget, "entry",
+ rect->x, rect->y, rect->width, rect->height);
+ }
+
+ /* Now unset the focus flag. We don't want other entries to look
+ * like they're focused too! */
+ GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
+ }
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_combo_box_paint(GdkDrawable* drawable, GdkRectangle* rect,
+ GdkRectangle* cliprect, GtkWidgetState* state,
+ gboolean ishtml, GtkTextDirection direction)
+{
+ GdkRectangle arrow_rect, real_arrow_rect;
+ gint /* arrow_size, */ separator_width;
+ gboolean wide_separators;
+ GtkStateType state_type = ConvertGtkState(state);
+ GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
+ GtkStyle* style;
+ GtkRequisition arrow_req;
+
+ ensure_combo_box_widgets();
+
+ /* Also sets the direction on gParts->comboBoxButtonWidget, which is then
+ * inherited by the separator and arrow */
+ moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL,
+ gParts->comboBoxButtonWidget, direction);
+
+ calculate_button_inner_rect(gParts->comboBoxButtonWidget,
+ rect, &arrow_rect, direction, ishtml);
+ /* Now arrow_rect contains the inner rect ; we want to correct the width
+ * to what the arrow needs (see gtk_combo_box_size_allocate) */
+ gtk_widget_size_request(gParts->comboBoxArrowWidget, &arrow_req);
+ if (direction == GTK_TEXT_DIR_LTR)
+ arrow_rect.x += arrow_rect.width - arrow_req.width;
+ arrow_rect.width = arrow_req.width;
+
+ calculate_arrow_rect(gParts->comboBoxArrowWidget,
+ &arrow_rect, &real_arrow_rect, direction);
+
+ style = gtk_widget_get_style(gParts->comboBoxArrowWidget);
+ TSOffsetStyleGCs(style, rect->x, rect->y);
+
+ gtk_widget_size_allocate(gParts->comboBoxWidget, rect);
+
+ gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect,
+ gParts->comboBoxArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE,
+ real_arrow_rect.x, real_arrow_rect.y,
+ real_arrow_rect.width, real_arrow_rect.height);
+
+
+ /* If there is no separator in the theme, there's nothing left to do. */
+ if (!gParts->comboBoxSeparatorWidget)
+ return MOZ_GTK_SUCCESS;
+
+ style = gtk_widget_get_style(gParts->comboBoxSeparatorWidget);
+ TSOffsetStyleGCs(style, rect->x, rect->y);
+
+ gtk_widget_style_get(gParts->comboBoxSeparatorWidget,
+ "wide-separators", &wide_separators,
+ "separator-width", &separator_width,
+ NULL);
+
+ if (wide_separators) {
+ if (direction == GTK_TEXT_DIR_LTR)
+ arrow_rect.x -= separator_width;
+ else
+ arrow_rect.x += arrow_rect.width;
+
+ gtk_paint_box(style, drawable,
+ GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT,
+ cliprect, gParts->comboBoxSeparatorWidget, "vseparator",
+ arrow_rect.x, arrow_rect.y,
+ separator_width, arrow_rect.height);
+ } else {
+ if (direction == GTK_TEXT_DIR_LTR)
+ arrow_rect.x -= XTHICKNESS(style);
+ else
+ arrow_rect.x += arrow_rect.width;
+
+ gtk_paint_vline(style, drawable, GTK_STATE_NORMAL, cliprect,
+ gParts->comboBoxSeparatorWidget, "vseparator",
+ arrow_rect.y, arrow_rect.y + arrow_rect.height,
+ arrow_rect.x);
+ }
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_progressbar_paint(GdkDrawable* drawable, GdkRectangle* rect,
+ GdkRectangle* cliprect, GtkTextDirection direction)
+{
+ GtkStyle* style;
+
+ ensure_progress_widget();
+ gtk_widget_set_direction(gParts->progresWidget, direction);
+
+ style = gtk_widget_get_style(gParts->progresWidget);
+
+ TSOffsetStyleGCs(style, rect->x, rect->y);
+ gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
+ cliprect, gParts->progresWidget, "trough", rect->x, rect->y,
+ rect->width, rect->height);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_progress_chunk_paint(GdkDrawable* drawable, GdkRectangle* rect,
+ GdkRectangle* cliprect, GtkTextDirection direction)
+{
+ GtkStyle* style;
+
+ ensure_progress_widget();
+ gtk_widget_set_direction(gParts->progresWidget, direction);
+
+ style = gtk_widget_get_style(gParts->progresWidget);
+
+ TSOffsetStyleGCs(style, rect->x, rect->y);
+ gtk_paint_box(style, drawable, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
+ cliprect, gParts->progresWidget, "bar", rect->x, rect->y,
+ rect->width, rect->height);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
+ gint* right, gint* bottom, GtkTextDirection direction,
+ gboolean inhtml)
+{
+ GtkWidget* w;
+ GtkStyle *style;
+
+ switch (widget) {
+ case MOZ_GTK_BUTTON:
+ {
+ GtkBorder inner_border;
+ gboolean interior_focus;
+ gint focus_width, focus_pad;
+ GtkStyle *style;
+
+ ensure_button_widget();
+ *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(gParts->buttonWidget));
+
+ /* Don't add this padding in HTML, otherwise the buttons will
+ become too big and stuff the layout. */
+ if (!inhtml) {
+ moz_gtk_widget_get_focus(gParts->buttonWidget, &interior_focus, &focus_width, &focus_pad);
+ moz_gtk_button_get_inner_border(gParts->buttonWidget, &inner_border);
+ *left += focus_width + focus_pad + inner_border.left;
+ *right += focus_width + focus_pad + inner_border.right;
+ *top += focus_width + focus_pad + inner_border.top;
+ *bottom += focus_width + focus_pad + inner_border.bottom;
+ }
+
+ style = gtk_widget_get_style(gParts->buttonWidget);
+ *left += style->xthickness;
+ *right += style->xthickness;
+ *top += style->ythickness;
+ *bottom += style->ythickness;
+ return MOZ_GTK_SUCCESS;
+ }
+ case MOZ_GTK_ENTRY:
+ ensure_entry_widget();
+ w = gParts->entryWidget;
+ break;
+ case MOZ_GTK_DROPDOWN:
+ {
+ /* We need to account for the arrow on the dropdown, so text
+ * doesn't come too close to the arrow, or in some cases spill
+ * into the arrow. */
+ gboolean ignored_interior_focus, wide_separators;
+ gint focus_width, focus_pad, separator_width;
+ GtkRequisition arrow_req;
+ GtkStyle* style;
+
+ ensure_combo_box_widgets();
+
+ *left = gtk_container_get_border_width(GTK_CONTAINER(gParts->comboBoxButtonWidget));
+
+ if (!inhtml) {
+ moz_gtk_widget_get_focus(gParts->comboBoxButtonWidget,
+ &ignored_interior_focus,
+ &focus_width, &focus_pad);
+ *left += focus_width + focus_pad;
+ }
+
+ style = gtk_widget_get_style(gParts->comboBoxButtonWidget);
+ *top = *left + style->ythickness;
+ *left += style->xthickness;
+
+ *right = *left; *bottom = *top;
+
+ /* If there is no separator, don't try to count its width. */
+ separator_width = 0;
+ if (gParts->comboBoxSeparatorWidget) {
+ gtk_widget_style_get(gParts->comboBoxSeparatorWidget,
+ "wide-separators", &wide_separators,
+ "separator-width", &separator_width,
+ NULL);
+
+ if (!wide_separators)
+ separator_width =
+ XTHICKNESS(style);
+ }
+
+ gtk_widget_size_request(gParts->comboBoxArrowWidget, &arrow_req);
+ if (direction == GTK_TEXT_DIR_RTL)
+ *left += separator_width + arrow_req.width;
+ else
+ *right += separator_width + arrow_req.width;
+
+ return MOZ_GTK_SUCCESS;
+ }
+ case MOZ_GTK_PROGRESSBAR:
+ ensure_progress_widget();
+ w = gParts->progresWidget;
+ break;
+ /* These widgets have no borders, since they are not containers. */
+ case MOZ_GTK_CHECKBUTTON:
+ case MOZ_GTK_RADIOBUTTON:
+ case MOZ_GTK_SCROLLBAR_BUTTON:
+ case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL:
+ case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL:
+ case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
+ case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
+ case MOZ_GTK_PROGRESS_CHUNK:
+ *left = *top = *right = *bottom = 0;
+ return MOZ_GTK_SUCCESS;
+ default:
+ g_warning("Unsupported widget type: %d", widget);
+ return MOZ_GTK_UNKNOWN_WIDGET;
+ }
+
+ style = gtk_widget_get_style(w);
+ *right = *left = XTHICKNESS(style);
+ *bottom = *top = YTHICKNESS(style);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics)
+{
+ ensure_scrollbar_widget();
+
+ gtk_widget_style_get (gParts->horizScrollbarWidget,
+ "slider_width", &metrics->slider_width,
+ "trough_border", &metrics->trough_border,
+ "stepper_size", &metrics->stepper_size,
+ "stepper_spacing", &metrics->stepper_spacing,
+ "trough_under_steppers", &metrics->trough_under_steppers,
+ "has_secondary_forward_stepper", &metrics->has_secondary_forward_stepper,
+ "has_secondary_backward_stepper", &metrics->has_secondary_backward_stepper,
+ NULL);
+
+ metrics->min_slider_size = gtk_range_get_min_slider_size(GTK_RANGE(gParts->horizScrollbarWidget));
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable,
+ GdkRectangle* rect, GdkRectangle* cliprect,
+ GtkWidgetState* state, gint flags,
+ GtkTextDirection direction)
+{
+ switch (widget) {
+ case MOZ_GTK_BUTTON:
+ if (state->depressed) {
+ ensure_toggle_button_widget();
+ return moz_gtk_button_paint(drawable, rect, cliprect, state,
+ (GtkReliefStyle) flags,
+ gParts->toggleButtonWidget, direction);
+ }
+ ensure_button_widget();
+ return moz_gtk_button_paint(drawable, rect, cliprect, state,
+ (GtkReliefStyle) flags, gParts->buttonWidget,
+ direction);
+ break;
+ case MOZ_GTK_CHECKBUTTON:
+ case MOZ_GTK_RADIOBUTTON:
+ return moz_gtk_toggle_paint(drawable, rect, cliprect, state,
+ !!(flags & MOZ_GTK_WIDGET_CHECKED),
+ !!(flags & MOZ_GTK_WIDGET_INCONSISTENT),
+ (widget == MOZ_GTK_RADIOBUTTON),
+ direction);
+ break;
+ case MOZ_GTK_SCROLLBAR_BUTTON:
+ return moz_gtk_scrollbar_button_paint(drawable, rect, cliprect, state,
+ (GtkScrollbarButtonFlags) flags,
+ direction);
+ break;
+ case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL:
+ case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL:
+ return moz_gtk_scrollbar_trough_paint(widget, drawable, rect,
+ cliprect, state, direction);
+ break;
+ case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
+ case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
+ return moz_gtk_scrollbar_thumb_paint(widget, drawable, rect,
+ cliprect, state, direction);
+ break;
+ case MOZ_GTK_SCROLLED_WINDOW:
+ return moz_gtk_scrolled_window_paint(drawable, rect, cliprect, state);
+ break;
+ case MOZ_GTK_ENTRY:
+ ensure_entry_widget();
+ return moz_gtk_entry_paint(drawable, rect, cliprect, state,
+ gParts->entryWidget, direction);
+ break;
+ case MOZ_GTK_DROPDOWN:
+ return moz_gtk_combo_box_paint(drawable, rect, cliprect, state,
+ (gboolean) flags, direction);
+ break;
+ case MOZ_GTK_PROGRESSBAR:
+ return moz_gtk_progressbar_paint(drawable, rect, cliprect, direction);
+ break;
+ case MOZ_GTK_PROGRESS_CHUNK:
+ return moz_gtk_progress_chunk_paint(drawable, rect, cliprect,
+ direction);
+ break;
+ default:
+ g_warning("Unknown widget type: %d", widget);
+ }
+
+ return MOZ_GTK_UNKNOWN_WIDGET;
+}
+
+GtkWidget* moz_gtk_get_scrollbar_widget(void)
+{
+ if (!is_initialized)
+ return NULL;
+ ensure_scrollbar_widget();
+ return gParts->horizScrollbarWidget;
+}
+
+gint
+moz_gtk_shutdown()
+{
+ GtkWidgetClass *entry_class;
+ entry_class = g_type_class_peek(GTK_TYPE_ENTRY);
+ g_type_class_unref(entry_class);
+
+ is_initialized = FALSE;
+
+ return MOZ_GTK_SUCCESS;
+}
+
+void moz_gtk_destroy_theme_parts_widgets(GtkThemeParts* parts)
+{
+ if (!parts)
+ return;
+
+ if (parts->protoWindow) {
+ gtk_widget_destroy(parts->protoWindow);
+ parts->protoWindow = NULL;
+ }
+}
+
+GtkWidget* moz_gtk_get_progress_widget()
+{
+ if (!is_initialized)
+ return NULL;
+ ensure_progress_widget();
+ return gParts->progresWidget;
+}
+
+#endif // GTK_API_VERSION_2
diff --git a/Source/WebCore/platform/gtk/gtk3drawing.c b/Source/WebCore/platform/gtk/gtk3drawing.c
new file mode 100644
index 0000000..d3bdd56
--- /dev/null
+++ b/Source/WebCore/platform/gtk/gtk3drawing.c
@@ -0,0 +1,1288 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Brian Ryner <bryner@brianryner.com> (Original Author)
+ * Pierre Chanial <p_ch@verizon.net>
+ * Michael Ventnor <m.ventnor@gmail.com>
+ * Alp Toker <alp@nuanti.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * This file contains painting functions for each of the gtk2 widgets.
+ * Adapted from the gtkdrawing.c, and gtk+2.0 source.
+ */
+
+#ifndef GTK_API_VERSION_2
+
+#include <gdk/gdkprivate.h>
+#include "gtkdrawing.h"
+#include "GtkVersioning.h"
+#include <math.h>
+#include <string.h>
+
+#define XTHICKNESS(style) (style->xthickness)
+#define YTHICKNESS(style) (style->ythickness)
+
+static GtkThemeParts *gParts = NULL;
+static style_prop_t style_prop_func;
+static gboolean have_arrow_scaling;
+static gboolean is_initialized;
+
+void
+moz_gtk_use_theme_parts(GtkThemeParts* parts)
+{
+ gParts = parts;
+}
+
+/* Because we have such an unconventional way of drawing widgets, signal to the GTK theme engine
+ that they are drawing for Mozilla instead of a conventional GTK app so they can do any specific
+ things they may want to do. */
+static void
+moz_gtk_set_widget_name(GtkWidget* widget)
+{
+ gtk_widget_set_name(widget, "MozillaGtkWidget");
+}
+
+gint
+moz_gtk_enable_style_props(style_prop_t styleGetProp)
+{
+ style_prop_func = styleGetProp;
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_window_widget()
+{
+ if (!gParts->protoWindow) {
+ gParts->protoWindow = gtk_window_new(GTK_WINDOW_POPUP);
+ gtk_widget_realize(gParts->protoWindow);
+ moz_gtk_set_widget_name(gParts->protoWindow);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+setup_widget_prototype(GtkWidget* widget)
+{
+ ensure_window_widget();
+ if (!gParts->protoLayout) {
+ gParts->protoLayout = gtk_fixed_new();
+ gtk_container_add(GTK_CONTAINER(gParts->protoWindow), gParts->protoLayout);
+ }
+
+ gtk_container_add(GTK_CONTAINER(gParts->protoLayout), widget);
+ gtk_widget_realize(widget);
+ g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_button_widget()
+{
+ if (!gParts->buttonWidget) {
+ gParts->buttonWidget = gtk_button_new_with_label("M");
+ setup_widget_prototype(gParts->buttonWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_toggle_button_widget()
+{
+ if (!gParts->toggleButtonWidget) {
+ gParts->toggleButtonWidget = gtk_toggle_button_new();
+ setup_widget_prototype(gParts->toggleButtonWidget);
+ /* toggle button must be set active to get the right style on hover. */
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gParts->toggleButtonWidget), TRUE);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_button_arrow_widget()
+{
+ if (!gParts->buttonArrowWidget) {
+ ensure_toggle_button_widget();
+
+ gParts->buttonArrowWidget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
+ gtk_container_add(GTK_CONTAINER(gParts->toggleButtonWidget), gParts->buttonArrowWidget);
+ gtk_widget_realize(gParts->buttonArrowWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_checkbox_widget()
+{
+ if (!gParts->checkboxWidget) {
+ gParts->checkboxWidget = gtk_check_button_new_with_label("M");
+ setup_widget_prototype(gParts->checkboxWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_radiobutton_widget()
+{
+ if (!gParts->radiobuttonWidget) {
+ gParts->radiobuttonWidget = gtk_radio_button_new_with_label(NULL, "M");
+ setup_widget_prototype(gParts->radiobuttonWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_scrollbar_widget()
+{
+ if (!gParts->vertScrollbarWidget) {
+ gParts->vertScrollbarWidget = gtk_vscrollbar_new(NULL);
+ setup_widget_prototype(gParts->vertScrollbarWidget);
+ }
+ if (!gParts->horizScrollbarWidget) {
+ gParts->horizScrollbarWidget = gtk_hscrollbar_new(NULL);
+ setup_widget_prototype(gParts->horizScrollbarWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_entry_widget()
+{
+ if (!gParts->entryWidget) {
+ gParts->entryWidget = gtk_entry_new();
+ setup_widget_prototype(gParts->entryWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+/* We need to have pointers to the inner widgets (button, separator, arrow)
+ * of the ComboBox to get the correct rendering from theme engines which
+ * special cases their look. Since the inner layout can change, we ask GTK
+ * to NULL our pointers when they are about to become invalid because the
+ * corresponding widgets don't exist anymore. It's the role of
+ * g_object_add_weak_pointer().
+ * Note that if we don't find the inner widgets (which shouldn't happen), we
+ * fallback to use generic "non-inner" widgets, and they don't need that kind
+ * of weak pointer since they are explicit children of gParts->protoWindow and as
+ * such GTK holds a strong reference to them. */
+static void
+moz_gtk_get_combo_box_inner_button(GtkWidget *widget, gpointer client_data)
+{
+ if (GTK_IS_TOGGLE_BUTTON(widget)) {
+ gParts->comboBoxButtonWidget = widget;
+ g_object_add_weak_pointer(G_OBJECT(widget),
+ (gpointer) &gParts->comboBoxButtonWidget);
+ gtk_widget_realize(widget);
+ g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
+ }
+}
+
+static void
+moz_gtk_get_combo_box_button_inner_widgets(GtkWidget *widget,
+ gpointer client_data)
+{
+ if (GTK_IS_SEPARATOR(widget)) {
+ gParts->comboBoxSeparatorWidget = widget;
+ g_object_add_weak_pointer(G_OBJECT(widget),
+ (gpointer) &gParts->comboBoxSeparatorWidget);
+ } else if (GTK_IS_ARROW(widget)) {
+ gParts->comboBoxArrowWidget = widget;
+ g_object_add_weak_pointer(G_OBJECT(widget),
+ (gpointer) &gParts->comboBoxArrowWidget);
+ } else
+ return;
+ gtk_widget_realize(widget);
+ g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
+}
+
+static gint
+ensure_combo_box_widgets()
+{
+ GtkWidget* buttonChild;
+
+ if (gParts->comboBoxButtonWidget && gParts->comboBoxArrowWidget)
+ return MOZ_GTK_SUCCESS;
+
+ /* Create a ComboBox if needed */
+ if (!gParts->comboBoxWidget) {
+ gParts->comboBoxWidget = gtk_combo_box_new();
+ setup_widget_prototype(gParts->comboBoxWidget);
+ }
+
+ /* Get its inner Button */
+ gtk_container_forall(GTK_CONTAINER(gParts->comboBoxWidget),
+ moz_gtk_get_combo_box_inner_button,
+ NULL);
+
+ if (gParts->comboBoxButtonWidget) {
+ /* Get the widgets inside the Button */
+ buttonChild = gtk_bin_get_child(GTK_BIN(gParts->comboBoxButtonWidget));
+ if (GTK_IS_HBOX(buttonChild)) {
+ /* appears-as-list = FALSE, cell-view = TRUE; the button
+ * contains an hbox. This hbox is there because the ComboBox
+ * needs to place a cell renderer, a separator, and an arrow in
+ * the button when appears-as-list is FALSE. */
+ gtk_container_forall(GTK_CONTAINER(buttonChild),
+ moz_gtk_get_combo_box_button_inner_widgets,
+ NULL);
+ } else if(GTK_IS_ARROW(buttonChild)) {
+ /* appears-as-list = TRUE, or cell-view = FALSE;
+ * the button only contains an arrow */
+ gParts->comboBoxArrowWidget = buttonChild;
+ g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer)
+ &gParts->comboBoxArrowWidget);
+ gtk_widget_realize(gParts->comboBoxArrowWidget);
+ g_object_set_data(G_OBJECT(gParts->comboBoxArrowWidget),
+ "transparent-bg-hint", GINT_TO_POINTER(TRUE));
+ }
+ } else {
+ /* Shouldn't be reached with current internal gtk implementation; we
+ * use a generic toggle button as last resort fallback to avoid
+ * crashing. */
+ ensure_toggle_button_widget();
+ gParts->comboBoxButtonWidget = gParts->toggleButtonWidget;
+ }
+
+ if (!gParts->comboBoxArrowWidget) {
+ /* Shouldn't be reached with current internal gtk implementation;
+ * we gParts->buttonArrowWidget as last resort fallback to avoid
+ * crashing. */
+ ensure_button_arrow_widget();
+ gParts->comboBoxArrowWidget = gParts->buttonArrowWidget;
+ }
+
+ /* We don't test the validity of gParts->comboBoxSeparatorWidget since there
+ * is none when "appears-as-list" = TRUE or "cell-view" = FALSE; if it
+ * is invalid we just won't paint it. */
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_progress_widget()
+{
+ if (!gParts->progresWidget) {
+ gParts->progresWidget = gtk_progress_bar_new();
+ setup_widget_prototype(gParts->progresWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+ensure_scrolled_window_widget()
+{
+ if (!gParts->scrolledWindowWidget) {
+ gParts->scrolledWindowWidget = gtk_scrolled_window_new(NULL, NULL);
+ setup_widget_prototype(gParts->scrolledWindowWidget);
+ }
+ return MOZ_GTK_SUCCESS;
+}
+
+static GtkStateType
+ConvertGtkState(GtkWidgetState* state)
+{
+ if (state->disabled)
+ return GTK_STATE_INSENSITIVE;
+ else if (state->depressed)
+ return (state->inHover ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE);
+ else if (state->inHover)
+ return (state->active ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT);
+ else
+ return GTK_STATE_NORMAL;
+}
+
+static gint
+moz_gtk_button_paint(cairo_t* cr, GdkRectangle* rect,
+ GtkWidgetState* state, GtkReliefStyle relief,
+ GtkWidget* widget, GtkTextDirection direction)
+{
+ GtkShadowType shadow_type;
+ GtkStyle* style = gtk_widget_get_style(widget);
+ GtkStateType button_state = ConvertGtkState(state);
+ gint x = rect->x, y=rect->y, width=rect->width, height=rect->height;
+ GdkWindow* window = gtk_widget_get_window(widget);
+
+ gboolean interior_focus;
+ gint focus_width, focus_pad;
+
+ moz_gtk_widget_get_focus(widget, &interior_focus, &focus_width, &focus_pad);
+
+ if (window && gdk_window_is_visible(window)) {
+ gdk_window_set_background_pattern(window, NULL);
+ }
+
+ gtk_widget_set_state(widget, button_state);
+ gtk_widget_set_direction(widget, direction);
+ gtk_button_set_relief(GTK_BUTTON(widget), relief);
+
+ if (!interior_focus && state->focused) {
+ x += focus_width + focus_pad;
+ y += focus_width + focus_pad;
+ width -= 2 * (focus_width + focus_pad);
+ height -= 2 * (focus_width + focus_pad);
+ }
+
+ shadow_type = button_state == GTK_STATE_ACTIVE ||
+ state->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
+
+ if (state->isDefault && relief == GTK_RELIEF_NORMAL) {
+ gtk_paint_box(style, cr, button_state, shadow_type,
+ widget, "buttondefault", x, y, width, height);
+ }
+
+ if (relief != GTK_RELIEF_NONE || state->depressed ||
+ (button_state != GTK_STATE_NORMAL &&
+ button_state != GTK_STATE_INSENSITIVE)) {
+ /* the following line can trigger an assertion (Crux theme)
+ file ../../gdk/gdkwindow.c: line 1846 (gdk_window_clear_area):
+ assertion `GDK_IS_WINDOW (window)' failed */
+ gtk_paint_box(style, cr, button_state, shadow_type,
+ widget, "button", x, y, width, height);
+ }
+
+ if (state->focused) {
+ if (interior_focus) {
+ GtkStyle* style = gtk_widget_get_style(widget);
+ x += style->xthickness + focus_pad;
+ y += style->ythickness + focus_pad;
+ width -= 2 * (style->xthickness + focus_pad);
+ height -= 2 * (style->ythickness + focus_pad);
+ } else {
+ x -= focus_width + focus_pad;
+ y -= focus_width + focus_pad;
+ width += 2 * (focus_width + focus_pad);
+ height += 2 * (focus_width + focus_pad);
+ }
+
+ gtk_paint_focus(style, cr, button_state,
+ widget, "button", x, y, width, height);
+ }
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_init()
+{
+ GtkWidgetClass *entry_class;
+
+ is_initialized = TRUE;
+ have_arrow_scaling = (gtk_major_version > 2 ||
+ (gtk_major_version == 2 && gtk_minor_version >= 12));
+
+ /* Add style property to GtkEntry.
+ * Adding the style property to the normal GtkEntry class means that it
+ * will work without issues inside GtkComboBox and for Spinbuttons. */
+ entry_class = g_type_class_ref(GTK_TYPE_ENTRY);
+ gtk_widget_class_install_style_property(entry_class,
+ g_param_spec_boolean("honors-transparent-bg-hint",
+ "Transparent BG enabling flag",
+ "If TRUE, the theme is able to draw the GtkEntry on non-prefilled background.",
+ FALSE,
+ G_PARAM_READWRITE));
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing)
+{
+ ensure_checkbox_widget();
+
+ gtk_widget_style_get (gParts->checkboxWidget,
+ "indicator_size", indicator_size,
+ "indicator_spacing", indicator_spacing,
+ NULL);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing)
+{
+ ensure_radiobutton_widget();
+
+ gtk_widget_style_get (gParts->radiobuttonWidget,
+ "indicator_size", indicator_size,
+ "indicator_spacing", indicator_spacing,
+ NULL);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_widget_get_focus(GtkWidget* widget, gboolean* interior_focus,
+ gint* focus_width, gint* focus_pad)
+{
+ gtk_widget_style_get (widget,
+ "interior-focus", interior_focus,
+ "focus-line-width", focus_width,
+ "focus-padding", focus_pad,
+ NULL);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_button_get_inner_border(GtkWidget* widget, GtkBorder* inner_border)
+{
+ static const GtkBorder default_inner_border = { 1, 1, 1, 1 };
+ GtkBorder *tmp_border;
+
+ gtk_widget_style_get (widget, "inner-border", &tmp_border, NULL);
+
+ if (tmp_border) {
+ *inner_border = *tmp_border;
+ gtk_border_free(tmp_border);
+ }
+ else
+ *inner_border = default_inner_border;
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_toggle_paint(cairo_t* cr, GdkRectangle* rect,
+ GtkWidgetState* state, gboolean selected,
+ gboolean inconsistent, gboolean isradio,
+ GtkTextDirection direction)
+{
+ GtkStateType state_type = ConvertGtkState(state);
+ GtkShadowType shadow_type = (selected)?GTK_SHADOW_IN:GTK_SHADOW_OUT;
+ gint indicator_size, indicator_spacing;
+ gint x, y, width, height;
+ gint focus_x, focus_y, focus_width, focus_height;
+ GtkWidget *w;
+ GtkStyle *style;
+
+ if (isradio) {
+ moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing);
+ w = gParts->radiobuttonWidget;
+ } else {
+ moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing);
+ w = gParts->checkboxWidget;
+ }
+
+ // "GetMinimumWidgetSize was ignored"
+ // FIXME: This assert causes a build failure in WebKitGTK+ debug
+ // builds, because it uses 'false' in its definition. We may want
+ // to force this file to be built with g++, by renaming it.
+ // ASSERT(rect->width == indicator_size);
+
+ /*
+ * vertically center in the box, since XUL sometimes ignores our
+ * GetMinimumWidgetSize in the vertical dimension
+ */
+ x = rect->x;
+ y = rect->y + (rect->height - indicator_size) / 2;
+ width = indicator_size;
+ height = indicator_size;
+
+ focus_x = x - indicator_spacing;
+ focus_y = y - indicator_spacing;
+ focus_width = width + 2 * indicator_spacing;
+ focus_height = height + 2 * indicator_spacing;
+
+ style = gtk_widget_get_style(w);
+
+ gtk_widget_set_sensitive(w, !state->disabled);
+ gtk_widget_set_direction(w, direction);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), selected);
+
+ if (isradio) {
+ gtk_paint_option(style, cr, state_type, shadow_type,
+ gParts->radiobuttonWidget, "radiobutton", x, y,
+ width, height);
+ if (state->focused) {
+ gtk_paint_focus(style, cr, GTK_STATE_ACTIVE,
+ gParts->radiobuttonWidget, "radiobutton", focus_x, focus_y,
+ focus_width, focus_height);
+ }
+ }
+ else {
+ /*
+ * 'indeterminate' type on checkboxes. In GTK, the shadow type
+ * must also be changed for the state to be drawn.
+ */
+ if (inconsistent) {
+ gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gParts->checkboxWidget), TRUE);
+ shadow_type = GTK_SHADOW_ETCHED_IN;
+ } else {
+ gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gParts->checkboxWidget), FALSE);
+ }
+
+ gtk_paint_check(style, cr, state_type, shadow_type,
+ gParts->checkboxWidget, "checkbutton", x, y, width, height);
+ if (state->focused) {
+ gtk_paint_focus(style, cr, GTK_STATE_ACTIVE,
+ gParts->checkboxWidget, "checkbutton", focus_x, focus_y,
+ focus_width, focus_height);
+ }
+ }
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+calculate_button_inner_rect(GtkWidget* button, GdkRectangle* rect,
+ GdkRectangle* inner_rect,
+ GtkTextDirection direction,
+ gboolean ignore_focus)
+{
+ GtkBorder inner_border;
+ gboolean interior_focus;
+ gint focus_width, focus_pad;
+ GtkStyle* style;
+
+ style = gtk_widget_get_style(button);
+
+ /* This mirrors gtkbutton's child positioning */
+ moz_gtk_button_get_inner_border(button, &inner_border);
+ moz_gtk_widget_get_focus(button, &interior_focus,
+ &focus_width, &focus_pad);
+
+ if (ignore_focus)
+ focus_width = focus_pad = 0;
+
+ inner_rect->x = rect->x + XTHICKNESS(style) + focus_width + focus_pad;
+ inner_rect->x += direction == GTK_TEXT_DIR_LTR ?
+ inner_border.left : inner_border.right;
+ inner_rect->y = rect->y + inner_border.top + YTHICKNESS(style) +
+ focus_width + focus_pad;
+ inner_rect->width = MAX(1, rect->width - inner_border.left -
+ inner_border.right - (XTHICKNESS(style) + focus_pad + focus_width) * 2);
+ inner_rect->height = MAX(1, rect->height - inner_border.top -
+ inner_border.bottom - (YTHICKNESS(style) + focus_pad + focus_width) * 2);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+
+static gint
+calculate_arrow_rect(GtkWidget* arrow, GdkRectangle* rect,
+ GdkRectangle* arrow_rect, GtkTextDirection direction)
+{
+ /* defined in gtkarrow.c */
+ gfloat arrow_scaling = 0.7;
+ gfloat xalign, xpad;
+ gint extent;
+ GtkMisc* misc = GTK_MISC(arrow);
+ gfloat misc_xalign, misc_yalign;
+ gint misc_xpad, misc_ypad;
+
+ if (have_arrow_scaling)
+ gtk_widget_style_get(arrow, "arrow_scaling", &arrow_scaling, NULL);
+
+ gtk_misc_get_padding(misc, &misc_xpad, &misc_ypad);
+ gtk_misc_get_alignment(misc, &misc_xalign, &misc_yalign);
+
+ extent = MIN((rect->width - misc_xpad * 2),
+ (rect->height - misc_ypad * 2)) * arrow_scaling;
+
+ xalign = direction == GTK_TEXT_DIR_LTR ? misc_xalign : 1.0 - misc_xalign;
+ xpad = misc_xpad + (rect->width - extent) * xalign;
+
+ arrow_rect->x = direction == GTK_TEXT_DIR_LTR ?
+ floor(rect->x + xpad) : ceil(rect->x + xpad);
+ arrow_rect->y = floor(rect->y + misc_ypad +
+ ((rect->height - extent) * misc_yalign));
+
+ arrow_rect->width = arrow_rect->height = extent;
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_scrolled_window_paint(cairo_t* cr, GdkRectangle* rect,
+ GtkWidgetState* state)
+{
+ GtkStyle* style;
+ GtkAllocation allocation;
+ GtkWidget* widget;
+
+ ensure_scrolled_window_widget();
+ widget = gParts->scrolledWindowWidget;
+
+ gtk_widget_get_allocation(widget, &allocation);
+ allocation.x = rect->x;
+ allocation.y = rect->y;
+ allocation.width = rect->width;
+ allocation.height = rect->height;
+ gtk_widget_set_allocation(widget, &allocation);
+
+ style = gtk_widget_get_style(widget);
+ gtk_paint_shadow(style, cr, GTK_STATE_NORMAL, GTK_SHADOW_IN,
+ widget, "scrolled_window", rect->x , rect->y,
+ rect->width, rect->height);
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_scrollbar_button_paint(cairo_t* cr, GdkRectangle* rect,
+ GtkWidgetState* state,
+ GtkScrollbarButtonFlags flags,
+ GtkTextDirection direction)
+{
+ GtkStateType state_type = ConvertGtkState(state);
+ GtkShadowType shadow_type = (state->active) ?
+ GTK_SHADOW_IN : GTK_SHADOW_OUT;
+ GdkRectangle arrow_rect;
+ GtkStyle* style;
+ GtkWidget *scrollbar;
+ GtkAllocation allocation;
+ GtkArrowType arrow_type;
+ gint arrow_displacement_x, arrow_displacement_y;
+ const char* detail = (flags & MOZ_GTK_STEPPER_VERTICAL) ?
+ "vscrollbar" : "hscrollbar";
+
+ ensure_scrollbar_widget();
+
+ if (flags & MOZ_GTK_STEPPER_VERTICAL)
+ scrollbar = gParts->vertScrollbarWidget;
+ else
+ scrollbar = gParts->horizScrollbarWidget;
+
+ gtk_widget_set_direction(scrollbar, direction);
+
+ /* Some theme engines (i.e., ClearLooks) check the scrollbar's allocation
+ to determine where it should paint rounded corners on the buttons.
+ We need to trick them into drawing the buttons the way we want them. */
+
+ gtk_widget_get_allocation(scrollbar, &allocation);
+ allocation.x = rect->x;
+ allocation.y = rect->y;
+ allocation.width = rect->width;
+ allocation.height = rect->height;
+
+ if (flags & MOZ_GTK_STEPPER_VERTICAL) {
+ allocation.height *= 5;
+ if (flags & MOZ_GTK_STEPPER_DOWN) {
+ arrow_type = GTK_ARROW_DOWN;
+ if (flags & MOZ_GTK_STEPPER_BOTTOM)
+ allocation.y -= 4 * rect->height;
+ else
+ allocation.y -= rect->height;
+
+ } else {
+ arrow_type = GTK_ARROW_UP;
+ if (flags & MOZ_GTK_STEPPER_BOTTOM)
+ allocation.y -= 3 * rect->height;
+ }
+ } else {
+ allocation.width *= 5;
+ if (flags & MOZ_GTK_STEPPER_DOWN) {
+ arrow_type = GTK_ARROW_RIGHT;
+ if (flags & MOZ_GTK_STEPPER_BOTTOM)
+ allocation.x -= 4 * rect->width;
+ else
+ allocation.x -= rect->width;
+ } else {
+ arrow_type = GTK_ARROW_LEFT;
+ if (flags & MOZ_GTK_STEPPER_BOTTOM)
+ allocation.x -= 3 * rect->width;
+ }
+ }
+
+ gtk_widget_set_allocation(scrollbar, &allocation);
+ style = gtk_widget_get_style(scrollbar);
+
+ gtk_paint_box(style, cr, state_type, shadow_type,
+ scrollbar, detail, rect->x, rect->y,
+ rect->width, rect->height);
+
+ arrow_rect.width = rect->width / 2;
+ arrow_rect.height = rect->height / 2;
+ arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
+ arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2;
+
+ if (state_type == GTK_STATE_ACTIVE) {
+ gtk_widget_style_get(scrollbar,
+ "arrow-displacement-x", &arrow_displacement_x,
+ "arrow-displacement-y", &arrow_displacement_y,
+ NULL);
+
+ arrow_rect.x += arrow_displacement_x;
+ arrow_rect.y += arrow_displacement_y;
+ }
+
+ gtk_paint_arrow(style, cr, state_type, shadow_type,
+ scrollbar, detail, arrow_type, TRUE, arrow_rect.x,
+ arrow_rect.y, arrow_rect.width, arrow_rect.height);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_scrollbar_trough_paint(GtkThemeWidgetType widget,
+ cairo_t* cr, GdkRectangle* rect,
+ GtkWidgetState* state,
+ GtkTextDirection direction)
+{
+ GtkStyle* style;
+ GtkScrollbar *scrollbar;
+
+ ensure_scrollbar_widget();
+
+ if (widget == MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL)
+ scrollbar = GTK_SCROLLBAR(gParts->horizScrollbarWidget);
+ else
+ scrollbar = GTK_SCROLLBAR(gParts->vertScrollbarWidget);
+
+ gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction);
+
+ style = gtk_widget_get_style(GTK_WIDGET(scrollbar));
+
+ gtk_paint_box(style, cr, GTK_STATE_ACTIVE, GTK_SHADOW_IN,
+ GTK_WIDGET(scrollbar), "trough", rect->x, rect->y,
+ rect->width, rect->height);
+
+ if (state->focused) {
+ gtk_paint_focus(style, cr, GTK_STATE_ACTIVE,
+ GTK_WIDGET(scrollbar), "trough",
+ rect->x, rect->y, rect->width, rect->height);
+ }
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget,
+ cairo_t* cr, GdkRectangle* rect,
+ GtkWidgetState* state,
+ GtkTextDirection direction)
+{
+ GtkStateType state_type = (state->inHover || state->active) ?
+ GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
+ GtkShadowType shadow_type = GTK_SHADOW_OUT;
+ GtkStyle* style;
+ GtkScrollbar *scrollbar;
+ GtkAdjustment *adj;
+
+ ensure_scrollbar_widget();
+
+ if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL)
+ scrollbar = GTK_SCROLLBAR(gParts->horizScrollbarWidget);
+ else
+ scrollbar = GTK_SCROLLBAR(gParts->vertScrollbarWidget);
+
+ gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction);
+
+ /* Make sure to set the scrollbar range before painting so that
+ everything is drawn properly. At least the bluecurve (and
+ maybe other) themes don't draw the top or bottom black line
+ surrounding the scrollbar if the theme thinks that it's butted
+ up against the scrollbar arrows. Note the increases of the
+ clip rect below. */
+ adj = gtk_range_get_adjustment(GTK_RANGE(scrollbar));
+
+ if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) {
+ gtk_adjustment_set_page_size(adj, rect->width);
+ }
+ else {
+ gtk_adjustment_set_page_size(adj, rect->height);
+ }
+
+ gtk_adjustment_configure(adj,
+ state->curpos,
+ 0,
+ state->maxpos,
+ gtk_adjustment_get_step_increment(adj),
+ gtk_adjustment_get_page_increment(adj),
+ gtk_adjustment_get_page_size(adj));
+
+ style = gtk_widget_get_style(GTK_WIDGET(scrollbar));
+
+ gtk_paint_slider(style, cr, state_type, shadow_type,
+ GTK_WIDGET(scrollbar), "slider", rect->x, rect->y,
+ rect->width, rect->height,
+ (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) ?
+ GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_entry_paint(cairo_t* cr, GdkRectangle* rect,
+ GtkWidgetState* state, GtkWidget* widget,
+ GtkTextDirection direction)
+{
+ GtkStateType bg_state = state->disabled ?
+ GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL;
+ gint x, y, width = rect->width, height = rect->height;
+ GtkStyle* style;
+ gboolean interior_focus;
+ gboolean theme_honors_transparency = FALSE;
+ gint focus_width;
+
+ gtk_widget_set_direction(widget, direction);
+
+ style = gtk_widget_get_style(widget);
+
+ gtk_widget_style_get(widget,
+ "interior-focus", &interior_focus,
+ "focus-line-width", &focus_width,
+ "honors-transparent-bg-hint", &theme_honors_transparency,
+ NULL);
+
+ /* gtkentry.c uses two windows, one for the entire widget and one for the
+ * text area inside it. The background of both windows is set to the "base"
+ * color of the new state in gtk_entry_state_changed, but only the inner
+ * textarea window uses gtk_paint_flat_box when exposed */
+
+ /* This gets us a lovely greyish disabledish look */
+ gtk_widget_set_sensitive(widget, !state->disabled);
+
+ /* GTK fills the outer widget window with the base color before drawing the widget.
+ * Some older themes rely on this behavior, but many themes nowadays use rounded
+ * corners on their widgets. While most GTK apps are blissfully unaware of this
+ * problem due to their use of the default window background, we render widgets on
+ * many kinds of backgrounds on the web.
+ * If the theme is able to cope with transparency, then we can skip pre-filling
+ * and notify the theme it will paint directly on the canvas. */
+ if (theme_honors_transparency) {
+ g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
+ } else {
+ cairo_save(cr);
+ gdk_cairo_set_source_color(cr, (const GdkColor*)&style->base[bg_state]);
+ cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
+ cairo_fill(cr);
+ cairo_restore(cr);
+ g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(FALSE));
+ }
+
+ /* Get the position of the inner window, see _gtk_entry_get_borders */
+ x = XTHICKNESS(style);
+ y = YTHICKNESS(style);
+
+ if (!interior_focus) {
+ x += focus_width;
+ y += focus_width;
+ }
+
+ /* Simulate an expose of the inner window */
+ gtk_paint_flat_box(style, cr, bg_state, GTK_SHADOW_NONE,
+ widget, "entry_bg", rect->x + x,
+ rect->y + y, rect->width - 2*x, rect->height - 2*y);
+
+ /* Now paint the shadow and focus border.
+ * We do like in gtk_entry_draw_frame, we first draw the shadow, a tad
+ * smaller when focused if the focus is not interior, then the focus. */
+ x = rect->x;
+ y = rect->y;
+
+ if (state->focused && !state->disabled) {
+ /* This will get us the lit borders that focused textboxes enjoy on
+ * some themes. */
+ if (!interior_focus) {
+ /* Indent the border a little bit if we have exterior focus
+ (this is what GTK does to draw native entries) */
+ x += focus_width;
+ y += focus_width;
+ width -= 2 * focus_width;
+ height -= 2 * focus_width;
+ }
+ }
+
+ gtk_paint_shadow(style, cr, GTK_STATE_NORMAL, GTK_SHADOW_IN,
+ widget, "entry", x, y, width, height);
+
+ if (state->focused && !state->disabled) {
+ if (!interior_focus) {
+ gtk_paint_focus(style, cr, GTK_STATE_NORMAL,
+ widget, "entry",
+ rect->x, rect->y, rect->width, rect->height);
+ }
+ }
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_combo_box_paint(cairo_t* cr, GdkRectangle* rect,
+ GtkWidgetState* state, gboolean ishtml,
+ GtkTextDirection direction)
+{
+ GdkRectangle arrow_rect, real_arrow_rect;
+ gint /* arrow_size, */ separator_width;
+ gboolean wide_separators;
+ GtkStateType state_type = ConvertGtkState(state);
+ GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
+ GtkStyle* style;
+ GtkRequisition arrow_req;
+
+ ensure_combo_box_widgets();
+
+ /* Also sets the direction on gParts->comboBoxButtonWidget, which is then
+ * inherited by the separator and arrow */
+ moz_gtk_button_paint(cr, rect, state, GTK_RELIEF_NORMAL,
+ gParts->comboBoxButtonWidget, direction);
+
+ calculate_button_inner_rect(gParts->comboBoxButtonWidget,
+ rect, &arrow_rect, direction, ishtml);
+ /* Now arrow_rect contains the inner rect ; we want to correct the width
+ * to what the arrow needs (see gtk_combo_box_size_allocate) */
+ gtk_widget_get_preferred_size(gParts->comboBoxArrowWidget, &arrow_req, NULL);
+ if (direction == GTK_TEXT_DIR_LTR)
+ arrow_rect.x += arrow_rect.width - arrow_req.width;
+ arrow_rect.width = arrow_req.width;
+
+ calculate_arrow_rect(gParts->comboBoxArrowWidget,
+ &arrow_rect, &real_arrow_rect, direction);
+
+ style = gtk_widget_get_style(gParts->comboBoxArrowWidget);
+
+ gtk_widget_size_allocate(gParts->comboBoxWidget, rect);
+
+ gtk_paint_arrow(style, cr, state_type, shadow_type,
+ gParts->comboBoxArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE,
+ real_arrow_rect.x, real_arrow_rect.y,
+ real_arrow_rect.width, real_arrow_rect.height);
+
+
+ /* If there is no separator in the theme, there's nothing left to do. */
+ if (!gParts->comboBoxSeparatorWidget)
+ return MOZ_GTK_SUCCESS;
+
+ style = gtk_widget_get_style(gParts->comboBoxSeparatorWidget);
+
+ gtk_widget_style_get(gParts->comboBoxSeparatorWidget,
+ "wide-separators", &wide_separators,
+ "separator-width", &separator_width,
+ NULL);
+
+ if (wide_separators) {
+ if (direction == GTK_TEXT_DIR_LTR)
+ arrow_rect.x -= separator_width;
+ else
+ arrow_rect.x += arrow_rect.width;
+
+ gtk_paint_box(style, cr,
+ GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT,
+ gParts->comboBoxSeparatorWidget, "vseparator",
+ arrow_rect.x, arrow_rect.y,
+ separator_width, arrow_rect.height);
+ } else {
+ if (direction == GTK_TEXT_DIR_LTR)
+ arrow_rect.x -= XTHICKNESS(style);
+ else
+ arrow_rect.x += arrow_rect.width;
+
+ gtk_paint_vline(style, cr, GTK_STATE_NORMAL,
+ gParts->comboBoxSeparatorWidget, "vseparator",
+ arrow_rect.y, arrow_rect.y + arrow_rect.height,
+ arrow_rect.x);
+ }
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_progressbar_paint(cairo_t* cr, GdkRectangle* rect,
+ GtkTextDirection direction)
+{
+ GtkStyle* style;
+
+ ensure_progress_widget();
+ gtk_widget_set_direction(gParts->progresWidget, direction);
+
+ style = gtk_widget_get_style(gParts->progresWidget);
+
+ gtk_paint_box(style, cr, GTK_STATE_NORMAL, GTK_SHADOW_IN,
+ gParts->progresWidget, "trough", rect->x, rect->y,
+ rect->width, rect->height);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+static gint
+moz_gtk_progress_chunk_paint(cairo_t* cr, GdkRectangle* rect,
+ GtkTextDirection direction)
+{
+ GtkStyle* style;
+
+ ensure_progress_widget();
+ gtk_widget_set_direction(gParts->progresWidget, direction);
+
+ style = gtk_widget_get_style(gParts->progresWidget);
+
+ gtk_paint_box(style, cr, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
+ gParts->progresWidget, "bar", rect->x, rect->y,
+ rect->width, rect->height);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
+ gint* right, gint* bottom, GtkTextDirection direction,
+ gboolean inhtml)
+{
+ GtkWidget* w;
+ GtkStyle *style;
+
+ switch (widget) {
+ case MOZ_GTK_BUTTON:
+ {
+ GtkBorder inner_border;
+ gboolean interior_focus;
+ gint focus_width, focus_pad;
+ GtkStyle *style;
+
+ ensure_button_widget();
+ *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(gParts->buttonWidget));
+
+ /* Don't add this padding in HTML, otherwise the buttons will
+ become too big and stuff the layout. */
+ if (!inhtml) {
+ moz_gtk_widget_get_focus(gParts->buttonWidget, &interior_focus, &focus_width, &focus_pad);
+ moz_gtk_button_get_inner_border(gParts->buttonWidget, &inner_border);
+ *left += focus_width + focus_pad + inner_border.left;
+ *right += focus_width + focus_pad + inner_border.right;
+ *top += focus_width + focus_pad + inner_border.top;
+ *bottom += focus_width + focus_pad + inner_border.bottom;
+ }
+
+ style = gtk_widget_get_style(gParts->buttonWidget);
+ *left += style->xthickness;
+ *right += style->xthickness;
+ *top += style->ythickness;
+ *bottom += style->ythickness;
+ return MOZ_GTK_SUCCESS;
+ }
+ case MOZ_GTK_ENTRY:
+ ensure_entry_widget();
+ w = gParts->entryWidget;
+ break;
+ case MOZ_GTK_DROPDOWN:
+ {
+ /* We need to account for the arrow on the dropdown, so text
+ * doesn't come too close to the arrow, or in some cases spill
+ * into the arrow. */
+ gboolean ignored_interior_focus, wide_separators;
+ gint focus_width, focus_pad, separator_width;
+ GtkRequisition arrow_req;
+ GtkStyle* style;
+
+ ensure_combo_box_widgets();
+
+ *left = gtk_container_get_border_width(GTK_CONTAINER(gParts->comboBoxButtonWidget));
+
+ if (!inhtml) {
+ moz_gtk_widget_get_focus(gParts->comboBoxButtonWidget,
+ &ignored_interior_focus,
+ &focus_width, &focus_pad);
+ *left += focus_width + focus_pad;
+ }
+
+ style = gtk_widget_get_style(gParts->comboBoxButtonWidget);
+ *top = *left + style->ythickness;
+ *left += style->xthickness;
+
+ *right = *left; *bottom = *top;
+
+ /* If there is no separator, don't try to count its width. */
+ separator_width = 0;
+ if (gParts->comboBoxSeparatorWidget) {
+ gtk_widget_style_get(gParts->comboBoxSeparatorWidget,
+ "wide-separators", &wide_separators,
+ "separator-width", &separator_width,
+ NULL);
+
+ if (!wide_separators)
+ separator_width =
+ XTHICKNESS(style);
+ }
+
+ gtk_widget_get_preferred_size(gParts->comboBoxArrowWidget, &arrow_req, NULL);
+ if (direction == GTK_TEXT_DIR_RTL)
+ *left += separator_width + arrow_req.width;
+ else
+ *right += separator_width + arrow_req.width;
+
+ return MOZ_GTK_SUCCESS;
+ }
+ case MOZ_GTK_PROGRESSBAR:
+ ensure_progress_widget();
+ w = gParts->progresWidget;
+ break;
+ /* These widgets have no borders, since they are not containers. */
+ case MOZ_GTK_CHECKBUTTON:
+ case MOZ_GTK_RADIOBUTTON:
+ case MOZ_GTK_SCROLLBAR_BUTTON:
+ case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL:
+ case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL:
+ case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
+ case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
+ case MOZ_GTK_PROGRESS_CHUNK:
+ *left = *top = *right = *bottom = 0;
+ return MOZ_GTK_SUCCESS;
+ default:
+ g_warning("Unsupported widget type: %d", widget);
+ return MOZ_GTK_UNKNOWN_WIDGET;
+ }
+
+ style = gtk_widget_get_style(w);
+ *right = *left = XTHICKNESS(style);
+ *bottom = *top = YTHICKNESS(style);
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics)
+{
+ ensure_scrollbar_widget();
+
+ gtk_widget_style_get (gParts->horizScrollbarWidget,
+ "slider_width", &metrics->slider_width,
+ "trough_border", &metrics->trough_border,
+ "stepper_size", &metrics->stepper_size,
+ "stepper_spacing", &metrics->stepper_spacing,
+ "trough_under_steppers", &metrics->trough_under_steppers,
+ "has_secondary_forward_stepper", &metrics->has_secondary_forward_stepper,
+ "has_secondary_backward_stepper", &metrics->has_secondary_backward_stepper,
+ NULL);
+
+ metrics->min_slider_size = gtk_range_get_min_slider_size(GTK_RANGE(gParts->horizScrollbarWidget));
+
+ return MOZ_GTK_SUCCESS;
+}
+
+gint
+moz_gtk_widget_paint(GtkThemeWidgetType widget, cairo_t* cr,
+ GdkRectangle* rect, GtkWidgetState* state,
+ gint flags, GtkTextDirection direction)
+{
+ switch (widget) {
+ case MOZ_GTK_BUTTON:
+ if (state->depressed) {
+ ensure_toggle_button_widget();
+ return moz_gtk_button_paint(cr, rect, state,
+ (GtkReliefStyle) flags,
+ gParts->toggleButtonWidget, direction);
+ }
+ ensure_button_widget();
+ return moz_gtk_button_paint(cr, rect, state,
+ (GtkReliefStyle) flags, gParts->buttonWidget,
+ direction);
+ break;
+ case MOZ_GTK_CHECKBUTTON:
+ case MOZ_GTK_RADIOBUTTON:
+ return moz_gtk_toggle_paint(cr, rect, state,
+ !!(flags & MOZ_GTK_WIDGET_CHECKED),
+ !!(flags & MOZ_GTK_WIDGET_INCONSISTENT),
+ (widget == MOZ_GTK_RADIOBUTTON),
+ direction);
+ break;
+ case MOZ_GTK_SCROLLBAR_BUTTON:
+ return moz_gtk_scrollbar_button_paint(cr, rect, state,
+ (GtkScrollbarButtonFlags) flags,
+ direction);
+ break;
+ case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL:
+ case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL:
+ return moz_gtk_scrollbar_trough_paint(widget, cr, rect,
+ state, direction);
+ break;
+ case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
+ case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
+ return moz_gtk_scrollbar_thumb_paint(widget, cr, rect,
+ state, direction);
+ break;
+ case MOZ_GTK_SCROLLED_WINDOW:
+ return moz_gtk_scrolled_window_paint(cr, rect, state);
+ break;
+ case MOZ_GTK_ENTRY:
+ ensure_entry_widget();
+ return moz_gtk_entry_paint(cr, rect, state,
+ gParts->entryWidget, direction);
+ break;
+ case MOZ_GTK_DROPDOWN:
+ return moz_gtk_combo_box_paint(cr, rect, state,
+ (gboolean) flags, direction);
+ break;
+ case MOZ_GTK_PROGRESSBAR:
+ return moz_gtk_progressbar_paint(cr, rect, direction);
+ break;
+ case MOZ_GTK_PROGRESS_CHUNK:
+ return moz_gtk_progress_chunk_paint(cr, rect, direction);
+ break;
+ default:
+ g_warning("Unknown widget type: %d", widget);
+ }
+
+ return MOZ_GTK_UNKNOWN_WIDGET;
+}
+
+GtkWidget* moz_gtk_get_scrollbar_widget(void)
+{
+ if (!is_initialized)
+ return NULL;
+ ensure_scrollbar_widget();
+ return gParts->horizScrollbarWidget;
+}
+
+gint
+moz_gtk_shutdown()
+{
+ GtkWidgetClass *entry_class;
+ entry_class = g_type_class_peek(GTK_TYPE_ENTRY);
+ g_type_class_unref(entry_class);
+
+ is_initialized = FALSE;
+
+ return MOZ_GTK_SUCCESS;
+}
+
+void moz_gtk_destroy_theme_parts_widgets(GtkThemeParts* parts)
+{
+ if (!parts)
+ return;
+
+ if (parts->protoWindow) {
+ gtk_widget_destroy(parts->protoWindow);
+ parts->protoWindow = NULL;
+ }
+}
+
+GtkWidget* moz_gtk_get_progress_widget()
+{
+ if (!is_initialized)
+ return NULL;
+ ensure_progress_widget();
+ return gParts->progresWidget;
+}
+
+#endif // GTK_API_VERSION_2
diff --git a/Source/WebCore/platform/gtk/gtkdrawing.h b/Source/WebCore/platform/gtk/gtkdrawing.h
new file mode 100644
index 0000000..9d13a07
--- /dev/null
+++ b/Source/WebCore/platform/gtk/gtkdrawing.h
@@ -0,0 +1,296 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Brian Ryner <bryner@brianryner.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * gtkdrawing.h: GTK widget rendering utilities
+ *
+ * gtkdrawing provides an API for rendering GTK widgets in the
+ * current theme to a pixmap or window, without requiring an actual
+ * widget instantiation, similar to the Macintosh Appearance Manager
+ * or Windows XP's DrawThemeBackground() API.
+ */
+
+#ifndef _GTK_DRAWING_H_
+#define _GTK_DRAWING_H_
+
+#include <gtk/gtk.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*** type definitions ***/
+typedef struct {
+ guint8 active;
+ guint8 focused;
+ guint8 inHover;
+ guint8 disabled;
+ guint8 isDefault;
+ guint8 canDefault;
+ /* The depressed state is for buttons which remain active for a longer period:
+ * activated toggle buttons or buttons showing a popup menu. */
+ guint8 depressed;
+ gint32 curpos; /* curpos and maxpos are used for scrollbars */
+ gint32 maxpos;
+} GtkWidgetState;
+
+typedef struct {
+ gint slider_width;
+ gint trough_border;
+ gint stepper_size;
+ gint stepper_spacing;
+ gint min_slider_size;
+ gboolean trough_under_steppers;
+ gboolean has_secondary_forward_stepper;
+ gboolean has_secondary_backward_stepper;
+} MozGtkScrollbarMetrics;
+
+typedef struct _GtkThemeParts {
+#ifdef GTK_API_VERSION_2
+ GdkColormap* colormap;
+#endif // GTK_API_VERSION_2
+ GtkWidget* protoWindow;
+ GtkWidget* protoLayout;
+ GtkWidget* buttonWidget;
+ GtkWidget* toggleButtonWidget;
+ GtkWidget* buttonArrowWidget;
+ GtkWidget* checkboxWidget;
+ GtkWidget* radiobuttonWidget;
+ GtkWidget* horizScrollbarWidget;
+ GtkWidget* vertScrollbarWidget;
+ GtkWidget* entryWidget;
+ GtkWidget* comboBoxWidget;
+ GtkWidget* comboBoxButtonWidget;
+ GtkWidget* comboBoxArrowWidget;
+ GtkWidget* comboBoxSeparatorWidget;
+ GtkWidget* comboBoxEntryWidget;
+ GtkWidget* comboBoxEntryTextareaWidget;
+ GtkWidget* comboBoxEntryButtonWidget;
+ GtkWidget* comboBoxEntryArrowWidget;
+ GtkWidget* progresWidget;
+ GtkWidget* scrolledWindowWidget;
+} GtkThemeParts;
+
+typedef enum {
+ MOZ_GTK_STEPPER_DOWN = 1 << 0,
+ MOZ_GTK_STEPPER_BOTTOM = 1 << 1,
+ MOZ_GTK_STEPPER_VERTICAL = 1 << 2
+} GtkScrollbarButtonFlags;
+
+/* function type for moz_gtk_enable_style_props */
+typedef gint (*style_prop_t)(GtkStyle*, const gchar*, gint);
+
+/*** result/error codes ***/
+#define MOZ_GTK_SUCCESS 0
+#define MOZ_GTK_UNKNOWN_WIDGET -1
+#define MOZ_GTK_UNSAFE_THEME -2
+
+/*** checkbox/radio flags ***/
+#define MOZ_GTK_WIDGET_CHECKED 1
+#define MOZ_GTK_WIDGET_INCONSISTENT (1 << 1)
+
+/*** widget type constants ***/
+typedef enum {
+ /* Paints a GtkButton. flags is a GtkReliefStyle. */
+ MOZ_GTK_BUTTON,
+ /* Paints a GtkCheckButton. flags is a boolean, 1=checked, 0=not checked. */
+ MOZ_GTK_CHECKBUTTON,
+ /* Paints a GtkRadioButton. flags is a boolean, 1=checked, 0=not checked. */
+ MOZ_GTK_RADIOBUTTON,
+ /**
+ * Paints the button of a GtkScrollbar. flags is a GtkArrowType giving
+ * the arrow direction.
+ */
+ MOZ_GTK_SCROLLBAR_BUTTON,
+ /* Paints the trough (track) of a GtkScrollbar. */
+ MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL,
+ MOZ_GTK_SCROLLBAR_TRACK_VERTICAL,
+ /* Paints the slider (thumb) of a GtkScrollbar. */
+ MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL,
+ MOZ_GTK_SCROLLBAR_THUMB_VERTICAL,
+ /* Paints the background of a scrolled window */
+ MOZ_GTK_SCROLLED_WINDOW,
+ MOZ_GTK_ENTRY,
+ /* Paints a GtkOptionMenu. */
+ MOZ_GTK_DROPDOWN,
+ /* Paints a GtkProgressBar. */
+ MOZ_GTK_PROGRESSBAR,
+ /* Paints a progress chunk of a GtkProgressBar. */
+ MOZ_GTK_PROGRESS_CHUNK
+} GtkThemeWidgetType;
+
+/*** General library functions ***/
+/**
+ * Initializes the drawing library. You must call this function
+ * prior to using any other functionality.
+ * returns: MOZ_GTK_SUCCESS if there were no errors
+ * MOZ_GTK_UNSAFE_THEME if the current theme engine is known
+ * to crash with gtkdrawing.
+ */
+gint moz_gtk_init();
+
+/**
+ * Instruct the drawing library to do all rendering based on
+ * the given collection of theme parts. If any members of the
+ * GtkThemeParts struct are NULL, they will be created lazily.
+ */
+void
+moz_gtk_use_theme_parts(GtkThemeParts* parts);
+
+/**
+ * Enable GTK+ 1.2.9+ theme enhancements. You must provide a pointer
+ * to the GTK+ 1.2.9+ function "gtk_style_get_prop_experimental".
+ * styleGetProp: pointer to gtk_style_get_prop_experimental
+ *
+ * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
+ */
+gint moz_gtk_enable_style_props(style_prop_t styleGetProp);
+
+/**
+ * Perform cleanup of the drawing library. You should call this function
+ * when your program exits, or you no longer need the library.
+ *
+ * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
+ */
+gint moz_gtk_shutdown();
+
+/**
+ * Destroy the widgets in the given GtkThemeParts, which should
+ * be destroyed before the GtkThemeParts can be freed.
+ */
+void moz_gtk_destroy_theme_parts_widgets(GtkThemeParts* parts);
+
+/*** Widget drawing ***/
+/**
+ * Paint a widget in the current theme.
+ * widget: a constant giving the widget to paint
+ * rect: the bounding rectangle for the widget
+ * cliprect: a clipprect rectangle for this painting operation
+ * state: the state of the widget. ignored for some widgets.
+ * flags: widget-dependant flags; see the GtkThemeWidgetType definition.
+ * direction: the text direction, to draw the widget correctly LTR and RTL.
+ */
+#ifdef GTK_API_VERSION_2
+gint
+moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable,
+ GdkRectangle* rect, GdkRectangle* cliprect,
+ GtkWidgetState* state, gint flags,
+ GtkTextDirection direction);
+#else
+gint
+moz_gtk_widget_paint(GtkThemeWidgetType widget, cairo_t* cr,
+ GdkRectangle* rect, GtkWidgetState* state,
+ gint flags, GtkTextDirection direction);
+#endif
+
+/*** Widget metrics ***/
+/**
+ * Get the border size of a widget
+ * left/right: [OUT] the widget's left/right border
+ * top/bottom: [OUT] the widget's top/bottom border
+ * direction: the text direction for the widget
+ * inhtml: boolean indicating whether this widget will be drawn as a HTML form control,
+ * in order to workaround a size issue (MOZ_GTK_BUTTON only, ignored otherwise)
+ *
+ * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
+ */
+gint moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
+ gint* right, gint* bottom, GtkTextDirection direction,
+ gboolean inhtml);
+
+/**
+ * Get the desired size of a GtkCheckButton
+ * indicator_size: [OUT] the indicator size
+ * indicator_spacing: [OUT] the spacing between the indicator and its
+ * container
+ *
+ * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
+ */
+gint
+moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing);
+
+/**
+ * Get the desired size of a GtkRadioButton
+ * indicator_size: [OUT] the indicator size
+ * indicator_spacing: [OUT] the spacing between the indicator and its
+ * container
+ *
+ * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
+ */
+gint
+moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing);
+
+/** Get the focus metrics for a treeheadercell, button, checkbox, or radio button.
+ * widget: [IN] the widget to get the focus metrics for
+ * interior_focus: [OUT] whether the focus is drawn around the
+ * label (TRUE) or around the whole container (FALSE)
+ * focus_width: [OUT] the width of the focus line
+ * focus_pad: [OUT] the padding between the focus line and children
+ *
+ * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
+ */
+gint
+moz_gtk_widget_get_focus(GtkWidget* widget, gboolean* interior_focus,
+ gint* focus_width, gint* focus_pad);
+
+/**
+ * Get the desired metrics for a GtkScrollbar
+ * metrics: [IN] struct which will contain the metrics
+ *
+ * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
+ */
+gint
+moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics* metrics);
+
+/**
+ * Retrieve an actual GTK scrollbar widget for style analysis. It will not
+ * be modified.
+ */
+GtkWidget* moz_gtk_get_scrollbar_widget(void);
+
+/**
+ * Retrieve an actual GTK progress bar widget for style analysis. It will not
+ * be modified.
+ */
+GtkWidget* moz_gtk_get_progress_widget(void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif