summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/win
diff options
context:
space:
mode:
authorUpstream <upstream-import@none>1970-01-12 13:46:40 +0000
committerUpstream <upstream-import@none>1970-01-12 13:46:40 +0000
commitd8543bb6618c17b12da906afa77d216f58cf4058 (patch)
treec58dc05ed86825bd0ef8d305d58c8205106b540f /WebCore/platform/win
downloadexternal_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.zip
external_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.tar.gz
external_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.tar.bz2
external/webkit r30707
Diffstat (limited to 'WebCore/platform/win')
-rw-r--r--WebCore/platform/win/BString.cpp191
-rw-r--r--WebCore/platform/win/BString.h77
-rw-r--r--WebCore/platform/win/COMPtr.h230
-rw-r--r--WebCore/platform/win/ClipboardUtilitiesWin.cpp452
-rw-r--r--WebCore/platform/win/ClipboardUtilitiesWin.h70
-rw-r--r--WebCore/platform/win/ClipboardWin.cpp767
-rw-r--r--WebCore/platform/win/ClipboardWin.h79
-rw-r--r--WebCore/platform/win/ContextMenuItemWin.cpp193
-rw-r--r--WebCore/platform/win/ContextMenuWin.cpp157
-rw-r--r--WebCore/platform/win/CursorWin.cpp349
-rw-r--r--WebCore/platform/win/DragDataWin.cpp151
-rw-r--r--WebCore/platform/win/DragImageCGWin.cpp166
-rw-r--r--WebCore/platform/win/DragImageCairoWin.cpp53
-rw-r--r--WebCore/platform/win/DragImageWin.cpp65
-rw-r--r--WebCore/platform/win/EditorWin.cpp51
-rw-r--r--WebCore/platform/win/FileChooserWin.cpp105
-rw-r--r--WebCore/platform/win/FileSystemWin.cpp268
-rw-r--r--WebCore/platform/win/GDIObjectCounter.cpp74
-rw-r--r--WebCore/platform/win/GDIObjectCounter.h63
-rw-r--r--WebCore/platform/win/KeyEventWin.cpp216
-rw-r--r--WebCore/platform/win/Language.cpp68
-rw-r--r--WebCore/platform/win/MIMETypeRegistryWin.cpp122
-rw-r--r--WebCore/platform/win/MainThreadWin.cpp123
-rw-r--r--WebCore/platform/win/PasteboardWin.cpp327
-rw-r--r--WebCore/platform/win/PlatformMouseEventWin.cpp122
-rw-r--r--WebCore/platform/win/PlatformScreenWin.cpp93
-rw-r--r--WebCore/platform/win/PlatformScrollBar.h114
-rw-r--r--WebCore/platform/win/PlatformScrollBarSafari.cpp660
-rw-r--r--WebCore/platform/win/PlatformScrollBarWin.cpp772
-rw-r--r--WebCore/platform/win/PopupMenuWin.cpp826
-rw-r--r--WebCore/platform/win/ScrollViewWin.cpp858
-rw-r--r--WebCore/platform/win/SearchPopupMenuWin.cpp83
-rw-r--r--WebCore/platform/win/SharedBufferWin.cpp68
-rw-r--r--WebCore/platform/win/SharedTimerWin.cpp158
-rw-r--r--WebCore/platform/win/SoftLinking.h62
-rw-r--r--WebCore/platform/win/SoundWin.cpp36
-rw-r--r--WebCore/platform/win/SystemTimeWin.cpp64
-rw-r--r--WebCore/platform/win/TemporaryLinkStubs.cpp38
-rw-r--r--WebCore/platform/win/WCDataObject.cpp381
-rw-r--r--WebCore/platform/win/WCDataObject.h70
-rw-r--r--WebCore/platform/win/WebCoreHistory.cpp47
-rw-r--r--WebCore/platform/win/WebCoreHistory.h46
-rw-r--r--WebCore/platform/win/WebCoreTextRenderer.cpp106
-rw-r--r--WebCore/platform/win/WebCoreTextRenderer.h38
-rw-r--r--WebCore/platform/win/WheelEventWin.cpp71
-rw-r--r--WebCore/platform/win/WidgetWin.cpp255
-rw-r--r--WebCore/platform/win/WindowMessageBroadcaster.cpp132
-rw-r--r--WebCore/platform/win/WindowMessageBroadcaster.h69
-rw-r--r--WebCore/platform/win/WindowMessageListener.h46
49 files changed, 9632 insertions, 0 deletions
diff --git a/WebCore/platform/win/BString.cpp b/WebCore/platform/win/BString.cpp
new file mode 100644
index 0000000..7d08248
--- /dev/null
+++ b/WebCore/platform/win/BString.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2006, 2007, 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 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 "BString.h"
+
+#include "AtomicString.h"
+#include "KURL.h"
+#include "PlatformString.h"
+#include <tchar.h>
+#include <windows.h>
+
+#if PLATFORM(CF)
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+namespace WebCore {
+
+BString::BString()
+ : m_bstr(0)
+{
+}
+
+BString::BString(const wchar_t* characters)
+{
+ if (!characters)
+ m_bstr = 0;
+ else
+ m_bstr = SysAllocString(characters);
+}
+
+BString::BString(const wchar_t* characters, size_t length)
+{
+ if (!characters)
+ m_bstr = 0;
+ else
+ m_bstr = SysAllocStringLen(characters, length);
+}
+
+BString::BString(const String& s)
+{
+ if (s.isNull())
+ m_bstr = 0;
+ else
+ m_bstr = SysAllocStringLen(s.characters(), s.length());
+}
+
+BString::BString(const KURL& url)
+{
+ if (url.isNull())
+ m_bstr = 0;
+ else
+ m_bstr = SysAllocStringLen(url.string().characters(), url.string().length());
+}
+
+BString::BString(const AtomicString& s)
+{
+ if (s.isNull())
+ m_bstr = 0;
+ else
+ m_bstr = SysAllocStringLen(s.characters(), s.length());
+}
+
+#if PLATFORM(CF)
+BString::BString(CFStringRef cfstr)
+ : m_bstr(0)
+{
+ if (!cfstr)
+ return;
+
+ const UniChar* uniChars = CFStringGetCharactersPtr(cfstr);
+ if (uniChars) {
+ m_bstr = SysAllocStringLen((LPCTSTR)uniChars, CFStringGetLength(cfstr));
+ return;
+ }
+
+ CFIndex length = CFStringGetLength(cfstr);
+ m_bstr = SysAllocStringLen(0, length);
+ CFStringGetCharacters(cfstr, CFRangeMake(0, length), (UniChar*)m_bstr);
+ m_bstr[length] = 0;
+}
+#endif
+
+BString::~BString()
+{
+ SysFreeString(m_bstr);
+}
+
+BString::BString(const BString& other)
+{
+ if (!other.m_bstr)
+ m_bstr = 0;
+ else
+ m_bstr = SysAllocString(other.m_bstr);
+}
+
+void BString::adoptBSTR(BSTR bstr)
+{
+ if (m_bstr)
+ SysFreeString(m_bstr);
+ m_bstr = bstr;
+}
+
+BString& BString::operator=(const BString& other)
+{
+ if (this != &other)
+ *this = other.m_bstr;
+ return *this;
+}
+
+BString& BString::operator=(const BSTR& other)
+{
+ if (other != m_bstr) {
+ SysFreeString(m_bstr);
+ m_bstr = other ? SysAllocString(other) : 0;
+ }
+
+ return *this;
+}
+
+bool operator ==(const BString& a, const BString& b)
+{
+ if (SysStringLen((BSTR)a) != SysStringLen((BSTR)b))
+ return false;
+ if (!(BSTR)a && !(BSTR)b)
+ return true;
+ if (!(BSTR)a || !(BSTR)b)
+ return false;
+ return !_tcscmp((BSTR)a, (BSTR)b);
+}
+
+bool operator !=(const BString& a, const BString& b)
+{
+ return !(a==b);
+}
+
+bool operator ==(const BString& a, BSTR b)
+{
+ if (SysStringLen((BSTR)a) != SysStringLen(b))
+ return false;
+ if (!(BSTR)a && !b)
+ return true;
+ if (!(BSTR)a || !b)
+ return false;
+ return !_tcscmp((BSTR)a, b);
+}
+
+bool operator !=(const BString& a, BSTR b)
+{
+ return !(a==b);
+}
+
+bool operator ==(BSTR a, const BString& b)
+{
+ if (SysStringLen(a) != SysStringLen((BSTR)b))
+ return false;
+ if (!a && !(BSTR)b)
+ return true;
+ if (!a || !(BSTR)b)
+ return false;
+ return !_tcscmp(a, (BSTR)b);
+}
+
+bool operator !=(BSTR a, const BString& b)
+{
+ return !(a==b);
+}
+
+}
diff --git a/WebCore/platform/win/BString.h b/WebCore/platform/win/BString.h
new file mode 100644
index 0000000..5269491
--- /dev/null
+++ b/WebCore/platform/win/BString.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2006, 2007, 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 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 BString_h
+#define BString_h
+
+#if PLATFORM(CF)
+typedef const struct __CFString * CFStringRef;
+#endif
+
+typedef wchar_t* BSTR;
+
+namespace WebCore {
+
+ class AtomicString;
+ class KURL;
+ class String;
+
+ class BString {
+ public:
+ BString();
+ BString(const wchar_t*);
+ BString(const wchar_t*, size_t length);
+ BString(const String&);
+ BString(const AtomicString&);
+ BString(const KURL&);
+#if PLATFORM(CF)
+ BString(CFStringRef);
+#endif
+ ~BString();
+
+ void adoptBSTR(BSTR);
+
+ BString(const BString&);
+ BString& operator=(const BString&);
+ BString& operator=(const BSTR&);
+
+ operator BSTR() const { return m_bstr; }
+
+ BSTR release() { BSTR result = m_bstr; m_bstr = 0; return result; }
+
+ private:
+ BSTR m_bstr;
+ };
+
+ bool operator ==(const BString&, const BString&);
+ bool operator !=(const BString&, const BString&);
+ bool operator ==(const BString&, BSTR);
+ bool operator !=(const BString&, BSTR);
+ bool operator ==(BSTR, const BString&);
+ bool operator !=(BSTR, const BString&);
+
+}
+
+#endif
diff --git a/WebCore/platform/win/COMPtr.h b/WebCore/platform/win/COMPtr.h
new file mode 100644
index 0000000..4fb6fbb
--- /dev/null
+++ b/WebCore/platform/win/COMPtr.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2007 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 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 COMPtr_h
+#define COMPtr_h
+
+#define NOMINMAX
+
+#include <guiddef.h>
+#include <unknwn.h>
+#include <WTF/Assertions.h>
+#include <WTF/HashTraits.h>
+
+typedef long HRESULT;
+
+// FIXME: Should we put this into the WebCore namespace and use "using" on it
+// as we do with things in WTF?
+
+enum AdoptCOMTag { AdoptCOM };
+enum QueryTag { Query };
+enum CreateTag { Create };
+
+template <typename T> class COMPtr {
+public:
+ COMPtr() : m_ptr(0) { }
+ COMPtr(T* ptr) : m_ptr(ptr) { if (m_ptr) m_ptr->AddRef(); }
+ COMPtr(AdoptCOMTag, T* ptr) : m_ptr(ptr) { }
+ COMPtr(const COMPtr& o) : m_ptr(o.m_ptr) { if (T* ptr = m_ptr) ptr->AddRef(); }
+
+ inline COMPtr(QueryTag, IUnknown* ptr) : m_ptr(copyQueryInterfaceRef(ptr)) { }
+ template <typename U> inline COMPtr(QueryTag, const COMPtr<U>& ptr) : m_ptr(copyQueryInterfaceRef(ptr.get())) { }
+
+ inline COMPtr(CreateTag, const IID& clsid) : m_ptr(createInstance(clsid)) { }
+
+ ~COMPtr() { if (m_ptr) m_ptr->Release(); }
+
+ T* get() const { return m_ptr; }
+ T* releaseRef() { T* tmp = m_ptr; m_ptr = 0; return tmp; }
+
+ T& operator*() const { return *m_ptr; }
+ T* operator->() const { return m_ptr; }
+
+ T** operator&() { ASSERT(!m_ptr); return &m_ptr; }
+
+ bool operator!() const { return !m_ptr; }
+
+ // This conversion operator allows implicit conversion to bool but not to other integer types.
+ typedef T* (COMPtr::*UnspecifiedBoolType)() const;
+ operator UnspecifiedBoolType() const { return m_ptr ? &COMPtr::get : 0; }
+
+ COMPtr& operator=(const COMPtr&);
+ COMPtr& operator=(T*);
+ template <typename U> COMPtr& operator=(const COMPtr<U>&);
+
+ void query(IUnknown* ptr) { adoptRef(copyQueryInterfaceRef(ptr)); }
+ template <typename U> inline void query(const COMPtr<U>& ptr) { query(ptr.get()); }
+
+ void create(const IID& clsid) { adoptRef(createInstance(clsid)); }
+
+ template <typename U> HRESULT copyRefTo(U**);
+ void adoptRef(T*);
+
+private:
+ static T* copyQueryInterfaceRef(IUnknown*);
+ static T* createInstance(const IID& clsid);
+
+ T* m_ptr;
+};
+
+template <typename T> inline T* COMPtr<T>::createInstance(const IID& clsid)
+{
+ T* result;
+ if (FAILED(CoCreateInstance(clsid, 0, CLSCTX_ALL, __uuidof(result), reinterpret_cast<void**>(&result))))
+ return 0;
+ return result;
+}
+
+template <typename T> inline T* COMPtr<T>::copyQueryInterfaceRef(IUnknown* ptr)
+{
+ if (!ptr)
+ return 0;
+ T* result;
+ if (FAILED(ptr->QueryInterface(&result)))
+ return 0;
+ return result;
+}
+
+template <typename T> template <typename U> inline HRESULT COMPtr<T>::copyRefTo(U** ptr)
+{
+ if (!ptr)
+ return E_POINTER;
+ *ptr = m_ptr;
+ if (m_ptr)
+ m_ptr->AddRef();
+ return S_OK;
+}
+
+template <typename T> inline void COMPtr<T>::adoptRef(T *ptr)
+{
+ if (m_ptr)
+ m_ptr->Release();
+ m_ptr = ptr;
+}
+
+template <typename T> inline COMPtr<T>& COMPtr<T>::operator=(const COMPtr<T>& o)
+{
+ T* optr = o.get();
+ if (optr)
+ optr->AddRef();
+ T* ptr = m_ptr;
+ m_ptr = optr;
+ if (ptr)
+ ptr->Release();
+ return *this;
+}
+
+template <typename T> template <typename U> inline COMPtr<T>& COMPtr<T>::operator=(const COMPtr<U>& o)
+{
+ T* optr = o.get();
+ if (optr)
+ optr->AddRef();
+ T* ptr = m_ptr;
+ m_ptr = optr;
+ if (ptr)
+ ptr->Release();
+ return *this;
+}
+
+template <typename T> inline COMPtr<T>& COMPtr<T>::operator=(T* optr)
+{
+ if (optr)
+ optr->AddRef();
+ T* ptr = m_ptr;
+ m_ptr = optr;
+ if (ptr)
+ ptr->Release();
+ return *this;
+}
+
+template <typename T, typename U> inline bool operator==(const COMPtr<T>& a, const COMPtr<U>& b)
+{
+ return a.get() == b.get();
+}
+
+template <typename T, typename U> inline bool operator==(const COMPtr<T>& a, U* b)
+{
+ return a.get() == b;
+}
+
+template <typename T, typename U> inline bool operator==(T* a, const COMPtr<U>& b)
+{
+ return a == b.get();
+}
+
+template <typename T, typename U> inline bool operator!=(const COMPtr<T>& a, const COMPtr<U>& b)
+{
+ return a.get() != b.get();
+}
+
+template <typename T, typename U> inline bool operator!=(const COMPtr<T>& a, U* b)
+{
+ return a.get() != b;
+}
+
+template <typename T, typename U> inline bool operator!=(T* a, const COMPtr<U>& b)
+{
+ return a != b.get();
+}
+
+namespace WTF {
+ template<typename P> struct HashTraits<COMPtr<P> > : GenericHashTraits<COMPtr<P> > {
+ typedef HashTraits<typename IntTypes<sizeof(P*)>::SignedType> StorageTraits;
+ typedef typename StorageTraits::TraitType StorageType;
+ static const bool emptyValueIsZero = true;
+ static const bool needsRef = true;
+
+ typedef union {
+ P* m_p;
+ StorageType m_s;
+ } UnionType;
+
+ static void ref(const StorageType& s)
+ {
+ if (const P* p = reinterpret_cast<const UnionType*>(&s)->m_p)
+ const_cast<P*>(p)->AddRef();
+ }
+ static void deref(const StorageType& s)
+ {
+ if (const P* p = reinterpret_cast<const UnionType*>(&s)->m_p)
+ const_cast<P*>(p)->Release();
+ }
+ };
+
+ template<typename P> struct HashKeyStorageTraits<PtrHash<COMPtr<P> >, HashTraits<COMPtr<P> > > {
+ typedef typename IntTypes<sizeof(P*)>::SignedType IntType;
+ typedef IntHash<IntType> Hash;
+ typedef HashTraits<IntType> Traits;
+ };
+
+ template<typename P> struct DefaultHash<COMPtr<P> > { typedef PtrHash<COMPtr<P> > Hash; };
+
+ template<typename P> struct PtrHash<COMPtr<P> > {
+ static unsigned hash(const COMPtr<P>& key) { return PtrHash<P*>::hash(key.get()); }
+ static bool equal(const COMPtr<P>& a, const COMPtr<P>& b) { return a == b; }
+ };
+}
+
+#endif
diff --git a/WebCore/platform/win/ClipboardUtilitiesWin.cpp b/WebCore/platform/win/ClipboardUtilitiesWin.cpp
new file mode 100644
index 0000000..7a3e5ff
--- /dev/null
+++ b/WebCore/platform/win/ClipboardUtilitiesWin.cpp
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2007, 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 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 "ClipboardUtilitiesWin.h"
+
+#include "CString.h"
+#include "DocumentFragment.h"
+#include "KURL.h"
+#include "PlatformString.h"
+#include "TextEncoding.h"
+#include "markup.h"
+#include <CoreFoundation/CoreFoundation.h>
+#include <wtf/RetainPtr.h>
+#include <shlwapi.h>
+#include <wininet.h> // for INTERNET_MAX_URL_LENGTH
+
+namespace WebCore {
+
+FORMATETC* cfHDropFormat()
+{
+ static FORMATETC urlFormat = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ return &urlFormat;
+}
+
+static bool getWebLocData(IDataObject* dataObject, String& url, String* title)
+{
+ bool succeeded = false;
+ WCHAR filename[MAX_PATH];
+ WCHAR urlBuffer[INTERNET_MAX_URL_LENGTH];
+
+ STGMEDIUM medium;
+ if (FAILED(dataObject->GetData(cfHDropFormat(), &medium)))
+ return false;
+
+ HDROP hdrop = (HDROP)GlobalLock(medium.hGlobal);
+
+ if (!hdrop)
+ return false;
+
+ if (!DragQueryFileW(hdrop, 0, filename, ARRAYSIZE(filename)))
+ goto exit;
+
+ if (_wcsicmp(PathFindExtensionW(filename), L".url"))
+ goto exit;
+
+ if (!GetPrivateProfileStringW(L"InternetShortcut", L"url", 0, urlBuffer, ARRAYSIZE(urlBuffer), filename))
+ goto exit;
+
+ if (title) {
+ PathRemoveExtension(filename);
+ *title = String((UChar*)filename);
+ }
+
+ url = String((UChar*)urlBuffer);
+ succeeded = true;
+
+exit:
+ // Free up memory.
+ DragFinish(hdrop);
+ GlobalUnlock(medium.hGlobal);
+ return succeeded;
+}
+
+static String extractURL(const String &inURL, String* title)
+{
+ String url = inURL;
+ int splitLoc = url.find('\n');
+ if (splitLoc > 0) {
+ if (title)
+ *title = url.substring(splitLoc+1);
+ url.truncate(splitLoc);
+ } else if (title)
+ *title = url;
+ return url;
+}
+
+//Firefox text/html
+static FORMATETC* texthtmlFormat()
+{
+ static UINT cf = RegisterClipboardFormat(L"text/html");
+ static FORMATETC texthtmlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ return &texthtmlFormat;
+}
+
+HGLOBAL createGlobalData(const KURL& url, const String& title)
+{
+ String mutableURL(url.string());
+ String mutableTitle(title);
+ SIZE_T size = mutableURL.length() + mutableTitle.length() + 2; // +1 for "\n" and +1 for null terminator
+ HGLOBAL cbData = ::GlobalAlloc(GPTR, size * sizeof(UChar));
+
+ if (cbData) {
+ PWSTR buffer = (PWSTR)::GlobalLock(cbData);
+ swprintf_s(buffer, size, L"%s\n%s", mutableURL.charactersWithNullTermination(), mutableTitle.charactersWithNullTermination());
+ ::GlobalUnlock(cbData);
+ }
+ return cbData;
+}
+
+HGLOBAL createGlobalData(const String& str)
+{
+ HGLOBAL globalData = ::GlobalAlloc(GPTR, (str.length() + 1) * sizeof(UChar));
+ if (!globalData)
+ return 0;
+ UChar* buffer = static_cast<UChar*>(::GlobalLock(globalData));
+ memcpy(buffer, str.characters(), str.length() * sizeof(UChar));
+ buffer[str.length()] = 0;
+ ::GlobalUnlock(globalData);
+ return globalData;
+}
+
+HGLOBAL createGlobalData(const Vector<char>& vector)
+{
+ HGLOBAL globalData = ::GlobalAlloc(GPTR, vector.size() + 1);
+ if (!globalData)
+ return 0;
+ char* buffer = static_cast<char*>(::GlobalLock(globalData));
+ memcpy(buffer, vector.data(), vector.size());
+ buffer[vector.size()] = 0;
+ ::GlobalUnlock(globalData);
+ return globalData;
+}
+
+static void append(Vector<char>& vector, const char* string)
+{
+ vector.append(string, strlen(string));
+}
+
+static void append(Vector<char>& vector, const CString& string)
+{
+ vector.append(string.data(), string.length());
+}
+
+// Documentation for the CF_HTML format is available at http://msdn.microsoft.com/workshop/networking/clipboard/htmlclipboard.asp
+void markupToCF_HTML(const String& markup, const String& srcURL, Vector<char>& result)
+{
+ if (markup.isEmpty())
+ return;
+
+ #define MAX_DIGITS 10
+ #define MAKE_NUMBER_FORMAT_1(digits) MAKE_NUMBER_FORMAT_2(digits)
+ #define MAKE_NUMBER_FORMAT_2(digits) "%0" #digits "u"
+ #define NUMBER_FORMAT MAKE_NUMBER_FORMAT_1(MAX_DIGITS)
+
+ const char* header = "Version:0.9\n"
+ "StartHTML:" NUMBER_FORMAT "\n"
+ "EndHTML:" NUMBER_FORMAT "\n"
+ "StartFragment:" NUMBER_FORMAT "\n"
+ "EndFragment:" NUMBER_FORMAT "\n";
+ const char* sourceURLPrefix = "SourceURL:";
+
+ const char* startMarkup = "<HTML>\n<BODY>\n<!--StartFragment-->\n";
+ const char* endMarkup = "\n<!--EndFragment-->\n</BODY>\n</HTML>";
+
+ CString sourceURLUTF8 = srcURL == blankURL() ? "" : srcURL.utf8();
+ CString markupUTF8 = markup.utf8();
+
+ // calculate offsets
+ unsigned startHTMLOffset = strlen(header) - strlen(NUMBER_FORMAT) * 4 + MAX_DIGITS * 4;
+ if (sourceURLUTF8.length())
+ startHTMLOffset += strlen(sourceURLPrefix) + sourceURLUTF8.length() + 1;
+ unsigned startFragmentOffset = startHTMLOffset + strlen(startMarkup);
+ unsigned endFragmentOffset = startFragmentOffset + markupUTF8.length();
+ unsigned endHTMLOffset = endFragmentOffset + strlen(endMarkup);
+
+ append(result, String::format(header, startHTMLOffset, endHTMLOffset, startFragmentOffset, endFragmentOffset).utf8());
+ if (sourceURLUTF8.length()) {
+ append(result, sourceURLPrefix);
+ append(result, sourceURLUTF8);
+ result.append('\n');
+ }
+ append(result, startMarkup);
+ append(result, markupUTF8);
+ append(result, endMarkup);
+
+ #undef MAX_DIGITS
+ #undef MAKE_NUMBER_FORMAT_1
+ #undef MAKE_NUMBER_FORMAT_2
+ #undef NUMBER_FORMAT
+}
+
+String urlToMarkup(const KURL& url, const String& title)
+{
+ Vector<UChar> markup;
+ append(markup, "<a href=\"");
+ append(markup, url.string());
+ append(markup, "\">");
+ append(markup, title);
+ append(markup, "</a>");
+ return String::adopt(markup);
+}
+
+void replaceNewlinesWithWindowsStyleNewlines(String& str)
+{
+ static const UChar Newline = '\n';
+ static const char* const WindowsNewline("\r\n");
+ str.replace(Newline, WindowsNewline);
+}
+
+void replaceNBSPWithSpace(String& str)
+{
+ static const UChar NonBreakingSpaceCharacter = 0xA0;
+ static const UChar SpaceCharacter = ' ';
+ str.replace(NonBreakingSpaceCharacter, SpaceCharacter);
+}
+
+FORMATETC* urlWFormat()
+{
+ static UINT cf = RegisterClipboardFormat(L"UniformResourceLocatorW");
+ static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ return &urlFormat;
+}
+
+FORMATETC* urlFormat()
+{
+ static UINT cf = RegisterClipboardFormat(L"UniformResourceLocator");
+ static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ return &urlFormat;
+}
+
+FORMATETC* plainTextFormat()
+{
+ static FORMATETC textFormat = {CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ return &textFormat;
+}
+
+FORMATETC* plainTextWFormat()
+{
+ static FORMATETC textFormat = {CF_UNICODETEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ return &textFormat;
+}
+
+FORMATETC* filenameWFormat()
+{
+ static UINT cf = RegisterClipboardFormat(L"FileNameW");
+ static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ return &urlFormat;
+}
+
+FORMATETC* filenameFormat()
+{
+ static UINT cf = RegisterClipboardFormat(L"FileName");
+ static FORMATETC urlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ return &urlFormat;
+}
+
+//MSIE HTML Format
+FORMATETC* htmlFormat()
+{
+ static UINT cf = RegisterClipboardFormat(L"HTML Format");
+ static FORMATETC htmlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ return &htmlFormat;
+}
+
+FORMATETC* smartPasteFormat()
+{
+ static UINT cf = RegisterClipboardFormat(L"WebKit Smart Paste Format");
+ static FORMATETC htmlFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ return &htmlFormat;
+}
+
+static bool urlFromPath(CFStringRef path, String& url)
+{
+ if (!path)
+ return false;
+
+ RetainPtr<CFURLRef> cfURL(AdoptCF, CFURLCreateWithFileSystemPath(0, path, kCFURLWindowsPathStyle, false));
+ if (!cfURL)
+ return false;
+
+ url = String(CFURLGetString(cfURL.get()));
+ return true;
+}
+
+String getURL(IDataObject* dataObject, bool& success, String* title)
+{
+ STGMEDIUM store;
+ String url;
+ success = false;
+ if (getWebLocData(dataObject, url, title)) {
+ success = true;
+ return url;
+ } else if (SUCCEEDED(dataObject->GetData(urlWFormat(), &store))) {
+ //URL using unicode
+ UChar* data = (UChar*)GlobalLock(store.hGlobal);
+ url = extractURL(String(data), title);
+ GlobalUnlock(store.hGlobal);
+ ReleaseStgMedium(&store);
+ success = true;
+ } else if (SUCCEEDED(dataObject->GetData(urlFormat(), &store))) {
+ //URL using ascii
+ char* data = (char*)GlobalLock(store.hGlobal);
+ url = extractURL(String(data), title);
+ GlobalUnlock(store.hGlobal);
+ ReleaseStgMedium(&store);
+ success = true;
+ } else if (SUCCEEDED(dataObject->GetData(filenameWFormat(), &store))) {
+ //file using unicode
+ wchar_t* data = (wchar_t*)GlobalLock(store.hGlobal);
+ if (data && data[0] && (PathFileExists(data) || PathIsUNC(data))) {
+ RetainPtr<CFStringRef> pathAsCFString(AdoptCF, CFStringCreateWithCharacters(kCFAllocatorDefault, (const UniChar*)data, wcslen(data)));
+ if (urlFromPath(pathAsCFString.get(), url)) {
+ if (title)
+ *title = url;
+ success = true;
+ }
+ }
+ GlobalUnlock(store.hGlobal);
+ ReleaseStgMedium(&store);
+ } else if (SUCCEEDED(dataObject->GetData(filenameFormat(), &store))) {
+ //filename using ascii
+ char* data = (char*)GlobalLock(store.hGlobal);
+ if (data && data[0] && (PathFileExistsA(data) || PathIsUNCA(data))) {
+ RetainPtr<CFStringRef> pathAsCFString(AdoptCF, CFStringCreateWithCString(kCFAllocatorDefault, data, kCFStringEncodingASCII));
+ if (urlFromPath(pathAsCFString.get(), url)) {
+ if (title)
+ *title = url;
+ success = true;
+ }
+ }
+ GlobalUnlock(store.hGlobal);
+ ReleaseStgMedium(&store);
+ }
+ return url;
+}
+
+String getPlainText(IDataObject* dataObject, bool& success)
+{
+ STGMEDIUM store;
+ String text;
+ success = false;
+ if (SUCCEEDED(dataObject->GetData(plainTextWFormat(), &store))) {
+ //unicode text
+ UChar* data = (UChar*)GlobalLock(store.hGlobal);
+ text = String(data);
+ GlobalUnlock(store.hGlobal);
+ ReleaseStgMedium(&store);
+ success = true;
+ } else if (SUCCEEDED(dataObject->GetData(plainTextFormat(), &store))) {
+ //ascii text
+ char* data = (char*)GlobalLock(store.hGlobal);
+ text = String(data);
+ GlobalUnlock(store.hGlobal);
+ ReleaseStgMedium(&store);
+ success = true;
+ } else {
+ //If a file is dropped on the window, it does not provide either of the
+ //plain text formats, so here we try to forcibly get a url.
+ text = getURL(dataObject, success);
+ success = true;
+ }
+ return text;
+}
+
+PassRefPtr<DocumentFragment> fragmentFromFilenames(Document*, const IDataObject*)
+{
+ //FIXME: We should be able to create fragments from files
+ return 0;
+}
+
+bool containsFilenames(const IDataObject*)
+{
+ //FIXME: We'll want to update this once we can produce fragments from files
+ return false;
+}
+
+//Convert a String containing CF_HTML formatted text to a DocumentFragment
+PassRefPtr<DocumentFragment> fragmentFromCF_HTML(Document* doc, const String& cf_html)
+{
+ // obtain baseURL if present
+ String srcURLStr("sourceURL:");
+ String srcURL;
+ unsigned lineStart = cf_html.find(srcURLStr, 0, false);
+ if (lineStart != -1) {
+ unsigned srcEnd = cf_html.find("\n", lineStart, false);
+ unsigned srcStart = lineStart+srcURLStr.length();
+ String rawSrcURL = cf_html.substring(srcStart, srcEnd-srcStart);
+ replaceNBSPWithSpace(rawSrcURL);
+ srcURL = rawSrcURL.stripWhiteSpace();
+ }
+
+ // find the markup between "<!--StartFragment -->" and "<!--EndFragment -->", accounting for browser quirks
+ unsigned markupStart = cf_html.find("<html", 0, false);
+ unsigned tagStart = cf_html.find("startfragment", markupStart, false);
+ unsigned fragmentStart = cf_html.find('>', tagStart) + 1;
+ unsigned tagEnd = cf_html.find("endfragment", fragmentStart, false);
+ unsigned fragmentEnd = cf_html.reverseFind('<', tagEnd);
+ String markup = cf_html.substring(fragmentStart, fragmentEnd - fragmentStart).stripWhiteSpace();
+
+ return createFragmentFromMarkup(doc, markup, srcURL).releaseRef();
+}
+
+
+PassRefPtr<DocumentFragment> fragmentFromHTML(Document* doc, IDataObject* data)
+{
+ if (!doc || !data)
+ return 0;
+
+ STGMEDIUM store;
+ String html;
+ String srcURL;
+ if (SUCCEEDED(data->GetData(htmlFormat(), &store))) {
+ //MS HTML Format parsing
+ char* data = (char*)GlobalLock(store.hGlobal);
+ SIZE_T dataSize = ::GlobalSize(store.hGlobal);
+ String cf_html(UTF8Encoding().decode(data, dataSize));
+ GlobalUnlock(store.hGlobal);
+ ReleaseStgMedium(&store);
+ if (PassRefPtr<DocumentFragment> fragment = fragmentFromCF_HTML(doc, cf_html))
+ return fragment;
+ }
+ if (SUCCEEDED(data->GetData(texthtmlFormat(), &store))) {
+ //raw html
+ UChar* data = (UChar*)GlobalLock(store.hGlobal);
+ html = String(data);
+ GlobalUnlock(store.hGlobal);
+ ReleaseStgMedium(&store);
+ return createFragmentFromMarkup(doc, html, srcURL);
+ }
+
+ return 0;
+}
+
+bool containsHTML(IDataObject* data)
+{
+ return SUCCEEDED(data->QueryGetData(texthtmlFormat())) || SUCCEEDED(data->QueryGetData(htmlFormat()));
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/win/ClipboardUtilitiesWin.h b/WebCore/platform/win/ClipboardUtilitiesWin.h
new file mode 100644
index 0000000..a92a4bf
--- /dev/null
+++ b/WebCore/platform/win/ClipboardUtilitiesWin.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 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 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 ClipboardUtilitiesWin_h
+#define ClipboardUtilitiesWin_h
+
+#include "DragData.h"
+#include <windows.h>
+
+namespace WebCore {
+
+class Document;
+class KURL;
+class String;
+
+HGLOBAL createGlobalData(const String&);
+HGLOBAL createGlobalData(const Vector<char>&);
+HGLOBAL createGlobalData(const KURL& url, const String& title);
+
+FORMATETC* urlWFormat();
+FORMATETC* urlFormat();
+FORMATETC* plainTextWFormat();
+FORMATETC* plainTextFormat();
+FORMATETC* filenameWFormat();
+FORMATETC* filenameFormat();
+FORMATETC* htmlFormat();
+FORMATETC* cfHDropFormat();
+FORMATETC* smartPasteFormat();
+
+void markupToCF_HTML(const String& markup, const String& srcURL, Vector<char>& result);
+String urlToMarkup(const KURL& url, const String& title);
+
+void replaceNewlinesWithWindowsStyleNewlines(String&);
+void replaceNBSPWithSpace(String&);
+
+bool containsFilenames(const IDataObject*);
+bool containsHTML(IDataObject*);
+
+PassRefPtr<DocumentFragment> fragmentFromFilenames(Document*, const IDataObject*);
+PassRefPtr<DocumentFragment> fragmentFromHTML(Document*, IDataObject*);
+PassRefPtr<DocumentFragment> fragmentFromCF_HTML(Document*, const String& cf_html);
+
+String getURL(IDataObject*, bool& success, String* title = 0);
+String getPlainText(IDataObject*, bool& success);
+
+} // namespace WebCore
+
+#endif // ClipboardUtilitiesWin_h \ No newline at end of file
diff --git a/WebCore/platform/win/ClipboardWin.cpp b/WebCore/platform/win/ClipboardWin.cpp
new file mode 100644
index 0000000..46e7695
--- /dev/null
+++ b/WebCore/platform/win/ClipboardWin.cpp
@@ -0,0 +1,767 @@
+/*
+ * Copyright (C) 2006, 2007 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 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 "ClipboardWin.h"
+
+#include "CString.h"
+#include "CachedImage.h"
+#include "ClipboardUtilitiesWin.h"
+#include "Document.h"
+#include "DragData.h"
+#include "Editor.h"
+#include "Element.h"
+#include "EventHandler.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameView.h"
+#include "HTMLNames.h"
+#include "Image.h"
+#include "MIMETypeRegistry.h"
+#include "Page.h"
+#include "Pasteboard.h"
+#include "PlatformMouseEvent.h"
+#include "PlatformString.h"
+#include "Range.h"
+#include "RenderImage.h"
+#include "ResourceResponse.h"
+#include "StringHash.h"
+#include "WCDataObject.h"
+#include "csshelper.h"
+#include "markup.h"
+
+#include <shlwapi.h>
+#include <wininet.h>
+
+#include <wtf/RefPtr.h>
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// format string for
+static const char szShellDotUrlTemplate[] = "[InternetShortcut]\r\nURL=%s\r\n";
+
+// We provide the IE clipboard types (URL and Text), and the clipboard types specified in the WHATWG Web Applications 1.0 draft
+// see http://www.whatwg.org/specs/web-apps/current-work/ Section 6.3.5.3
+
+enum ClipboardDataType { ClipboardDataTypeNone, ClipboardDataTypeURL, ClipboardDataTypeText };
+
+static ClipboardDataType clipboardTypeFromMIMEType(const String& type)
+{
+ String qType = type.stripWhiteSpace().lower();
+
+ // two special cases for IE compatibility
+ if (qType == "text" || qType == "text/plain" || qType.startsWith("text/plain;"))
+ return ClipboardDataTypeText;
+ if (qType == "url" || qType == "text/uri-list")
+ return ClipboardDataTypeURL;
+
+ return ClipboardDataTypeNone;
+}
+
+static inline FORMATETC* fileDescriptorFormat()
+{
+ static UINT cf = RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
+ static FORMATETC fileDescriptorFormat = {cf, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ return &fileDescriptorFormat;
+}
+
+static inline FORMATETC* fileContentFormatZero()
+{
+ static UINT cf = RegisterClipboardFormat(CFSTR_FILECONTENTS);
+ static FORMATETC fileContentFormat = {cf, 0, DVASPECT_CONTENT, 0, TYMED_HGLOBAL};
+ return &fileContentFormat;
+}
+
+static inline void pathRemoveBadFSCharacters(PWSTR psz, size_t length)
+{
+ size_t writeTo = 0;
+ size_t readFrom = 0;
+ while (readFrom < length) {
+ UINT type = PathGetCharType(psz[readFrom]);
+ if (psz[readFrom] == 0 || type & (GCT_LFNCHAR | GCT_SHORTCHAR)) {
+ psz[writeTo++] = psz[readFrom];
+ }
+
+ readFrom++;
+ }
+ psz[writeTo] = 0;
+}
+
+static String filesystemPathFromUrlOrTitle(const String& url, const String& title, TCHAR* extension, bool isLink)
+{
+ bool usedURL = false;
+ WCHAR fsPathBuffer[MAX_PATH + 1];
+ fsPathBuffer[0] = 0;
+ int extensionLen = extension ? lstrlen(extension) : 0;
+
+ if (!title.isEmpty()) {
+ size_t len = min<size_t>(title.length(), MAX_PATH - extensionLen);
+ CopyMemory(fsPathBuffer, title.characters(), len * sizeof(UChar));
+ fsPathBuffer[len] = 0;
+ pathRemoveBadFSCharacters(fsPathBuffer, len);
+ }
+
+ if (!lstrlen(fsPathBuffer)) {
+ DWORD len = MAX_PATH;
+ String nullTermURL = url;
+ usedURL = true;
+ if (UrlIsFileUrl((LPCWSTR)nullTermURL.charactersWithNullTermination())
+ && SUCCEEDED(PathCreateFromUrl((LPCWSTR)nullTermURL.charactersWithNullTermination(), fsPathBuffer, &len, 0))) {
+ // When linking to a file URL we can trivially find the file name
+ PWSTR fn = PathFindFileName(fsPathBuffer);
+ if (fn && fn != fsPathBuffer)
+ lstrcpyn(fsPathBuffer, fn, lstrlen(fn) + 1);
+ } else {
+ // The filename for any content based drag should be the last element of
+ // the path. If we can't find it, or we're coming up with the name for a link
+ // we just use the entire url.
+ KURL kurl(url);
+ String lastComponent;
+ if (!isLink && !(lastComponent = kurl.lastPathComponent()).isEmpty()) {
+ len = min<DWORD>(MAX_PATH, lastComponent.length());
+ CopyMemory(fsPathBuffer, lastComponent.characters(), len * sizeof(UChar));
+ } else {
+ len = min<DWORD>(MAX_PATH, nullTermURL.length());
+ CopyMemory(fsPathBuffer, nullTermURL.characters(), len * sizeof(UChar));
+ }
+ fsPathBuffer[len] = 0;
+ pathRemoveBadFSCharacters(fsPathBuffer, len);
+ }
+ }
+
+ if (!extension)
+ return String((UChar*)fsPathBuffer);
+
+ if (!isLink && usedURL) {
+ PathRenameExtension(fsPathBuffer, extension);
+ return String((UChar*)fsPathBuffer);
+ }
+
+ String result((UChar*)fsPathBuffer);
+ result += String((UChar*)extension);
+ return result;
+}
+
+static HGLOBAL createGlobalURLContent(const String& url, int estimatedFileSize)
+{
+ HRESULT hr = S_OK;
+ HGLOBAL memObj = 0;
+
+ char* fileContents;
+ char ansiUrl[INTERNET_MAX_URL_LENGTH + 1];
+ // Used to generate the buffer. This is null terminated whereas the fileContents won't be.
+ char contentGenerationBuffer[INTERNET_MAX_URL_LENGTH + ARRAYSIZE(szShellDotUrlTemplate) + 1];
+
+ if (estimatedFileSize > 0 && estimatedFileSize > ARRAYSIZE(contentGenerationBuffer))
+ return 0;
+
+ int ansiUrlSize = ::WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)url.characters(), url.length(), ansiUrl, ARRAYSIZE(ansiUrl) - 1, 0, 0);
+ if (!ansiUrlSize)
+ return 0;
+
+ ansiUrl[ansiUrlSize] = 0;
+
+ int fileSize = (int) (ansiUrlSize+strlen(szShellDotUrlTemplate)-2); // -2 to remove the %s
+ ASSERT(estimatedFileSize < 0 || fileSize == estimatedFileSize);
+
+ memObj = GlobalAlloc(GPTR, fileSize);
+ if (!memObj)
+ return 0;
+
+ fileContents = (PSTR)GlobalLock(memObj);
+
+ sprintf_s(contentGenerationBuffer, ARRAYSIZE(contentGenerationBuffer), szShellDotUrlTemplate, ansiUrl);
+ CopyMemory(fileContents, contentGenerationBuffer, fileSize);
+
+ GlobalUnlock(memObj);
+
+ return memObj;
+}
+
+static HGLOBAL createGlobalImageFileContent(SharedBuffer* data)
+{
+ HGLOBAL memObj = GlobalAlloc(GPTR, data->size());
+ if (!memObj)
+ return 0;
+
+ char* fileContents = (PSTR)GlobalLock(memObj);
+
+ CopyMemory(fileContents, data->data(), data->size());
+
+ GlobalUnlock(memObj);
+
+ return memObj;
+}
+
+static HGLOBAL createGlobalHDropContent(const KURL& url, String& fileName, SharedBuffer* data)
+{
+ if (fileName.isEmpty() || !data )
+ return 0;
+
+ WCHAR filePath[MAX_PATH];
+
+ if (url.isLocalFile()) {
+ String localPath = url.path();
+ // windows does not enjoy a leading slash on paths
+ if (localPath[0] == '/')
+ localPath = localPath.substring(1);
+ LPCTSTR localPathStr = localPath.charactersWithNullTermination();
+ if (wcslen(localPathStr) + 1 < MAX_PATH)
+ wcscpy_s(filePath, MAX_PATH, localPathStr);
+ else
+ return 0;
+ } else {
+ WCHAR tempPath[MAX_PATH];
+ WCHAR extension[MAX_PATH];
+ if (!::GetTempPath(ARRAYSIZE(tempPath), tempPath))
+ return 0;
+ if (!::PathAppend(tempPath, fileName.charactersWithNullTermination()))
+ return 0;
+ LPCWSTR foundExtension = ::PathFindExtension(tempPath);
+ if (foundExtension) {
+ if (wcscpy_s(extension, MAX_PATH, foundExtension))
+ return 0;
+ } else
+ *extension = 0;
+ ::PathRemoveExtension(tempPath);
+ for (int i = 1; i < 10000; i++) {
+ if (swprintf_s(filePath, MAX_PATH, TEXT("%s-%d%s"), tempPath, i, extension) == -1)
+ return 0;
+ if (!::PathFileExists(filePath))
+ break;
+ }
+ HANDLE tempFileHandle = CreateFile(filePath, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+ if (tempFileHandle == INVALID_HANDLE_VALUE)
+ return 0;
+
+ // Write the data to this temp file.
+ DWORD written;
+ BOOL tempWriteSucceeded = WriteFile(tempFileHandle, data->data(), data->size(), &written, 0);
+ CloseHandle(tempFileHandle);
+ if (!tempWriteSucceeded)
+ return 0;
+ }
+
+ SIZE_T dropFilesSize = sizeof(DROPFILES) + (sizeof(WCHAR) * (wcslen(filePath) + 2));
+ HGLOBAL memObj = GlobalAlloc(GHND | GMEM_SHARE, dropFilesSize);
+ if (!memObj)
+ return 0;
+
+ DROPFILES* dropFiles = (DROPFILES*) GlobalLock(memObj);
+ dropFiles->pFiles = sizeof(DROPFILES);
+ dropFiles->fWide = TRUE;
+ wcscpy((LPWSTR)(dropFiles + 1), filePath);
+ GlobalUnlock(memObj);
+
+ return memObj;
+}
+
+static HGLOBAL createGlobalUrlFileDescriptor(const String& url, const String& title, int& /*out*/ estimatedSize)
+{
+ HRESULT hr = S_OK;
+ HGLOBAL memObj = 0;
+ String fsPath;
+ memObj = GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTOR));
+ if (!memObj)
+ return 0;
+
+ FILEGROUPDESCRIPTOR* fgd = (FILEGROUPDESCRIPTOR*)GlobalLock(memObj);
+ memset(fgd, 0, sizeof(FILEGROUPDESCRIPTOR));
+ fgd->cItems = 1;
+ fgd->fgd[0].dwFlags = FD_FILESIZE;
+ int fileSize = ::WideCharToMultiByte(CP_ACP, 0, url.characters(), url.length(), 0, 0, 0, 0);
+ fileSize += strlen(szShellDotUrlTemplate) - 2; // -2 is for getting rid of %s in the template string
+ fgd->fgd[0].nFileSizeLow = fileSize;
+ estimatedSize = fileSize;
+ fsPath = filesystemPathFromUrlOrTitle(url, title, L".URL", true);
+
+ if (fsPath.length() <= 0) {
+ GlobalUnlock(memObj);
+ GlobalFree(memObj);
+ return 0;
+ }
+
+ int maxSize = min(fsPath.length(), ARRAYSIZE(fgd->fgd[0].cFileName));
+ CopyMemory(fgd->fgd[0].cFileName, (LPCWSTR)fsPath.characters(), maxSize * sizeof(UChar));
+ GlobalUnlock(memObj);
+
+ return memObj;
+}
+
+
+static HGLOBAL createGlobalImageFileDescriptor(const String& url, const String& title, CachedImage* image)
+{
+ ASSERT_ARG(image, image);
+ ASSERT(image->image()->data());
+
+ HRESULT hr = S_OK;
+ HGLOBAL memObj = 0;
+ String fsPath;
+ memObj = GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTOR));
+ if (!memObj)
+ return 0;
+
+ FILEGROUPDESCRIPTOR* fgd = (FILEGROUPDESCRIPTOR*)GlobalLock(memObj);
+ memset(fgd, 0, sizeof(FILEGROUPDESCRIPTOR));
+ fgd->cItems = 1;
+ fgd->fgd[0].dwFlags = FD_FILESIZE;
+ fgd->fgd[0].nFileSizeLow = image->image()->data()->size();
+
+ String extension(".");
+ extension += WebCore::MIMETypeRegistry::getPreferredExtensionForMIMEType(image->response().mimeType());
+ const String& preferredTitle = title.isEmpty() ? image->response().suggestedFilename() : title;
+ fsPath = filesystemPathFromUrlOrTitle(url, preferredTitle, extension.length() ? (TCHAR*)extension.charactersWithNullTermination() : 0, false);
+
+ if (fsPath.length() <= 0) {
+ GlobalUnlock(memObj);
+ GlobalFree(memObj);
+ return 0;
+ }
+
+ int maxSize = min(fsPath.length(), ARRAYSIZE(fgd->fgd[0].cFileName));
+ CopyMemory(fgd->fgd[0].cFileName, (LPCWSTR)fsPath.characters(), maxSize * sizeof(UChar));
+ GlobalUnlock(memObj);
+
+ return memObj;
+}
+
+
+// writeFileToDataObject takes ownership of fileDescriptor and fileContent
+static HRESULT writeFileToDataObject(IDataObject* dataObject, HGLOBAL fileDescriptor, HGLOBAL fileContent, HGLOBAL hDropContent)
+{
+ HRESULT hr = S_OK;
+ FORMATETC* fe;
+ STGMEDIUM medium = {0};
+ medium.tymed = TYMED_HGLOBAL;
+
+ if (!fileDescriptor || !fileContent)
+ goto exit;
+
+ // Descriptor
+ fe = fileDescriptorFormat();
+
+ medium.hGlobal = fileDescriptor;
+
+ if (FAILED(hr = dataObject->SetData(fe, &medium, TRUE)))
+ goto exit;
+
+ // Contents
+ fe = fileContentFormatZero();
+ medium.hGlobal = fileContent;
+ if (FAILED(hr = dataObject->SetData(fe, &medium, TRUE)))
+ goto exit;
+
+ // HDROP
+ if (hDropContent) {
+ medium.hGlobal = hDropContent;
+ hr = dataObject->SetData(cfHDropFormat(), &medium, TRUE);
+ }
+
+exit:
+ if (FAILED(hr)) {
+ if (fileDescriptor)
+ GlobalFree(fileDescriptor);
+ if (fileContent)
+ GlobalFree(fileContent);
+ if (hDropContent)
+ GlobalFree(hDropContent);
+ }
+ return hr;
+}
+
+ClipboardWin::ClipboardWin(bool isForDragging, IDataObject* dataObject, ClipboardAccessPolicy policy)
+ : Clipboard(policy, isForDragging)
+ , m_dataObject(dataObject)
+ , m_writableDataObject(0)
+{
+}
+
+ClipboardWin::ClipboardWin(bool isForDragging, WCDataObject* dataObject, ClipboardAccessPolicy policy)
+ : Clipboard(policy, isForDragging)
+ , m_dataObject(dataObject)
+ , m_writableDataObject(dataObject)
+{
+}
+
+ClipboardWin::~ClipboardWin()
+{
+}
+
+static bool writeURL(WCDataObject *data, const KURL& url, String title, bool withPlainText, bool withHTML)
+{
+ ASSERT(data);
+
+ if (url.isEmpty())
+ return false;
+
+ if (title.isEmpty()) {
+ title = url.lastPathComponent();
+ if (title.isEmpty())
+ title = url.host();
+ }
+
+ STGMEDIUM medium = {0};
+ medium.tymed = TYMED_HGLOBAL;
+
+ medium.hGlobal = createGlobalData(url, title);
+ bool success = false;
+ if (medium.hGlobal && FAILED(data->SetData(urlWFormat(), &medium, TRUE)))
+ ::GlobalFree(medium.hGlobal);
+ else
+ success = true;
+
+ if (withHTML) {
+ Vector<char> cfhtmlData;
+ markupToCF_HTML(urlToMarkup(url, title), "", cfhtmlData);
+ medium.hGlobal = createGlobalData(cfhtmlData);
+ if (medium.hGlobal && FAILED(data->SetData(htmlFormat(), &medium, TRUE)))
+ ::GlobalFree(medium.hGlobal);
+ else
+ success = true;
+ }
+
+ if (withPlainText) {
+ medium.hGlobal = createGlobalData(url.string());
+ if (medium.hGlobal && FAILED(data->SetData(plainTextWFormat(), &medium, TRUE)))
+ ::GlobalFree(medium.hGlobal);
+ else
+ success = true;
+ }
+
+ return success;
+}
+
+void ClipboardWin::clearData(const String& type)
+{
+ //FIXME: Need to be able to write to the system clipboard <rdar://problem/5015941>
+ ASSERT(isForDragging());
+ if (policy() != ClipboardWritable || !m_writableDataObject)
+ return;
+
+ ClipboardDataType dataType = clipboardTypeFromMIMEType(type);
+
+ if (dataType == ClipboardDataTypeURL) {
+ m_writableDataObject->clearData(urlWFormat()->cfFormat);
+ m_writableDataObject->clearData(urlFormat()->cfFormat);
+ }
+ if (dataType == ClipboardDataTypeText) {
+ m_writableDataObject->clearData(plainTextFormat()->cfFormat);
+ m_writableDataObject->clearData(plainTextWFormat()->cfFormat);
+ }
+
+}
+
+void ClipboardWin::clearAllData()
+{
+ //FIXME: Need to be able to write to the system clipboard <rdar://problem/5015941>
+ ASSERT(isForDragging());
+ if (policy() != ClipboardWritable)
+ return;
+
+ m_writableDataObject = 0;
+ WCDataObject::createInstance(&m_writableDataObject);
+ m_dataObject = m_writableDataObject;
+}
+
+String ClipboardWin::getData(const String& type, bool& success) const
+{
+ success = false;
+ if (policy() != ClipboardReadable || !m_dataObject) {
+ return "";
+ }
+
+ ClipboardDataType dataType = clipboardTypeFromMIMEType(type);
+ if (dataType == ClipboardDataTypeText)
+ return getPlainText(m_dataObject.get(), success);
+ else if (dataType == ClipboardDataTypeURL)
+ return getURL(m_dataObject.get(), success);
+
+ return "";
+}
+
+bool ClipboardWin::setData(const String& type, const String& data)
+{
+ // FIXME: Need to be able to write to the system clipboard <rdar://problem/5015941>
+ ASSERT(isForDragging());
+ if (policy() != ClipboardWritable || !m_writableDataObject)
+ return false;
+
+ ClipboardDataType winType = clipboardTypeFromMIMEType(type);
+
+ if (winType == ClipboardDataTypeURL)
+ return WebCore::writeURL(m_writableDataObject.get(), KURL(data), String(), false, true);
+
+ if (winType == ClipboardDataTypeText) {
+ STGMEDIUM medium = {0};
+ medium.tymed = TYMED_HGLOBAL;
+ medium.hGlobal = createGlobalData(data);
+ if (!medium.hGlobal)
+ return false;
+
+ if (FAILED(m_writableDataObject->SetData(plainTextWFormat(), &medium, TRUE))) {
+ ::GlobalFree(medium.hGlobal);
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+static void addMimeTypesForFormat(HashSet<String>& results, FORMATETC& format)
+{
+ // URL and Text are provided for compatibility with IE's model
+ if (format.cfFormat == urlFormat()->cfFormat || format.cfFormat == urlWFormat()->cfFormat) {
+ results.add("URL");
+ results.add("text/uri-list");
+ }
+
+ if (format.cfFormat == plainTextWFormat()->cfFormat || format.cfFormat == plainTextFormat()->cfFormat) {
+ results.add("Text");
+ results.add("text/plain");
+ }
+}
+
+// extensions beyond IE's API
+HashSet<String> ClipboardWin::types() const
+{
+ HashSet<String> results;
+ if (policy() != ClipboardReadable && policy() != ClipboardTypesReadable)
+ return results;
+
+ if (!m_dataObject)
+ return results;
+
+ COMPtr<IEnumFORMATETC> itr;
+
+ if (FAILED(m_dataObject->EnumFormatEtc(0, &itr)))
+ return results;
+
+ if (!itr)
+ return results;
+
+ FORMATETC data;
+
+ while (SUCCEEDED(itr->Next(1, &data, 0))) {
+ addMimeTypesForFormat(results, data);
+ }
+
+ return results;
+}
+
+void ClipboardWin::setDragImage(CachedImage* image, Node *node, const IntPoint &loc)
+{
+ if (policy() != ClipboardImageWritable && policy() != ClipboardWritable)
+ return;
+
+ if (m_dragImage)
+ m_dragImage->deref(this);
+ m_dragImage = image;
+ if (m_dragImage)
+ m_dragImage->ref(this);
+
+ m_dragLoc = loc;
+ m_dragImageElement = node;
+}
+
+void ClipboardWin::setDragImage(CachedImage* img, const IntPoint &loc)
+{
+ setDragImage(img, 0, loc);
+}
+
+void ClipboardWin::setDragImageElement(Node *node, const IntPoint &loc)
+{
+ setDragImage(0, node, loc);
+}
+
+DragImageRef ClipboardWin::createDragImage(IntPoint& loc) const
+{
+ HBITMAP result = 0;
+ //FIXME: Need to be able to draw element <rdar://problem/5015942>
+ if (m_dragImage) {
+ result = createDragImageFromImage(m_dragImage->image());
+ loc = m_dragLoc;
+ }
+ return result;
+}
+
+static String imageToMarkup(const String& url)
+{
+ String markup("<img src=\"");
+ markup.append(url);
+ markup.append("\"/>");
+ return markup;
+}
+
+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;
+}
+
+static void writeImageToDataObject(IDataObject* dataObject, Element* element, const KURL& url)
+{
+ // Shove image data into a DataObject for use as a file
+ CachedImage* cachedImage = getCachedImage(element);
+ if (!cachedImage || !cachedImage->image() || !cachedImage->isLoaded())
+ return;
+
+ SharedBuffer* imageBuffer = cachedImage->image()->data();
+ if (!imageBuffer || !imageBuffer->size())
+ return;
+
+ HGLOBAL imageFileDescriptor = createGlobalImageFileDescriptor(url.string(), element->getAttribute(altAttr), cachedImage);
+ if (!imageFileDescriptor)
+ return;
+
+ HGLOBAL imageFileContent = createGlobalImageFileContent(imageBuffer);
+ if (!imageFileContent) {
+ GlobalFree(imageFileDescriptor);
+ return;
+ }
+
+ String fileName = cachedImage->response().suggestedFilename();
+ HGLOBAL hDropContent = createGlobalHDropContent(url, fileName, imageBuffer);
+ if (!hDropContent) {
+ GlobalFree(hDropContent);
+ return;
+ }
+
+ writeFileToDataObject(dataObject, imageFileDescriptor, imageFileContent, hDropContent);
+}
+
+void ClipboardWin::declareAndWriteDragImage(Element* element, const KURL& url, const String& title, Frame* frame)
+{
+ // Order is important here for Explorer's sake
+ if (!m_writableDataObject)
+ return;
+ WebCore::writeURL(m_writableDataObject.get(), url, title, true, false);
+
+ writeImageToDataObject(m_writableDataObject.get(), element, url);
+
+ AtomicString imageURL = element->getAttribute(srcAttr);
+ if (imageURL.isEmpty())
+ return;
+
+ String fullURL = frame->document()->completeURL(parseURL(imageURL)).string();
+ if (fullURL.isEmpty())
+ return;
+ STGMEDIUM medium = {0};
+ medium.tymed = TYMED_HGLOBAL;
+ ExceptionCode ec = 0;
+
+ // Put img tag on the clipboard referencing the image
+ Vector<char> data;
+ markupToCF_HTML(imageToMarkup(fullURL), "", data);
+ medium.hGlobal = createGlobalData(data);
+ if (medium.hGlobal && FAILED(m_writableDataObject->SetData(htmlFormat(), &medium, TRUE)))
+ ::GlobalFree(medium.hGlobal);
+}
+
+void ClipboardWin::writeURL(const KURL& kurl, const String& titleStr, Frame*)
+{
+ if (!m_writableDataObject)
+ return;
+ WebCore::writeURL(m_writableDataObject.get(), kurl, titleStr, true, true);
+
+ int estimatedSize = 0;
+ String url = kurl.string();
+
+ HGLOBAL urlFileDescriptor = createGlobalUrlFileDescriptor(url, titleStr, estimatedSize);
+ if (!urlFileDescriptor)
+ return;
+ HGLOBAL urlFileContent = createGlobalURLContent(url, estimatedSize);
+ if (!urlFileContent) {
+ GlobalFree(urlFileDescriptor);
+ return;
+ }
+ writeFileToDataObject(m_writableDataObject.get(), urlFileDescriptor, urlFileContent, 0);
+}
+
+void ClipboardWin::writeRange(Range* selectedRange, Frame* frame)
+{
+ ASSERT(selectedRange);
+ if (!m_writableDataObject)
+ return;
+
+ STGMEDIUM medium = {0};
+ medium.tymed = TYMED_HGLOBAL;
+ ExceptionCode ec = 0;
+
+ Vector<char> data;
+ markupToCF_HTML(createMarkup(selectedRange, 0, AnnotateForInterchange),
+ selectedRange->startContainer(ec)->document()->url().string(), data);
+ medium.hGlobal = createGlobalData(data);
+ if (medium.hGlobal && FAILED(m_writableDataObject->SetData(htmlFormat(), &medium, TRUE)))
+ ::GlobalFree(medium.hGlobal);
+
+ String str = frame->selectedText();
+ replaceNewlinesWithWindowsStyleNewlines(str);
+ replaceNBSPWithSpace(str);
+ medium.hGlobal = createGlobalData(str);
+ if (medium.hGlobal && FAILED(m_writableDataObject->SetData(plainTextWFormat(), &medium, TRUE)))
+ ::GlobalFree(medium.hGlobal);
+
+ medium.hGlobal = 0;
+ if (frame->editor()->canSmartCopyOrDelete())
+ m_writableDataObject->SetData(smartPasteFormat(), &medium, TRUE);
+}
+
+bool ClipboardWin::hasData()
+{
+ if (!m_dataObject)
+ return false;
+
+ COMPtr<IEnumFORMATETC> itr;
+ if (FAILED(m_dataObject->EnumFormatEtc(0, &itr)))
+ return false;
+
+ if (!itr)
+ return false;
+
+ FORMATETC data;
+
+ if (SUCCEEDED(itr->Next(1, &data, 0))) {
+ // There is at least one item in the IDataObject
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/win/ClipboardWin.h b/WebCore/platform/win/ClipboardWin.h
new file mode 100644
index 0000000..0d6e448
--- /dev/null
+++ b/WebCore/platform/win/ClipboardWin.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2006, 2007 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 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 ClipboardWin_h
+#define ClipboardWin_h
+
+#include "Clipboard.h"
+
+#include "CachedResourceClient.h"
+#include "IntPoint.h"
+#include "COMPtr.h"
+
+struct IDataObject;
+
+namespace WebCore {
+
+ class CachedImage;
+ class IntPoint;
+ class WCDataObject;
+
+ // State available during IE's events for drag and drop and copy/paste
+ class ClipboardWin : public Clipboard, public CachedResourceClient {
+ public:
+ ClipboardWin(bool isForDragging, IDataObject* dataObject, ClipboardAccessPolicy policy);
+ ClipboardWin(bool isForDragging, WCDataObject* dataObject, ClipboardAccessPolicy policy);
+ ~ClipboardWin();
+
+ void clearData(const String& type);
+ void clearAllData();
+ String getData(const String& type, bool& success) const;
+ bool setData(const String& type, const String& data);
+
+ // extensions beyond IE's API
+ HashSet<String> types() const;
+
+ void setDragImage(CachedImage*, const IntPoint&);
+ void setDragImageElement(Node*, const IntPoint&);
+
+ virtual DragImageRef createDragImage(IntPoint& dragLoc) const;
+ virtual void declareAndWriteDragImage(Element*, const KURL&, const String& title, Frame*);
+ virtual void writeURL(const KURL&, const String&, Frame*);
+ virtual void writeRange(Range*, Frame*);
+
+ virtual bool hasData();
+
+ COMPtr<IDataObject> dataObject() { return m_dataObject; }
+ private:
+ void resetFromClipboard();
+ void setDragImage(CachedImage*, Node*, const IntPoint&);
+ COMPtr<IDataObject> m_dataObject;
+ COMPtr<WCDataObject> m_writableDataObject;
+ Frame* m_frame;
+ };
+
+} // namespace WebCore
+
+#endif // ClipboardWin_h
diff --git a/WebCore/platform/win/ContextMenuItemWin.cpp b/WebCore/platform/win/ContextMenuItemWin.cpp
new file mode 100644
index 0000000..bd10c91
--- /dev/null
+++ b/WebCore/platform/win/ContextMenuItemWin.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2006, 2007 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 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 "ContextMenuItem.h"
+
+#include "ContextMenu.h"
+
+#include "CString.h"
+#include <windows.h>
+
+namespace WebCore {
+
+ContextMenuItem::ContextMenuItem(LPMENUITEMINFO item)
+ : m_platformDescription(item)
+{
+}
+
+ContextMenuItem::ContextMenuItem(ContextMenu* subMenu)
+{
+ m_platformDescription = (LPMENUITEMINFO)malloc(sizeof(MENUITEMINFO));
+ if (!m_platformDescription)
+ return;
+
+ memset(m_platformDescription, 0, sizeof(MENUITEMINFO));
+ m_platformDescription->cbSize = sizeof(MENUITEMINFO);
+
+ m_platformDescription->wID = ContextMenuItemTagNoAction;
+ if (subMenu) {
+ m_platformDescription->fMask |= MIIM_SUBMENU;
+ m_platformDescription->hSubMenu = subMenu->platformDescription();
+ }
+}
+
+ContextMenuItem::ContextMenuItem(ContextMenuItemType type, ContextMenuAction action, const String& title, ContextMenu* subMenu)
+{
+ m_platformDescription = (LPMENUITEMINFO)malloc(sizeof(MENUITEMINFO));
+ if (!m_platformDescription)
+ return;
+
+ memset(m_platformDescription, 0, sizeof(MENUITEMINFO));
+ m_platformDescription->cbSize = sizeof(MENUITEMINFO);
+ m_platformDescription->fMask = MIIM_FTYPE;
+
+ if (type == SeparatorType) {
+ m_platformDescription->fType = MFT_SEPARATOR;
+ return;
+ }
+
+ if (subMenu) {
+ m_platformDescription->fMask |= MIIM_STRING | MIIM_SUBMENU;
+ m_platformDescription->hSubMenu = subMenu->platformDescription();
+ } else
+ m_platformDescription->fMask |= MIIM_STRING | MIIM_ID;
+
+ m_platformDescription->fType = MFT_STRING;
+ m_platformDescription->wID = action;
+
+ String t = title;
+ m_platformDescription->cch = t.length();
+ m_platformDescription->dwTypeData = wcsdup(t.charactersWithNullTermination());
+}
+
+ContextMenuItem::~ContextMenuItem()
+{
+ if (m_platformDescription) {
+ if (m_platformDescription->fType == MFT_STRING)
+ free(m_platformDescription->dwTypeData);
+ free(m_platformDescription);
+ }
+}
+
+LPMENUITEMINFO ContextMenuItem::releasePlatformDescription()
+{
+ LPMENUITEMINFO info = m_platformDescription;
+ m_platformDescription = 0;
+ return info;
+}
+
+ContextMenuItemType ContextMenuItem::type() const
+{
+ ContextMenuItemType type = ActionType;
+
+ if ((m_platformDescription->fType & MFT_STRING) && m_platformDescription->hSubMenu)
+ type = SubmenuType;
+ else if (m_platformDescription->fType & MFT_SEPARATOR)
+ type = SeparatorType;
+
+ return type;
+}
+
+ContextMenuAction ContextMenuItem::action() const
+{
+ return static_cast<ContextMenuAction>(m_platformDescription->wID);
+}
+
+String ContextMenuItem::title() const
+{
+ return String(m_platformDescription->dwTypeData, wcslen(m_platformDescription->dwTypeData));
+}
+
+PlatformMenuDescription ContextMenuItem::platformSubMenu() const
+{
+ return m_platformDescription->hSubMenu;
+}
+
+void ContextMenuItem::setType(ContextMenuItemType type)
+{
+ if (type == SeparatorType)
+ m_platformDescription->fType = MFT_SEPARATOR;
+ else
+ m_platformDescription->fType = MFT_STRING;
+}
+
+void ContextMenuItem::setAction(ContextMenuAction action)
+{
+ m_platformDescription->wID = action;
+}
+
+void ContextMenuItem::setTitle(const String& title)
+{
+ if (m_platformDescription->dwTypeData)
+ free(m_platformDescription->dwTypeData);
+
+ m_platformDescription->cch = title.length();
+ String titleCopy = title;
+ m_platformDescription->dwTypeData = wcsdup(titleCopy.charactersWithNullTermination());
+}
+
+void ContextMenuItem::setSubMenu(ContextMenu* subMenu)
+{
+ if (subMenu->platformDescription() == m_platformDescription->hSubMenu)
+ return;
+
+ if (m_platformDescription->hSubMenu)
+ ::DestroyMenu(m_platformDescription->hSubMenu);
+
+ m_platformDescription->fMask |= MIIM_SUBMENU;
+ m_platformDescription->hSubMenu = subMenu->releasePlatformDescription();
+}
+
+void ContextMenuItem::setChecked(bool checked)
+{
+ m_platformDescription->fMask |= MIIM_STATE;
+ if (checked) {
+ m_platformDescription->fState &= ~MFS_UNCHECKED;
+ m_platformDescription->fState |= MFS_CHECKED;
+ } else {
+ m_platformDescription->fState &= ~MFS_CHECKED;
+ m_platformDescription->fState |= MFS_UNCHECKED;
+ }
+}
+
+void ContextMenuItem::setEnabled(bool enabled)
+{
+ m_platformDescription->fMask |= MIIM_STATE;
+ if (enabled) {
+ m_platformDescription->fState &= ~MFS_DISABLED;
+ m_platformDescription->fState |= MFS_ENABLED;
+ } else {
+ m_platformDescription->fState &= ~MFS_ENABLED;
+ m_platformDescription->fState |= MFS_DISABLED;
+ }
+}
+
+bool ContextMenuItem::enabled() const
+{
+ return m_platformDescription->fState & MFS_ENABLED;
+}
+
+}
diff --git a/WebCore/platform/win/ContextMenuWin.cpp b/WebCore/platform/win/ContextMenuWin.cpp
new file mode 100644
index 0000000..26b081a
--- /dev/null
+++ b/WebCore/platform/win/ContextMenuWin.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2006, 2007 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 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 "ContextMenu.h"
+
+#include "CString.h"
+#include "Document.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "Node.h"
+#include <tchar.h>
+#include <windows.h>
+
+namespace WebCore {
+
+ContextMenu::ContextMenu(const HitTestResult& result)
+ : m_hitTestResult(result)
+ , m_platformDescription(0)
+{
+ setPlatformDescription(::CreatePopupMenu());
+}
+
+ContextMenu::ContextMenu(const HitTestResult& result, const PlatformMenuDescription menu)
+ : m_hitTestResult(result)
+ , m_platformDescription(0)
+{
+ setPlatformDescription(menu);
+}
+
+ContextMenu::~ContextMenu()
+{
+ if (m_platformDescription)
+ ::DestroyMenu(m_platformDescription);
+}
+
+unsigned ContextMenu::itemCount() const
+{
+ if (!m_platformDescription)
+ return 0;
+
+ return ::GetMenuItemCount(m_platformDescription);
+}
+
+void ContextMenu::insertItem(unsigned int position, ContextMenuItem& item)
+{
+ if (!m_platformDescription)
+ return;
+
+ checkOrEnableIfNeeded(item);
+ ::InsertMenuItem(m_platformDescription, position, TRUE, item.releasePlatformDescription());
+}
+
+void ContextMenu::appendItem(ContextMenuItem& item)
+{
+ insertItem(itemCount(), item);
+}
+
+static ContextMenuItem* contextMenuItemByIdOrPosition(HMENU menu, unsigned id, BOOL byPosition)
+{
+ if (!menu)
+ return 0;
+ LPMENUITEMINFO info = (LPMENUITEMINFO)malloc(sizeof(MENUITEMINFO));
+ if (!info)
+ return 0;
+
+ memset(info, 0, sizeof(MENUITEMINFO));
+
+ info->cbSize = sizeof(MENUITEMINFO);
+
+ info->fMask = MIIM_FTYPE | MIIM_ID | MIIM_STRING;
+
+ if (!::GetMenuItemInfo(menu, id, byPosition, info)) {
+ free(info);
+ return 0;
+ }
+
+ UINT type = info->fType & ~(MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_OWNERDRAW | MFT_RADIOCHECK | MFT_RIGHTORDER | MFT_RIGHTJUSTIFY);
+ if (type == MFT_STRING) {
+ LPTSTR buffer = (LPTSTR)malloc(++info->cch * sizeof(TCHAR));
+ if (!buffer) {
+ free(info);
+ return 0;
+ }
+ info->dwTypeData = buffer;
+ ::GetMenuItemInfo(menu, id, byPosition, info);
+ }
+
+ return new ContextMenuItem(info);
+}
+
+ContextMenuItem* ContextMenu::itemWithAction(unsigned action)
+{
+ return contextMenuItemByIdOrPosition(m_platformDescription, action, FALSE);
+}
+
+ContextMenuItem* ContextMenu::itemAtIndex(unsigned index, const PlatformMenuDescription platformDescription)
+{
+ return contextMenuItemByIdOrPosition(platformDescription, index, TRUE);
+}
+
+void ContextMenu::setPlatformDescription(HMENU menu)
+{
+ if (menu == m_platformDescription)
+ return;
+
+ if (m_platformDescription)
+ ::DestroyMenu(m_platformDescription);
+
+ m_platformDescription = menu;
+ if (!m_platformDescription)
+ return;
+
+ MENUINFO menuInfo = {0};
+ menuInfo.cbSize = sizeof(MENUINFO);
+ menuInfo.fMask = MIM_STYLE;
+ ::GetMenuInfo(m_platformDescription, &menuInfo);
+ menuInfo.fMask = MIM_STYLE;
+ menuInfo.dwStyle |= MNS_NOTIFYBYPOS;
+ ::SetMenuInfo(m_platformDescription, &menuInfo);
+}
+
+HMENU ContextMenu::platformDescription() const
+{
+ return m_platformDescription;
+}
+
+HMENU ContextMenu::releasePlatformDescription()
+{
+ HMENU description = m_platformDescription;
+ m_platformDescription = 0;
+ return description;
+}
+
+}
diff --git a/WebCore/platform/win/CursorWin.cpp b/WebCore/platform/win/CursorWin.cpp
new file mode 100644
index 0000000..1e31617
--- /dev/null
+++ b/WebCore/platform/win/CursorWin.cpp
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2006, 2007 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 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 "Cursor.h"
+
+#include "Image.h"
+#include "IntPoint.h"
+
+#include <wtf/OwnPtr.h>
+
+#include <windows.h>
+
+#define ALPHA_CURSORS
+
+namespace WebCore {
+
+Cursor::Cursor(const Cursor& other)
+ : m_impl(other.m_impl)
+{
+}
+
+static inline bool supportsAlphaCursors()
+{
+ OSVERSIONINFO osinfo = {0};
+ osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&osinfo);
+ return osinfo.dwMajorVersion > 5 || (osinfo.dwMajorVersion == 5 && osinfo.dwMinorVersion > 0);
+}
+
+Cursor::Cursor(Image* img, const IntPoint& hotspot)
+{
+ static bool doAlpha = supportsAlphaCursors();
+ BITMAPINFO cursorImage = {0};
+ cursorImage.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ cursorImage.bmiHeader.biWidth = img->width();
+ cursorImage.bmiHeader.biHeight = img->height();
+ cursorImage.bmiHeader.biPlanes = 1;
+ cursorImage.bmiHeader.biBitCount = 32;
+ cursorImage.bmiHeader.biCompression = BI_RGB;
+ HDC dc = GetDC(0);
+ HDC workingDC = CreateCompatibleDC(dc);
+ if (doAlpha) {
+ OwnPtr<HBITMAP> hCursor(CreateDIBSection(dc, (BITMAPINFO *)&cursorImage, DIB_RGB_COLORS, 0, 0, 0));
+ ASSERT(hCursor);
+
+ img->getHBITMAP(hCursor.get());
+ HBITMAP hOldBitmap = (HBITMAP)SelectObject(workingDC, hCursor.get());
+ SetBkMode(workingDC, TRANSPARENT);
+ SelectObject(workingDC, hOldBitmap);
+
+ OwnPtr<HBITMAP> hMask(CreateBitmap(img->width(), img->height(), 1, 1, NULL));
+
+ ICONINFO ii;
+ ii.fIcon = FALSE;
+ ii.xHotspot = hotspot.x();
+ ii.yHotspot = hotspot.y();
+ ii.hbmMask = hMask.get();
+ ii.hbmColor = hCursor.get();
+
+ m_impl = new SharedCursor(CreateIconIndirect(&ii));
+ } else {
+ // Platform doesn't support alpha blended cursors, so we need
+ // to create the mask manually
+ HDC andMaskDC = CreateCompatibleDC(dc);
+ HDC xorMaskDC = CreateCompatibleDC(dc);
+ OwnPtr<HBITMAP> hCursor(CreateDIBSection(dc, &cursorImage, DIB_RGB_COLORS, 0, 0, 0));
+ ASSERT(hCursor);
+ img->getHBITMAP(hCursor.get());
+ BITMAP cursor;
+ GetObject(hCursor.get(), sizeof(BITMAP), &cursor);
+ OwnPtr<HBITMAP> andMask(CreateBitmap(cursor.bmWidth, cursor.bmHeight, 1, 1, NULL));
+ OwnPtr<HBITMAP> xorMask(CreateCompatibleBitmap(dc, cursor.bmWidth, cursor.bmHeight));
+ HBITMAP oldCursor = (HBITMAP)SelectObject(workingDC, hCursor.get());
+ HBITMAP oldAndMask = (HBITMAP)SelectObject(andMaskDC, andMask.get());
+ HBITMAP oldXorMask = (HBITMAP)SelectObject(xorMaskDC, xorMask.get());
+
+ SetBkColor(workingDC, RGB(0,0,0));
+ BitBlt(andMaskDC, 0, 0, cursor.bmWidth, cursor.bmHeight, workingDC, 0, 0, SRCCOPY);
+
+ SetBkColor(xorMaskDC, RGB(255, 255, 255));
+ SetTextColor(xorMaskDC, RGB(255, 255, 255));
+ BitBlt(xorMaskDC, 0, 0, cursor.bmWidth, cursor.bmHeight, andMaskDC, 0, 0, SRCCOPY);
+ BitBlt(xorMaskDC, 0, 0, cursor.bmWidth, cursor.bmHeight, workingDC, 0,0, SRCAND);
+
+ SelectObject(workingDC, oldCursor);
+ SelectObject(andMaskDC, oldAndMask);
+ SelectObject(xorMaskDC, oldXorMask);
+
+ ICONINFO icon = {0};
+ icon.fIcon = FALSE;
+ icon.xHotspot = hotspot.x();
+ icon.yHotspot = hotspot.y();
+ icon.hbmMask = andMask.get();
+ icon.hbmColor = xorMask.get();
+ m_impl = new SharedCursor(CreateIconIndirect(&icon));
+
+ DeleteDC(xorMaskDC);
+ DeleteDC(andMaskDC);
+ }
+ DeleteDC(workingDC);
+ ReleaseDC(0, dc);
+}
+
+Cursor::~Cursor()
+{
+}
+
+Cursor& Cursor::operator=(const Cursor& other)
+{
+ m_impl = other.m_impl;
+ return *this;
+}
+
+Cursor::Cursor(PlatformCursor c)
+ : m_impl(c)
+{
+}
+
+static Cursor loadCursorByName(char* name, int x, int y)
+{
+ IntPoint hotSpot(x, y);
+ Cursor c;
+ OwnPtr<Image> cursorImage(Image::loadPlatformResource(name));
+ if (cursorImage && !cursorImage->isNull())
+ c = Cursor(cursorImage.get(), hotSpot);
+ else
+ c = pointerCursor();
+ return c;
+}
+
+static PassRefPtr<SharedCursor> loadSharedCursor(HINSTANCE hInstance, LPCTSTR lpCursorName)
+{
+ return new SharedCursor(LoadCursor(hInstance, lpCursorName));
+}
+
+const Cursor& pointerCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_ARROW);
+ return c;
+}
+
+const Cursor& crossCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_CROSS);
+ return c;
+}
+
+const Cursor& handCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_HAND);
+ return c;
+}
+
+const Cursor& iBeamCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_IBEAM);
+ return c;
+}
+
+const Cursor& waitCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_WAIT);
+ return c;
+}
+
+const Cursor& helpCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_HELP);
+ return c;
+}
+
+const Cursor& eastResizeCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_SIZEWE);
+ return c;
+}
+
+const Cursor& northResizeCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_SIZENS);
+ return c;
+}
+
+const Cursor& northEastResizeCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_SIZENESW);
+ return c;
+}
+
+const Cursor& northWestResizeCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_SIZENWSE);
+ return c;
+}
+
+const Cursor& southResizeCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_SIZENS);
+ return c;
+}
+
+const Cursor& southEastResizeCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_SIZENWSE);
+ return c;
+}
+
+const Cursor& southWestResizeCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_SIZENESW);
+ return c;
+}
+
+const Cursor& westResizeCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_SIZEWE);
+ return c;
+}
+
+const Cursor& northSouthResizeCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_SIZENS);
+ return c;
+}
+
+const Cursor& eastWestResizeCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_SIZEWE);
+ return c;
+}
+
+const Cursor& northEastSouthWestResizeCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_SIZENESW);
+ return c;
+}
+
+const Cursor& northWestSouthEastResizeCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_SIZENWSE);
+ return c;
+}
+
+const Cursor& columnResizeCursor()
+{
+ // FIXME: Windows does not have a standard column resize cursor <rdar://problem/5018591>
+ static Cursor c = loadSharedCursor(0, IDC_SIZEWE);
+ return c;
+}
+
+const Cursor& rowResizeCursor()
+{
+ // FIXME: Windows does not have a standard row resize cursor <rdar://problem/5018591>
+ static Cursor c = loadSharedCursor(0, IDC_SIZENS);
+ return c;
+}
+
+const Cursor& moveCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_SIZEALL);
+ return c;
+}
+
+const Cursor& verticalTextCursor()
+{
+ static const Cursor c = loadCursorByName("verticalTextCursor", 7, 7);
+ return c;
+}
+
+const Cursor& cellCursor()
+{
+ return pointerCursor();
+}
+
+const Cursor& contextMenuCursor()
+{
+ return pointerCursor();
+}
+
+const Cursor& aliasCursor()
+{
+ return pointerCursor();
+}
+
+const Cursor& progressCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_APPSTARTING);
+ return c;
+}
+
+const Cursor& noDropCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_NO);
+ return c;
+}
+
+const Cursor& copyCursor()
+{
+ return pointerCursor();
+}
+
+const Cursor& noneCursor()
+{
+ return pointerCursor();
+}
+
+const Cursor& notAllowedCursor()
+{
+ static Cursor c = loadSharedCursor(0, IDC_NO);
+ return c;
+}
+
+const Cursor& zoomInCursor()
+{
+ static const Cursor c = loadCursorByName("zoomInCursor", 7, 7);
+ return c;
+}
+
+const Cursor& zoomOutCursor()
+{
+ static const Cursor c = loadCursorByName("zoomOutCursor", 7, 7);
+ return c;
+}
+
+}
diff --git a/WebCore/platform/win/DragDataWin.cpp b/WebCore/platform/win/DragDataWin.cpp
new file mode 100644
index 0000000..26f72d6
--- /dev/null
+++ b/WebCore/platform/win/DragDataWin.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2007 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 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 "DragData.h"
+
+#include "ClipboardWin.h"
+#include "ClipboardUtilitiesWin.h"
+#include "ClipboardAccessPolicy.h"
+#include "DocumentFragment.h"
+#include "PlatformString.h"
+#include "Markup.h"
+#include "TextEncoding.h"
+#include <objidl.h>
+#include <shlwapi.h>
+#include <wininet.h>
+
+namespace WebCore {
+
+Clipboard* DragData::createClipboard(ClipboardAccessPolicy policy) const
+{
+ return new ClipboardWin(true, m_platformDragData, policy);
+}
+
+bool DragData::containsURL() const
+{
+ return SUCCEEDED(m_platformDragData->QueryGetData(urlWFormat()))
+ || SUCCEEDED(m_platformDragData->QueryGetData(urlFormat()))
+ || SUCCEEDED(m_platformDragData->QueryGetData(filenameWFormat()))
+ || SUCCEEDED(m_platformDragData->QueryGetData(filenameFormat()));
+}
+
+String DragData::asURL(String* title) const
+{
+ bool success;
+ return getURL(m_platformDragData, success, title);
+}
+
+bool DragData::containsFiles() const
+{
+ return SUCCEEDED(m_platformDragData->QueryGetData(cfHDropFormat()));
+}
+
+void DragData::asFilenames(Vector<String>& result) const
+{
+ WCHAR filename[MAX_PATH];
+
+ STGMEDIUM medium;
+ if (FAILED(m_platformDragData->GetData(cfHDropFormat(), &medium)))
+ return;
+
+ HDROP hdrop = (HDROP)GlobalLock(medium.hGlobal);
+
+ if (!hdrop)
+ return;
+
+ const unsigned numFiles = DragQueryFileW(hdrop, 0xFFFFFFFF, 0, 0);
+ for (unsigned i = 0; i < numFiles; i++) {
+ if (!DragQueryFileW(hdrop, 0, filename, ARRAYSIZE(filename)))
+ continue;
+ result.append((UChar*)filename);
+ }
+
+ // Free up memory from drag
+ DragFinish(hdrop);
+
+ GlobalUnlock(medium.hGlobal);
+}
+
+bool DragData::containsPlainText() const
+{
+ return SUCCEEDED(m_platformDragData->QueryGetData(plainTextWFormat()))
+ || SUCCEEDED(m_platformDragData->QueryGetData(plainTextFormat()));
+}
+
+String DragData::asPlainText() const
+{
+ bool success;
+ return getPlainText(m_platformDragData, success);
+}
+
+bool DragData::containsColor() const
+{
+ return false;
+}
+
+bool DragData::canSmartReplace() const
+{
+ return SUCCEEDED(m_platformDragData->QueryGetData(smartPasteFormat()));
+}
+
+bool DragData::containsCompatibleContent() const
+{
+ return containsPlainText() || containsURL()
+ || containsHTML(m_platformDragData)
+ || containsFilenames(m_platformDragData)
+ || containsColor();
+}
+
+PassRefPtr<DocumentFragment> DragData::asFragment(Document* doc) const
+{
+ /*
+ * Order is richest format first. On OSX this is:
+ * * Web Archive
+ * * Filenames
+ * * HTML
+ * * RTF
+ * * TIFF
+ * * PICT
+ */
+
+ if (containsFilenames(m_platformDragData))
+ if (PassRefPtr<DocumentFragment> fragment = fragmentFromFilenames(doc, m_platformDragData))
+ return fragment;
+
+ if (containsHTML(m_platformDragData))
+ if (PassRefPtr<DocumentFragment> fragment = fragmentFromHTML(doc, m_platformDragData))
+ return fragment;
+
+ return 0;
+}
+
+Color DragData::asColor() const
+{
+ return Color();
+}
+
+}
+
diff --git a/WebCore/platform/win/DragImageCGWin.cpp b/WebCore/platform/win/DragImageCGWin.cpp
new file mode 100644
index 0000000..7788572
--- /dev/null
+++ b/WebCore/platform/win/DragImageCGWin.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2007, 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 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 "DragImage.h"
+
+#include "CachedImage.h"
+#include "GraphicsContext.h"
+#include "Image.h"
+#include "RetainPtr.h"
+
+#include <CoreGraphics/CoreGraphics.h>
+
+#include <windows.h>
+
+namespace WebCore {
+
+HBITMAP allocImage(HDC dc, IntSize size, CGContextRef *targetRef)
+{
+ HBITMAP hbmp;
+ BITMAPINFO bmpInfo = {0};
+ bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmpInfo.bmiHeader.biWidth = size.width();
+ bmpInfo.bmiHeader.biHeight = size.height();
+ bmpInfo.bmiHeader.biPlanes = 1;
+ bmpInfo.bmiHeader.biBitCount = 32;
+ bmpInfo.bmiHeader.biCompression = BI_RGB;
+ LPVOID bits;
+ hbmp = CreateDIBSection(dc, &bmpInfo, DIB_RGB_COLORS, &bits, 0, 0);
+
+ if (!targetRef)
+ return hbmp;
+
+ CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
+ CGContextRef bitmapContext = CGBitmapContextCreate(bits, bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight, 8,
+ bmpInfo.bmiHeader.biWidth * 4, deviceRGB,
+ kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst);
+ CGColorSpaceRelease(deviceRGB);
+ if (!bitmapContext) {
+ DeleteObject(hbmp);
+ return 0;
+ }
+
+ *targetRef = bitmapContext;
+ return hbmp;
+}
+
+static CGContextRef createCgContextFromBitmap(HBITMAP bitmap)
+{
+ BITMAP info;
+ GetObject(bitmap, sizeof(info), &info);
+ ASSERT(info.bmBitsPixel == 32);
+
+ CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB();
+ CGContextRef bitmapContext = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8,
+ info.bmWidthBytes, deviceRGB, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst);
+ CGColorSpaceRelease(deviceRGB);
+ return bitmapContext;
+}
+
+DragImageRef scaleDragImage(DragImageRef image, FloatSize scale)
+{
+ // FIXME: due to the way drag images are done on windows we need
+ // to preprocess the alpha channel <rdar://problem/5015946>
+
+ if (!image)
+ return 0;
+ CGContextRef targetContext;
+ CGContextRef srcContext;
+ CGImageRef srcImage;
+ IntSize srcSize = dragImageSize(image);
+ IntSize dstSize(static_cast<int>(srcSize.width() * scale.width()), static_cast<int>(srcSize.height() * scale.height()));
+ HBITMAP hbmp = 0;
+ HDC dc = GetDC(0);
+ HDC dstDC = CreateCompatibleDC(dc);
+ if (!dstDC)
+ goto exit;
+
+ hbmp = allocImage(dstDC, dstSize, &targetContext);
+ if (!hbmp)
+ goto exit;
+
+ srcContext = createCgContextFromBitmap(image);
+ srcImage = CGBitmapContextCreateImage(srcContext);
+ CGRect rect;
+ rect.origin.x = 0;
+ rect.origin.y = 0;
+ rect.size = dstSize;
+ CGContextDrawImage(targetContext, rect, srcImage);
+ CGImageRelease(srcImage);
+ CGContextRelease(srcContext);
+ CGContextRelease(targetContext);
+ ::DeleteObject(image);
+ image = 0;
+
+exit:
+ if (!hbmp)
+ hbmp = image;
+ if (dstDC)
+ DeleteDC(dstDC);
+ ReleaseDC(0, dc);
+ return hbmp;
+}
+
+DragImageRef createDragImageFromImage(Image* img)
+{
+ HBITMAP hbmp = 0;
+ HDC dc = GetDC(0);
+ HDC workingDC = CreateCompatibleDC(dc);
+ CGContextRef drawContext = 0;
+ if (!workingDC)
+ goto exit;
+
+ hbmp = allocImage(workingDC, img->size(), &drawContext);
+
+ if (!hbmp)
+ goto exit;
+
+ if (!drawContext) {
+ ::DeleteObject(hbmp);
+ hbmp = 0;
+ }
+
+ CGImageRef srcImage = img->getCGImageRef();
+ CGRect rect;
+ rect.size = img->size();
+ rect.origin.x = 0;
+ rect.origin.y = -rect.size.height;
+ static const CGFloat white [] = {1.0, 1.0, 1.0, 1.0};
+ CGContextScaleCTM(drawContext, 1, -1);
+ CGContextSetFillColor(drawContext, white);
+ CGContextFillRect(drawContext, rect);
+ CGContextSetBlendMode(drawContext, kCGBlendModeNormal);
+ CGContextDrawImage(drawContext, rect, srcImage);
+ CGContextRelease(drawContext);
+
+exit:
+ if (workingDC)
+ DeleteDC(workingDC);
+ ReleaseDC(0, dc);
+ return hbmp;
+}
+
+}
diff --git a/WebCore/platform/win/DragImageCairoWin.cpp b/WebCore/platform/win/DragImageCairoWin.cpp
new file mode 100644
index 0000000..5fff64f
--- /dev/null
+++ b/WebCore/platform/win/DragImageCairoWin.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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 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 "DragImage.h"
+
+#include "CachedImage.h"
+#include "GraphicsContext.h"
+#include "Image.h"
+#include "NotImplemented.h"
+#include "RetainPtr.h"
+
+#include <windows.h>
+
+namespace WebCore {
+
+DragImageRef scaleDragImage(DragImageRef image, FloatSize scale)
+{
+ notImplemented();
+
+ return image;
+}
+
+DragImageRef createDragImageFromImage(Image* img)
+{
+ notImplemented();
+
+ return 0;
+}
+
+}
diff --git a/WebCore/platform/win/DragImageWin.cpp b/WebCore/platform/win/DragImageWin.cpp
new file mode 100644
index 0000000..46146b3
--- /dev/null
+++ b/WebCore/platform/win/DragImageWin.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007, 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 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 "DragImage.h"
+
+#include "CachedImage.h"
+#include "GraphicsContext.h"
+#include "Image.h"
+#include "RetainPtr.h"
+
+#include <windows.h>
+
+namespace WebCore {
+
+IntSize dragImageSize(DragImageRef image)
+{
+ if (!image)
+ return IntSize();
+ BITMAP b;
+ GetObject(image, sizeof(BITMAP), &b);
+ return IntSize(b.bmWidth, b.bmHeight);
+}
+
+void deleteDragImage(DragImageRef image)
+{
+ if (image)
+ ::DeleteObject(image);
+}
+
+DragImageRef dissolveDragImageToFraction(DragImageRef image, float)
+{
+ //We don't do this on windows as the dragimage is blended by the OS
+ return image;
+}
+
+DragImageRef createDragImageIconForCachedImage(CachedImage*)
+{
+ //FIXME: Provide icon for image type <rdar://problem/5015949>
+ return 0;
+}
+
+}
diff --git a/WebCore/platform/win/EditorWin.cpp b/WebCore/platform/win/EditorWin.cpp
new file mode 100644
index 0000000..5738a64
--- /dev/null
+++ b/WebCore/platform/win/EditorWin.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2006, 2007 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 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 "Editor.h"
+#include "EditorClient.h"
+
+#include "ClipboardWin.h"
+#include "Document.h"
+#include "Element.h"
+#include "htmlediting.h"
+#include "NotImplemented.h"
+#include "TextIterator.h"
+#include "visible_units.h"
+
+#include <windows.h>
+
+namespace WebCore {
+
+PassRefPtr<Clipboard> Editor::newGeneralClipboard(ClipboardAccessPolicy policy)
+{
+ COMPtr<IDataObject> clipboardData;
+ if (!SUCCEEDED(OleGetClipboard(&clipboardData)))
+ clipboardData = 0;
+
+ return new ClipboardWin(false, clipboardData.get(), policy);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/win/FileChooserWin.cpp b/WebCore/platform/win/FileChooserWin.cpp
new file mode 100644
index 0000000..1bc4681
--- /dev/null
+++ b/WebCore/platform/win/FileChooserWin.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2006, 2007 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 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 "Document.h"
+#include "FrameView.h"
+#include "Icon.h"
+#include "LocalizedStrings.h"
+#include "RenderObject.h"
+#include "RenderThemeWin.h"
+#include "RenderView.h"
+#include "StringTruncator.h"
+#include <shlwapi.h>
+#include <tchar.h>
+#include <windows.h>
+
+namespace WebCore {
+
+FileChooser::FileChooser(FileChooserClient* client, const String& filename)
+ : RefCounted<FileChooser>(0)
+ , m_client(client)
+ , m_filename(filename)
+ , m_icon(chooseIcon(filename))
+{
+}
+
+FileChooser::~FileChooser()
+{
+}
+
+void FileChooser::openFileChooser(Document* document)
+{
+ FrameView* view = document->view();
+ if (!view)
+ return;
+
+ TCHAR fileBuf[MAX_PATH];
+ OPENFILENAME ofn;
+
+ memset(&ofn, 0, sizeof(ofn));
+
+ // Need to zero out the first char of fileBuf so GetOpenFileName doesn't think it's an initialization string
+ fileBuf[0] = '\0';
+
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = view->containingWindow();
+ String allFiles = allFilesText();
+ allFiles.append(TEXT("\0*.*\0\0"), 6);
+ ofn.lpstrFilter = allFiles.charactersWithNullTermination();
+ ofn.lpstrFile = fileBuf;
+ ofn.nMaxFile = sizeof(fileBuf);
+ String dialogTitle = uploadFileText();
+ ofn.lpstrTitle = dialogTitle.charactersWithNullTermination();
+ ofn.Flags = OFN_ENABLESIZING | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
+
+ // We need this protector because otherwise we can be deleted if the file upload control is detached while
+ // we're within the GetOpenFileName call.
+ RefPtr<FileChooser> protector(this);
+
+ if (GetOpenFileName(&ofn))
+ chooseFile(String(fileBuf));
+}
+
+String FileChooser::basenameForWidth(const Font& font, int width) const
+{
+ if (width <= 0)
+ return String();
+
+ String string;
+ if (m_filename.isEmpty())
+ string = fileButtonNoFileSelectedLabel();
+ else {
+ String tmpFilename = m_filename;
+ LPTSTR basename = PathFindFileName(tmpFilename.charactersWithNullTermination());
+ string = String(basename);
+ }
+
+ return StringTruncator::centerTruncate(string, width, font, false);
+}
+
+} \ No newline at end of file
diff --git a/WebCore/platform/win/FileSystemWin.cpp b/WebCore/platform/win/FileSystemWin.cpp
new file mode 100644
index 0000000..2a6c5d1
--- /dev/null
+++ b/WebCore/platform/win/FileSystemWin.cpp
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 "FileSystem.h"
+
+#include "CString.h"
+#include "NotImplemented.h"
+#include "PlatformString.h"
+
+#include <windows.h>
+#include <winbase.h>
+#include <shlobj.h>
+#include <shlwapi.h>
+
+namespace WebCore {
+
+static bool statFile(String path, struct _stat64& st)
+{
+ ASSERT_ARG(path, !path.isNull());
+ return !_wstat64(path.charactersWithNullTermination(), &st) && (st.st_mode & _S_IFMT) == _S_IFREG;
+}
+
+bool getFileSize(const String& path, long long& result)
+{
+ struct _stat64 sb;
+ if (!statFile(path, sb))
+ return false;
+ result = sb.st_size;
+ return true;
+}
+
+bool getFileModificationTime(const String& path, time_t& result)
+{
+ struct _stat64 st;
+ if (!statFile(path, st))
+ return false;
+ result = st.st_mtime;
+ return true;
+}
+
+bool fileExists(const String& path)
+{
+ struct _stat64 st;
+ return statFile(path, st);
+}
+
+bool deleteFile(const String& path)
+{
+ String filename = path;
+ return !!DeleteFileW(filename.charactersWithNullTermination());
+}
+
+bool deleteEmptyDirectory(const String& path)
+{
+ String filename = path;
+ return !!RemoveDirectoryW(filename.charactersWithNullTermination());
+}
+
+String pathByAppendingComponent(const String& path, const String& component)
+{
+ Vector<UChar> buffer(MAX_PATH);
+
+ if (path.length() + 1 > buffer.size())
+ return String();
+
+ memcpy(buffer.data(), path.characters(), path.length() * sizeof(UChar));
+ buffer[path.length()] = '\0';
+
+ String componentCopy = component;
+ if (!PathAppendW(buffer.data(), componentCopy.charactersWithNullTermination()))
+ return String();
+
+ buffer.resize(wcslen(buffer.data()));
+
+ return String::adopt(buffer);
+}
+
+CString fileSystemRepresentation(const String&)
+{
+ return "";
+}
+
+bool makeAllDirectories(const String& path)
+{
+ String fullPath = path;
+ if (SHCreateDirectoryEx(0, fullPath.charactersWithNullTermination(), 0) != ERROR_SUCCESS) {
+ DWORD error = GetLastError();
+ if (error != ERROR_FILE_EXISTS && error != ERROR_ALREADY_EXISTS) {
+ LOG_ERROR("Failed to create path %s", path.ascii().data());
+ return false;
+ }
+ }
+ return true;
+}
+
+String homeDirectoryPath()
+{
+ notImplemented();
+ return "";
+}
+
+String pathGetFileName(const String& path)
+{
+ return String(PathFindFileName(String(path).charactersWithNullTermination()));
+}
+
+static String bundleName()
+{
+ static bool initialized;
+ static String name = "WebKit";
+
+ if (!initialized) {
+ initialized = true;
+
+ if (CFBundleRef bundle = CFBundleGetMainBundle())
+ if (CFTypeRef bundleExecutable = CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleExecutableKey))
+ if (CFGetTypeID(bundleExecutable) == CFStringGetTypeID())
+ name = reinterpret_cast<CFStringRef>(bundleExecutable);
+ }
+
+ return name;
+}
+
+static String storageDirectory(DWORD pathIdentifier)
+{
+ Vector<UChar> buffer(MAX_PATH);
+ if (FAILED(SHGetFolderPathW(0, pathIdentifier | CSIDL_FLAG_CREATE, 0, 0, buffer.data())))
+ return String();
+ buffer.resize(wcslen(buffer.data()));
+ String directory = String::adopt(buffer);
+
+ static const String companyNameDirectory = "Apple Computer\\";
+ directory = pathByAppendingComponent(directory, companyNameDirectory + bundleName());
+ if (!makeAllDirectories(directory))
+ return String();
+
+ return directory;
+}
+
+static String cachedStorageDirectory(DWORD pathIdentifier)
+{
+ static HashMap<DWORD, String> directories;
+
+ HashMap<DWORD, String>::iterator it = directories.find(pathIdentifier);
+ if (it != directories.end())
+ return it->second;
+
+ String directory = storageDirectory(pathIdentifier);
+ directories.add(pathIdentifier, directory);
+
+ return directory;
+}
+
+
+CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle)
+{
+ char tempPath[MAX_PATH];
+ int tempPathLength = ::GetTempPathA(_countof(tempPath), tempPath);
+ if (tempPathLength <= 0 || tempPathLength > _countof(tempPath))
+ return 0;
+
+ char tempFile[MAX_PATH];
+ if (::GetTempFileNameA(tempPath, prefix, 0, tempFile) > 0) {
+ HANDLE tempHandle = ::CreateFileA(tempFile, GENERIC_READ | GENERIC_WRITE, 0, 0,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (isHandleValid(tempHandle)) {
+ handle = tempHandle;
+ return tempFile;
+ }
+ }
+ return 0;
+}
+
+void closeFile(PlatformFileHandle& handle)
+{
+ if (isHandleValid(handle)) {
+ ::CloseHandle(handle);
+ handle = invalidPlatformFileHandle;
+ }
+}
+
+int writeToFile(PlatformFileHandle handle, const char* data, int length)
+{
+ if (!isHandleValid(handle))
+ return -1;
+
+ DWORD bytesWritten;
+ bool success = WriteFile(handle, data, length, &bytesWritten, 0);
+
+ if (!success)
+ return -1;
+ return static_cast<int>(bytesWritten);
+}
+
+bool unloadModule(PlatformModule module)
+{
+ return ::FreeLibrary(module);
+}
+
+String localUserSpecificStorageDirectory()
+{
+ return cachedStorageDirectory(CSIDL_LOCAL_APPDATA);
+}
+
+String roamingUserSpecificStorageDirectory()
+{
+ return cachedStorageDirectory(CSIDL_APPDATA);
+}
+
+bool safeCreateFile(const String& path, CFDataRef data)
+{
+ // Create a temporary file.
+ WCHAR tempDirPath[MAX_PATH];
+ if (!GetTempPathW(ARRAYSIZE(tempDirPath), tempDirPath))
+ return false;
+
+ WCHAR tempPath[MAX_PATH];
+ if (!GetTempFileNameW(tempDirPath, L"WEBKIT", 0, tempPath))
+ return false;
+
+ HANDLE tempFileHandle = CreateFileW(tempPath, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+ if (tempFileHandle == INVALID_HANDLE_VALUE)
+ return false;
+
+ // Write the data to this temp file.
+ DWORD written;
+ if (!WriteFile(tempFileHandle, CFDataGetBytePtr(data), static_cast<DWORD>(CFDataGetLength(data)), &written, 0))
+ return false;
+
+ CloseHandle(tempFileHandle);
+
+ // Copy the temp file to the destination file.
+ String destination = path;
+ if (!MoveFileExW(tempPath, destination.charactersWithNullTermination(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
+ return false;
+
+ return true;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/win/GDIObjectCounter.cpp b/WebCore/platform/win/GDIObjectCounter.cpp
new file mode 100644
index 0000000..3cc5bcb
--- /dev/null
+++ b/WebCore/platform/win/GDIObjectCounter.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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"
+
+#ifndef NDEBUG
+
+#include "GDIObjectCounter.h"
+
+#include "CString.h"
+#include "Logging.h"
+
+#include <windows.h>
+
+namespace WebCore {
+
+GDIObjectCounter::GDIObjectCounter(const String& identifier)
+{
+ init(identifier);
+}
+
+GDIObjectCounter::GDIObjectCounter(const String& className, void* instance)
+{
+ init(String::format("%s (%p)", className.latin1().data(), instance));
+}
+
+void GDIObjectCounter::init(const String& identifier)
+{
+ m_identifier = identifier;
+ m_startCount = currentGDIObjectsInUse();
+ m_endCount = 0;
+}
+
+GDIObjectCounter::~GDIObjectCounter()
+{
+ m_endCount = currentGDIObjectsInUse();
+ int leaked = m_endCount - m_startCount;
+ if (leaked != 0)
+ LOG(PlatformLeaks, "%s: leaked %d GDI object%s!", m_identifier.latin1().data(), leaked, leaked == 1 ? "" : "s");
+}
+
+unsigned GDIObjectCounter::currentGDIObjectsInUse()
+{
+ return ::GetGuiResources(::GetCurrentProcess(), GR_GDIOBJECTS);
+}
+
+} // namespace WebCore
+
+#endif // !defined(NDEBUG)
diff --git a/WebCore/platform/win/GDIObjectCounter.h b/WebCore/platform/win/GDIObjectCounter.h
new file mode 100644
index 0000000..9b9bd12
--- /dev/null
+++ b/WebCore/platform/win/GDIObjectCounter.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2007 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 GDIObjectCounter_h
+#define GDIObjectCounter_h
+
+#ifdef NDEBUG
+#define LOCAL_GDI_COUNTER(num, identifier) ((void)0)
+#else
+#define LOCAL_GDI_COUNTER(num, identifier) GDIObjectCounter counter##num(identifier)
+#endif
+
+#ifndef NDEBUG
+
+#include "PlatformString.h"
+
+namespace WebCore {
+
+ class GDIObjectCounter {
+ public:
+ GDIObjectCounter(const String& identifier);
+ GDIObjectCounter(const String& className, void* instance);
+ ~GDIObjectCounter();
+
+ static unsigned currentGDIObjectsInUse();
+
+ private:
+ void init(const String& identifier);
+ String m_identifier;
+ unsigned m_startCount;
+ unsigned m_endCount;
+ };
+
+} // namespace WebCore
+
+#endif // !defined(NDEBUG)
+
+#endif // !defined(GDIObjectCounter_h)
diff --git a/WebCore/platform/win/KeyEventWin.cpp b/WebCore/platform/win/KeyEventWin.cpp
new file mode 100644
index 0000000..c8f3ffa
--- /dev/null
+++ b/WebCore/platform/win/KeyEventWin.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2006, 2007 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 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 <windows.h>
+#include <wtf/ASCIICType.h>
+
+using namespace WTF;
+
+namespace WebCore {
+
+static const unsigned short HIGH_BIT_MASK_SHORT = 0x8000;
+
+// FIXME: This is incomplete. We could change this to mirror
+// more like what Firefox does, and generate these switch statements
+// at build time.
+static String keyIdentifierForWindowsKeyCode(unsigned short keyCode)
+{
+ switch (keyCode) {
+ case VK_MENU:
+ return "Alt";
+ case VK_CONTROL:
+ return "Control";
+ case VK_SHIFT:
+ return "Shift";
+ case VK_CAPITAL:
+ return "CapsLock";
+ case VK_LWIN:
+ case VK_RWIN:
+ return "Win";
+ case VK_CLEAR:
+ return "Clear";
+ case VK_DOWN:
+ return "Down";
+ // "End"
+ case VK_END:
+ return "End";
+ // "Enter"
+ case VK_RETURN:
+ return "Enter";
+ case VK_EXECUTE:
+ return "Execute";
+ case VK_F1:
+ return "F1";
+ case VK_F2:
+ return "F2";
+ case VK_F3:
+ return "F3";
+ case VK_F4:
+ return "F4";
+ case VK_F5:
+ return "F5";
+ case VK_F6:
+ return "F6";
+ case VK_F7:
+ return "F7";
+ case VK_F8:
+ return "F8";
+ case VK_F9:
+ return "F9";
+ case VK_F10:
+ return "F11";
+ case VK_F12:
+ return "F12";
+ case VK_F13:
+ return "F13";
+ case VK_F14:
+ return "F14";
+ case VK_F15:
+ return "F15";
+ case VK_F16:
+ return "F16";
+ case VK_F17:
+ return "F17";
+ case VK_F18:
+ return "F18";
+ case VK_F19:
+ return "F19";
+ case VK_F20:
+ return "F20";
+ case VK_F21:
+ return "F21";
+ case VK_F22:
+ return "F22";
+ case VK_F23:
+ return "F23";
+ case VK_F24:
+ return "F24";
+ case VK_HELP:
+ return "Help";
+ case VK_HOME:
+ return "Home";
+ case VK_INSERT:
+ return "Insert";
+ case VK_LEFT:
+ return "Left";
+ case VK_NEXT:
+ return "PageDown";
+ case VK_PRIOR:
+ return "PageUp";
+ case VK_PAUSE:
+ return "Pause";
+ case VK_SNAPSHOT:
+ return "PrintScreen";
+ case VK_RIGHT:
+ return "Right";
+ case VK_SCROLL:
+ return "Scroll";
+ case VK_SELECT:
+ return "Select";
+ case VK_UP:
+ return "Up";
+ // Standard says that DEL becomes U+007F.
+ case VK_DELETE:
+ return "U+007F";
+ default:
+ return String::format("U+%04X", toASCIIUpper(keyCode));
+ }
+}
+
+static bool isKeypadEvent(WPARAM code, LPARAM keyData, PlatformKeyboardEvent::Type type)
+{
+ if (type != PlatformKeyboardEvent::RawKeyDown && type != PlatformKeyboardEvent::KeyUp)
+ return false;
+
+ switch (code) {
+ case VK_NUMLOCK:
+ case VK_NUMPAD0:
+ case VK_NUMPAD1:
+ case VK_NUMPAD2:
+ case VK_NUMPAD3:
+ case VK_NUMPAD4:
+ case VK_NUMPAD5:
+ case VK_NUMPAD6:
+ case VK_NUMPAD7:
+ case VK_NUMPAD8:
+ case VK_NUMPAD9:
+ case VK_MULTIPLY:
+ case VK_ADD:
+ case VK_SEPARATOR:
+ case VK_SUBTRACT:
+ case VK_DECIMAL:
+ case VK_DIVIDE:
+ return true;
+ case VK_RETURN:
+ return HIWORD(keyData) & KF_EXTENDED;
+ case VK_INSERT:
+ case VK_DELETE:
+ case VK_PRIOR:
+ case VK_NEXT:
+ case VK_END:
+ case VK_HOME:
+ case VK_LEFT:
+ case VK_UP:
+ case VK_RIGHT:
+ case VK_DOWN:
+ return !(HIWORD(keyData) & KF_EXTENDED);
+ default:
+ return false;
+ }
+}
+
+static inline String singleCharacterString(UChar c) { return String(&c, 1); }
+
+PlatformKeyboardEvent::PlatformKeyboardEvent(HWND, WPARAM code, LPARAM keyData, Type type, bool systemKey)
+ : m_type(type)
+ , m_text((type == Char) ? singleCharacterString(code) : String())
+ , m_unmodifiedText((type == Char) ? singleCharacterString(code) : String())
+ , m_keyIdentifier((type == Char) ? String() : keyIdentifierForWindowsKeyCode(code))
+ , m_autoRepeat(HIWORD(keyData) & KF_REPEAT)
+ , m_windowsVirtualKeyCode((type == RawKeyDown || type == KeyUp) ? code : 0)
+ , m_isKeypad(isKeypadEvent(code, keyData, type))
+ , m_shiftKey(GetKeyState(VK_SHIFT) & HIGH_BIT_MASK_SHORT)
+ , m_ctrlKey(GetKeyState(VK_CONTROL) & HIGH_BIT_MASK_SHORT)
+ , m_altKey(GetKeyState(VK_MENU) & HIGH_BIT_MASK_SHORT)
+ , m_metaKey(false)
+ , m_isSystemKey(systemKey)
+{
+}
+
+void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type, bool)
+{
+ // No KeyDown events on Windows to disambiguate.
+ ASSERT_NOT_REACHED();
+}
+
+bool PlatformKeyboardEvent::currentCapsLockState()
+{
+ return GetKeyState(VK_CAPITAL) & 1;
+}
+
+}
diff --git a/WebCore/platform/win/Language.cpp b/WebCore/platform/win/Language.cpp
new file mode 100644
index 0000000..787c5a3
--- /dev/null
+++ b/WebCore/platform/win/Language.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 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 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 "Language.h"
+
+#include "CString.h"
+#include "PlatformString.h"
+
+namespace WebCore {
+
+static String localeInfo(LCTYPE localeType, const String& fallback)
+{
+ LANGID langID = GetUserDefaultUILanguage();
+ int localeChars = GetLocaleInfo(langID, localeType, 0, 0);
+ if (!localeChars)
+ return fallback;
+ Vector<WCHAR> localeNameBuf(localeChars);
+ localeChars = GetLocaleInfo(langID, localeType, localeNameBuf.data(), localeChars);
+ if (!localeChars)
+ return fallback;
+ String localeName = String::adopt(localeNameBuf);
+ if (localeName.isEmpty())
+ return fallback;
+
+ return localeName;
+}
+
+String defaultLanguage()
+{
+ static String computedDefaultLanguage;
+ if (!computedDefaultLanguage.isEmpty())
+ return computedDefaultLanguage;
+
+ String languageName = localeInfo(LOCALE_SISO639LANGNAME, "en");
+ String countryName = localeInfo(LOCALE_SISO3166CTRYNAME, String());
+
+ if (countryName.isEmpty())
+ computedDefaultLanguage = languageName;
+ else
+ computedDefaultLanguage = String::format("%s-%s", languageName.latin1().data(), countryName.latin1().data());
+
+ return computedDefaultLanguage;
+}
+
+}
diff --git a/WebCore/platform/win/MIMETypeRegistryWin.cpp b/WebCore/platform/win/MIMETypeRegistryWin.cpp
new file mode 100644
index 0000000..06c6f36
--- /dev/null
+++ b/WebCore/platform/win/MIMETypeRegistryWin.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2006, 2007 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 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"
+
+#include <shlwapi.h>
+#include <wtf/HashMap.h>
+
+namespace WebCore
+{
+
+String getMIMETypeForUTI(const String & uti)
+{
+ String mimeType;
+ // FIXME: This is an ugly hack: public.type -> image/type mimetype
+ if (int dotLocation = uti.reverseFind('.')) {
+ mimeType = String("image/")+uti.substring(dotLocation + 1);
+ }
+ return mimeType;
+}
+
+static String mimeTypeForExtension(const String& extension)
+{
+ String ext = "." + extension;
+ WCHAR contentTypeStr[256];
+ DWORD contentTypeStrLen = sizeof(contentTypeStr);
+ DWORD keyType;
+
+ HRESULT result = SHGetValue(HKEY_CLASSES_ROOT, ext.charactersWithNullTermination(), L"Content Type", &keyType, (LPVOID)contentTypeStr, &contentTypeStrLen);
+
+ if (result == ERROR_SUCCESS && keyType == REG_SZ)
+ return String(contentTypeStr, contentTypeStrLen / sizeof(contentTypeStr[0]) - 1);
+
+ return String();
+}
+
+String MIMETypeRegistry::getPreferredExtensionForMIMEType(const String& type)
+{
+ String mimeType;
+
+ int semiColonPos = type.find(';');
+ if (semiColonPos < 0)
+ mimeType = type;
+ else
+ mimeType = type.substring(0, semiColonPos);
+
+ String path = "MIME\\Database\\Content Type\\" + type;
+ WCHAR extStr[MAX_PATH];
+ DWORD extStrLen = sizeof(extStr);
+ DWORD keyType;
+
+ HRESULT result = SHGetValueW(HKEY_CLASSES_ROOT, path.charactersWithNullTermination(), L"Extension", &keyType, (LPVOID)extStr, &extStrLen);
+
+ if (result == ERROR_SUCCESS && keyType == REG_SZ)
+ return String(extStr + 1, extStrLen / sizeof(extStr[0]) - 2);
+
+ return String();
+}
+
+String MIMETypeRegistry::getMIMETypeForExtension(const String &ext)
+{
+ if (ext.isEmpty())
+ return String();
+
+ static HashMap<String, String> mimetypeMap;
+ if (mimetypeMap.isEmpty()) {
+ //fill with initial values
+ mimetypeMap.add("txt", "text/plain");
+ mimetypeMap.add("pdf", "application/pdf");
+ mimetypeMap.add("ps", "application/postscript");
+ mimetypeMap.add("html", "text/html");
+ mimetypeMap.add("htm", "text/html");
+ mimetypeMap.add("xml", "text/xml");
+ mimetypeMap.add("xsl", "text/xsl");
+ mimetypeMap.add("js", "application/x-javascript");
+ mimetypeMap.add("xhtml", "application/xhtml+xml");
+ mimetypeMap.add("rss", "application/rss+xml");
+ mimetypeMap.add("webarchive", "application/x-webarchive");
+ mimetypeMap.add("svg", "image/svg+xml");
+ mimetypeMap.add("svgz", "image/svg+xml");
+ mimetypeMap.add("jpg", "image/jpeg");
+ mimetypeMap.add("jpeg", "image/jpeg");
+ mimetypeMap.add("png", "image/png");
+ mimetypeMap.add("tif", "image/tiff");
+ mimetypeMap.add("tiff", "image/tiff");
+ mimetypeMap.add("ico", "image/ico");
+ mimetypeMap.add("cur", "image/ico");
+ mimetypeMap.add("bmp", "image/bmp");
+ }
+ String result = mimetypeMap.get(ext);
+ if (result.isEmpty()) {
+ result = mimeTypeForExtension(ext);
+ if (!result.isEmpty())
+ mimetypeMap.add(ext, result);
+ }
+ return result;
+}
+
+}
diff --git a/WebCore/platform/win/MainThreadWin.cpp b/WebCore/platform/win/MainThreadWin.cpp
new file mode 100644
index 0000000..6d3493c
--- /dev/null
+++ b/WebCore/platform/win/MainThreadWin.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2007, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 "MainThread.h"
+
+#include "Logging.h"
+#include "Page.h"
+#include <windows.h>
+
+namespace WebCore {
+
+struct FunctionWithContext {
+ MainThreadFunction* function;
+ void* context;
+ FunctionWithContext(MainThreadFunction* f = 0, void* c = 0) : function(f), context(c) { }
+};
+
+typedef Vector<FunctionWithContext> FunctionQueue;
+
+static HWND threadingWindowHandle = 0;
+static UINT threadingFiredMessage = 0;
+const LPCWSTR kThreadingWindowClassName = L"ThreadingWindowClass";
+static bool processingCustomThreadingMessage = false;
+
+static Mutex& functionQueueMutex()
+{
+ static Mutex staticFunctionQueueMutex;
+ return staticFunctionQueueMutex;
+}
+
+static FunctionQueue& functionQueue()
+{
+ static FunctionQueue staticFunctionQueue;
+ return staticFunctionQueue;
+}
+
+static void callFunctionsOnMainThread()
+{
+ FunctionQueue queueCopy;
+ {
+ MutexLocker locker(functionQueueMutex());
+ queueCopy.swap(functionQueue());
+ }
+
+ LOG(Threading, "Calling %u functions on the main thread", queueCopy.size());
+ for (unsigned i = 0; i < queueCopy.size(); ++i)
+ queueCopy[i].function(queueCopy[i].context);
+}
+
+LRESULT CALLBACK ThreadingWindowWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ if (message == threadingFiredMessage) {
+ processingCustomThreadingMessage = true;
+ callFunctionsOnMainThread();
+ processingCustomThreadingMessage = false;
+ } else
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ return 0;
+}
+
+void initializeThreadingAndMainThread()
+{
+ if (threadingWindowHandle)
+ return;
+
+ WTF::initializeThreading();
+
+ WNDCLASSEX wcex;
+ memset(&wcex, 0, sizeof(WNDCLASSEX));
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.lpfnWndProc = ThreadingWindowWndProc;
+ wcex.hInstance = Page::instanceHandle();
+ wcex.lpszClassName = kThreadingWindowClassName;
+ RegisterClassEx(&wcex);
+
+ threadingWindowHandle = CreateWindow(kThreadingWindowClassName, 0, 0,
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, HWND_MESSAGE, 0, Page::instanceHandle(), 0);
+ threadingFiredMessage = RegisterWindowMessage(L"com.apple.WebKit.MainThreadFired");
+}
+
+void callOnMainThread(MainThreadFunction* function, void* context)
+{
+ ASSERT(function);
+ ASSERT(threadingWindowHandle);
+
+ if (processingCustomThreadingMessage)
+ LOG(Threading, "callOnMainThread() called recursively. Beware of nested PostMessage()s");
+
+ {
+ MutexLocker locker(functionQueueMutex());
+ functionQueue().append(FunctionWithContext(function, context));
+ }
+
+ PostMessage(threadingWindowHandle, threadingFiredMessage, 0, 0);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/win/PasteboardWin.cpp b/WebCore/platform/win/PasteboardWin.cpp
new file mode 100644
index 0000000..506cc7b
--- /dev/null
+++ b/WebCore/platform/win/PasteboardWin.cpp
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2006, 2007 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 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 "Pasteboard.h"
+
+#include "CString.h"
+#include "ClipboardUtilitiesWin.h"
+#include "Document.h"
+#include "DocumentFragment.h"
+#include "Element.h"
+#include "Frame.h"
+#include "HitTestResult.h"
+#include "Image.h"
+#include "KURL.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "Range.h"
+#include "RenderImage.h"
+#include "TextEncoding.h"
+#include "markup.h"
+
+namespace WebCore {
+
+static UINT HTMLClipboardFormat = 0;
+static UINT BookmarkClipboardFormat = 0;
+static UINT WebSmartPasteFormat = 0;
+
+static LRESULT CALLBACK PasteboardOwnerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT lresult = 0;
+ LONG_PTR longPtr = GetWindowLongPtr(hWnd, 0);
+
+ switch(message) {
+ case WM_RENDERFORMAT:
+ // This message comes when SetClipboardData was sent a null data handle
+ // and now it's come time to put the data on the clipboard.
+ break;
+ case WM_RENDERALLFORMATS:
+ // This message comes when SetClipboardData was sent a null data handle
+ // and now this application is about to quit, so it must put data on
+ // the clipboard before it exits.
+ break;
+ case WM_DRAWCLIPBOARD:
+ break;
+ case WM_DESTROY:
+ break;
+ case WM_CHANGECBCHAIN:
+ break;
+ default:
+ lresult = DefWindowProc(hWnd, message, wParam, lParam);
+ break;
+ }
+ return lresult;
+}
+
+Pasteboard* Pasteboard::generalPasteboard()
+{
+ static Pasteboard* pasteboard = new Pasteboard;
+ return pasteboard;
+}
+
+Pasteboard::Pasteboard()
+{
+ // make a dummy HWND to be the Windows clipboard's owner
+ WNDCLASSEX wcex = {0};
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.lpfnWndProc = PasteboardOwnerWndProc;
+ wcex.hInstance = Page::instanceHandle();
+ wcex.lpszClassName = L"PasteboardOwnerWindowClass";
+ ::RegisterClassEx(&wcex);
+
+ m_owner = ::CreateWindow(L"PasteboardOwnerWindowClass", L"PasteboardOwnerWindow", 0, 0, 0, 0, 0,
+ HWND_MESSAGE, 0, 0, 0);
+
+ HTMLClipboardFormat = ::RegisterClipboardFormat(L"HTML Format");
+ BookmarkClipboardFormat = ::RegisterClipboardFormat(L"UniformResourceLocatorW");
+ WebSmartPasteFormat = ::RegisterClipboardFormat(L"WebKit Smart Paste Format");
+}
+
+void Pasteboard::clear()
+{
+ if (::OpenClipboard(m_owner)) {
+ ::EmptyClipboard();
+ ::CloseClipboard();
+ }
+}
+
+void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame)
+{
+ clear();
+
+ // Put CF_HTML format on the pasteboard
+ if (::OpenClipboard(m_owner)) {
+ ExceptionCode ec = 0;
+ Vector<char> data;
+ markupToCF_HTML(createMarkup(selectedRange, 0, AnnotateForInterchange),
+ selectedRange->startContainer(ec)->document()->url().string(), data);
+ HGLOBAL cbData = createGlobalData(data);
+ if (!::SetClipboardData(HTMLClipboardFormat, cbData))
+ ::GlobalFree(cbData);
+ ::CloseClipboard();
+ }
+
+ // Put plain string on the pasteboard. CF_UNICODETEXT covers CF_TEXT as well
+ String str = frame->selectedText();
+ replaceNewlinesWithWindowsStyleNewlines(str);
+ replaceNBSPWithSpace(str);
+ if (::OpenClipboard(m_owner)) {
+ HGLOBAL cbData = createGlobalData(str);
+ if (!::SetClipboardData(CF_UNICODETEXT, cbData))
+ ::GlobalFree(cbData);
+ ::CloseClipboard();
+ }
+
+ // enable smart-replacing later on by putting dummy data on the pasteboard
+ if (canSmartCopyOrDelete) {
+ if (::OpenClipboard(m_owner)) {
+ ::SetClipboardData(WebSmartPasteFormat, NULL);
+ ::CloseClipboard();
+ }
+
+ }
+}
+
+void Pasteboard::writeURL(const KURL& url, const String& titleStr, Frame* frame)
+{
+ ASSERT(!url.isEmpty());
+
+ clear();
+
+ String title(titleStr);
+ if (title.isEmpty()) {
+ title = url.lastPathComponent();
+ if (title.isEmpty())
+ title = url.host();
+ }
+
+ // write to clipboard in format com.apple.safari.bookmarkdata to be able to paste into the bookmarks view with appropriate title
+ if (::OpenClipboard(m_owner)) {
+ HGLOBAL cbData = createGlobalData(url, title);
+ if (!::SetClipboardData(BookmarkClipboardFormat, cbData))
+ ::GlobalFree(cbData);
+ ::CloseClipboard();
+ }
+
+ // write to clipboard in format CF_HTML to be able to paste into contenteditable areas as a link
+ if (::OpenClipboard(m_owner)) {
+ Vector<char> data;
+ markupToCF_HTML(urlToMarkup(url, title), "", data);
+ HGLOBAL cbData = createGlobalData(data);
+ if (!::SetClipboardData(HTMLClipboardFormat, cbData))
+ ::GlobalFree(cbData);
+ ::CloseClipboard();
+ }
+
+ // bare-bones CF_UNICODETEXT support
+ if (::OpenClipboard(m_owner)) {
+ HGLOBAL cbData = createGlobalData(url.string());
+ if (!::SetClipboardData(CF_UNICODETEXT, cbData))
+ ::GlobalFree(cbData);
+ ::CloseClipboard();
+ }
+}
+
+void Pasteboard::writeImage(Node* node, const KURL&, const String&)
+{
+ ASSERT(node && node->renderer() && node->renderer()->isImage());
+ RenderImage* renderer = static_cast<RenderImage*>(node->renderer());
+ CachedImage* cachedImage = static_cast<CachedImage*>(renderer->cachedImage());
+ ASSERT(cachedImage);
+ Image* image = cachedImage->image();
+ ASSERT(image);
+
+ clear();
+
+ HDC dc = GetDC(0);
+ HDC compatibleDC = CreateCompatibleDC(0);
+ HDC sourceDC = CreateCompatibleDC(0);
+ HBITMAP resultBitmap = CreateCompatibleBitmap(dc, image->width(), image->height());
+ HBITMAP oldBitmap = (HBITMAP)SelectObject(compatibleDC, resultBitmap);
+
+ BITMAPINFO bmInfo = {0};
+ bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmInfo.bmiHeader.biWidth = image->width();
+ bmInfo.bmiHeader.biHeight = image->height();
+ bmInfo.bmiHeader.biPlanes = 1;
+ bmInfo.bmiHeader.biBitCount = 32;
+ bmInfo.bmiHeader.biCompression = BI_RGB;
+ HBITMAP coreBitmap = CreateDIBSection(dc, &bmInfo, DIB_RGB_COLORS, 0, 0, 0);
+ HBITMAP oldSource = (HBITMAP)SelectObject(sourceDC, coreBitmap);
+ image->getHBITMAP(coreBitmap);
+
+ BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
+ AlphaBlend(compatibleDC, 0, 0, image->width(), image->height(),
+ sourceDC, 0, 0, image->width(), image->height(), bf);
+
+ SelectObject(compatibleDC, oldBitmap);
+ SelectObject(sourceDC, oldSource);
+
+ DeleteObject(oldBitmap);
+ DeleteObject(oldSource);
+ DeleteObject(coreBitmap);
+ ReleaseDC(0, dc);
+ DeleteDC(compatibleDC);
+ DeleteDC(sourceDC);
+
+ if (::OpenClipboard(m_owner)) {
+ ::SetClipboardData(CF_BITMAP, resultBitmap);
+ ::CloseClipboard();
+ }
+}
+
+bool Pasteboard::canSmartReplace()
+{
+ return ::IsClipboardFormatAvailable(WebSmartPasteFormat);
+}
+
+String Pasteboard::plainText(Frame* frame)
+{
+ if (::IsClipboardFormatAvailable(CF_UNICODETEXT) && ::OpenClipboard(m_owner)) {
+ HANDLE cbData = ::GetClipboardData(CF_UNICODETEXT);
+ if (cbData) {
+ UChar* buffer = (UChar*)::GlobalLock(cbData);
+ String fromClipboard(buffer);
+ ::GlobalUnlock(cbData);
+ ::CloseClipboard();
+ return fromClipboard;
+ } else
+ ::CloseClipboard();
+ }
+
+ if (::IsClipboardFormatAvailable(CF_TEXT) && ::OpenClipboard(m_owner)) {
+ HANDLE cbData = ::GetClipboardData(CF_TEXT);
+ if (cbData) {
+ char* buffer = (char*)::GlobalLock(cbData);
+ String fromClipboard(buffer);
+ ::GlobalUnlock(cbData);
+ ::CloseClipboard();
+ return fromClipboard;
+ } else
+ ::CloseClipboard();
+ }
+
+ return String();
+}
+
+PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefPtr<Range> context, bool allowPlainText, bool& chosePlainText)
+{
+ chosePlainText = false;
+
+ if (::IsClipboardFormatAvailable(HTMLClipboardFormat) && ::OpenClipboard(m_owner)) {
+ // get data off of clipboard
+ HANDLE cbData = ::GetClipboardData(HTMLClipboardFormat);
+ if (cbData) {
+ SIZE_T dataSize = ::GlobalSize(cbData);
+ String cf_html(UTF8Encoding().decode((char*)::GlobalLock(cbData), dataSize));
+ ::GlobalUnlock(cbData);
+ ::CloseClipboard();
+
+ PassRefPtr<DocumentFragment> fragment = fragmentFromCF_HTML(frame->document(), cf_html);
+ if (fragment)
+ return fragment;
+ } else
+ ::CloseClipboard();
+ }
+
+ if (allowPlainText && ::IsClipboardFormatAvailable(CF_UNICODETEXT)) {
+ chosePlainText = true;
+ if (::OpenClipboard(m_owner)) {
+ HANDLE cbData = ::GetClipboardData(CF_UNICODETEXT);
+ if (cbData) {
+ UChar* buffer = (UChar*)GlobalLock(cbData);
+ String str(buffer);
+ ::GlobalUnlock( cbData );
+ ::CloseClipboard();
+ RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), str);
+ if (fragment)
+ return fragment.release();
+ } else
+ ::CloseClipboard();
+ }
+ }
+
+ if (allowPlainText && ::IsClipboardFormatAvailable(CF_TEXT)) {
+ chosePlainText = true;
+ if (::OpenClipboard(m_owner)) {
+ HANDLE cbData = ::GetClipboardData(CF_TEXT);
+ if (cbData) {
+ char* buffer = (char*)GlobalLock(cbData);
+ String str(buffer);
+ ::GlobalUnlock( cbData );
+ ::CloseClipboard();
+ RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), str);
+ if (fragment)
+ return fragment.release();
+ } else
+ ::CloseClipboard();
+ }
+ }
+
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/win/PlatformMouseEventWin.cpp b/WebCore/platform/win/PlatformMouseEventWin.cpp
new file mode 100644
index 0000000..7110b39
--- /dev/null
+++ b/WebCore/platform/win/PlatformMouseEventWin.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2006, 2007 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 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 "PlatformMouseEvent.h"
+
+#include <wtf/Assertions.h>
+#include <windows.h>
+#include <windowsx.h>
+
+namespace WebCore {
+
+#define HIGH_BIT_MASK_SHORT 0x8000
+
+static IntPoint positionForEvent(HWND hWnd, LPARAM lParam)
+{
+ POINT point = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
+ return point;
+}
+
+static IntPoint globalPositionForEvent(HWND hWnd, LPARAM lParam)
+{
+ POINT point = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
+ ClientToScreen(hWnd, &point);
+ return point;
+}
+
+static MouseEventType messageToEventType(UINT message)
+{
+ switch (message) {
+ case WM_LBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
+ //MSDN docs say double click is sent on mouse down
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ return MouseEventPressed;
+
+ case WM_LBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_MBUTTONUP:
+ return MouseEventReleased;
+
+ case WM_MOUSELEAVE:
+ case WM_MOUSEMOVE:
+ return MouseEventMoved;
+
+ default:
+ ASSERT_NOT_REACHED();
+ //Move is relatively harmless
+ return MouseEventMoved;
+ }
+}
+PlatformMouseEvent::PlatformMouseEvent(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, bool activatedWebView)
+ : m_position(positionForEvent(hWnd, lParam))
+ , m_globalPosition(globalPositionForEvent(hWnd, lParam))
+ , m_clickCount(0)
+ , m_shiftKey(wParam & MK_SHIFT)
+ , m_ctrlKey(wParam & MK_CONTROL)
+ , m_altKey(GetKeyState(VK_MENU) & HIGH_BIT_MASK_SHORT)
+ , m_metaKey(m_altKey) // FIXME: We'll have to test other browsers
+ , m_activatedWebView(activatedWebView)
+ , m_eventType(messageToEventType(message))
+ , m_modifierFlags(wParam)
+{
+ m_timestamp = ::GetTickCount()*0.001; // GetTickCount returns milliseconds
+
+ switch (message) {
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_LBUTTONDBLCLK:
+ m_button = LeftButton;
+ break;
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONUP:
+ case WM_RBUTTONDBLCLK:
+ m_button = RightButton;
+ break;
+ case WM_MBUTTONDOWN:
+ case WM_MBUTTONUP:
+ case WM_MBUTTONDBLCLK:
+ m_button = MiddleButton;
+ break;
+ case WM_MOUSEMOVE:
+ case WM_MOUSELEAVE:
+ if (wParam & MK_LBUTTON)
+ m_button = LeftButton;
+ else if (wParam & MK_MBUTTON)
+ m_button = MiddleButton;
+ else if (wParam & MK_RBUTTON)
+ m_button = RightButton;
+ else
+ m_button = NoButton;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/win/PlatformScreenWin.cpp b/WebCore/platform/win/PlatformScreenWin.cpp
new file mode 100644
index 0000000..0a47987
--- /dev/null
+++ b/WebCore/platform/win/PlatformScreenWin.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2006, 2007 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 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 "IntRect.h"
+#include "FloatRect.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "Page.h"
+#include <windows.h>
+
+namespace WebCore {
+
+// Returns info for the default monitor if widget is NULL
+static MONITORINFOEX monitorInfoForWidget(Widget* widget)
+{
+ HWND window = widget ? widget->containingWindow() : 0;
+ HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY);
+
+ MONITORINFOEX monitorInfo;
+ monitorInfo.cbSize = sizeof(MONITORINFOEX);
+ GetMonitorInfo(monitor, &monitorInfo);
+ return monitorInfo;
+}
+
+static DEVMODE deviceInfoForWidget(Widget* widget)
+{
+ MONITORINFOEX monitorInfo = monitorInfoForWidget(widget);
+
+ DEVMODE deviceInfo;
+ deviceInfo.dmSize = sizeof(DEVMODE);
+ deviceInfo.dmDriverExtra = 0;
+ EnumDisplaySettings(monitorInfo.szDevice, ENUM_CURRENT_SETTINGS, &deviceInfo);
+
+ return deviceInfo;
+}
+
+int screenDepth(Widget* widget)
+{
+ DEVMODE deviceInfo = deviceInfoForWidget(widget);
+ return deviceInfo.dmBitsPerPel;
+}
+
+int screenDepthPerComponent(Widget* widget)
+{
+ // FIXME: Assumes RGB -- not sure if this is right.
+ DEVMODE deviceInfo = deviceInfoForWidget(widget);
+ return deviceInfo.dmBitsPerPel / 3;
+}
+
+bool screenIsMonochrome(Widget* widget)
+{
+ DEVMODE deviceInfo = deviceInfoForWidget(widget);
+ return deviceInfo.dmColor == DMCOLOR_MONOCHROME;
+}
+
+FloatRect screenRect(Widget* widget)
+{
+ MONITORINFOEX monitorInfo = monitorInfoForWidget(widget);
+ return monitorInfo.rcMonitor;
+}
+
+FloatRect screenAvailableRect(Widget* widget)
+{
+ MONITORINFOEX monitorInfo = monitorInfoForWidget(widget);
+ return monitorInfo.rcWork;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/win/PlatformScrollBar.h b/WebCore/platform/win/PlatformScrollBar.h
new file mode 100644
index 0000000..43f2f95
--- /dev/null
+++ b/WebCore/platform/win/PlatformScrollBar.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 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 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 PlatformScrollbar_h
+#define PlatformScrollbar_h
+
+#include "Widget.h"
+#include "ScrollBar.h"
+#include "Timer.h"
+
+typedef struct HDC__* HDC;
+
+namespace WebCore {
+
+enum ScrollbarPart { NoPart, BackButtonPart, BackTrackPart, ThumbPart, ForwardTrackPart, ForwardButtonPart };
+
+class PlatformScrollbar : public Widget, public Scrollbar {
+public:
+ PlatformScrollbar(ScrollbarClient*, ScrollbarOrientation, ScrollbarControlSize);
+
+ virtual ~PlatformScrollbar();
+
+ virtual bool isWidget() const { return true; }
+
+ virtual void setParent(ScrollView*);
+
+ virtual int width() const;
+ virtual int height() const;
+ virtual void setRect(const IntRect&);
+ virtual void setEnabled(bool);
+ virtual void paint(GraphicsContext*, const IntRect& damageRect);
+
+ virtual bool handleMouseMoveEvent(const PlatformMouseEvent&);
+ virtual bool handleMouseOutEvent(const PlatformMouseEvent&);
+ virtual bool handleMousePressEvent(const PlatformMouseEvent&);
+ virtual bool handleMouseReleaseEvent(const PlatformMouseEvent&);
+
+ virtual IntRect windowClipRect() const;
+
+ static void themeChanged();
+ static int horizontalScrollbarHeight(ScrollbarControlSize size = RegularScrollbar);
+ static int verticalScrollbarWidth(ScrollbarControlSize size = RegularScrollbar);
+
+ void autoscrollTimerFired(Timer<PlatformScrollbar>*);
+
+protected:
+ virtual void updateThumbPosition();
+ virtual void updateThumbProportion();
+
+private:
+ bool hasButtons() const;
+ bool hasThumb() const;
+ IntRect backButtonRect() const;
+ IntRect forwardButtonRect() const;
+ IntRect trackRect() const;
+ IntRect thumbRect() const;
+ IntRect gripperRect(const IntRect& thumbRect) const;
+ void splitTrack(const IntRect& trackRect, IntRect& beforeThumbRect, IntRect& thumbRect, IntRect& afterThumbRect) const;
+
+ int thumbPosition() const;
+ int thumbLength() const;
+ int trackLength() const;
+
+ void paintButton(GraphicsContext*, const IntRect& buttonRect, bool start, const IntRect& damageRect) const;
+ void paintTrack(GraphicsContext*, const IntRect& trackRect, bool start, const IntRect& damageRect) const;
+ void paintThumb(GraphicsContext*, const IntRect& thumbRect, const IntRect& damageRect) const;
+ void paintGripper(HDC, const IntRect& gripperRect) const;
+
+ ScrollbarPart hitTest(const PlatformMouseEvent&);
+
+ void startTimerIfNeeded(double delay);
+ void stopTimerIfNeeded();
+ void autoscrollPressedPart(double delay);
+ ScrollDirection pressedPartScrollDirection();
+ ScrollGranularity pressedPartScrollGranularity();
+
+ bool thumbUnderMouse();
+
+ void invalidatePart(ScrollbarPart);
+ void invalidateTrack();
+
+ ScrollbarPart m_hoveredPart;
+ ScrollbarPart m_pressedPart;
+ int m_pressedPos;
+ Timer<PlatformScrollbar> m_scrollTimer;
+ bool m_overlapsResizer;
+};
+
+}
+
+#endif // PlatformScrollbar_h
+
diff --git a/WebCore/platform/win/PlatformScrollBarSafari.cpp b/WebCore/platform/win/PlatformScrollBarSafari.cpp
new file mode 100644
index 0000000..6485914
--- /dev/null
+++ b/WebCore/platform/win/PlatformScrollBarSafari.cpp
@@ -0,0 +1,660 @@
+/*
+ * Copyright (C) 2007 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 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"
+
+#ifdef USE_SAFARI_THEME
+
+#include "PlatformScrollBar.h"
+
+#include "EventHandler.h"
+#include "FrameView.h"
+#include "Frame.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "PlatformMouseEvent.h"
+#include "SoftLinking.h"
+
+#include <CoreGraphics/CoreGraphics.h>
+#include <SafariTheme/SafariTheme.h>
+
+// FIXME: There are repainting problems due to Aqua scroll bar buttons' visual overflow.
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace SafariTheme;
+
+// FIXME: We should get these numbers from SafariTheme
+static int cHorizontalWidth[] = { 15, 11 };
+static int cHorizontalHeight[] = { 15, 11 };
+static int cVerticalWidth[] = { 15, 11 };
+static int cVerticalHeight[] = { 15, 11 };
+static int cRealButtonLength[] = { 28, 21 };
+static int cButtonInset[] = { 14, 11 };
+static int cButtonHitInset[] = { 3, 2 };
+// cRealButtonLength - cButtonInset
+static int cButtonLength[] = { 14, 10 };
+static int cThumbWidth[] = { 15, 11 };
+static int cThumbHeight[] = { 15, 11 };
+static int cThumbMinLength[] = { 26, 20 };
+
+#if !defined(NDEBUG) && defined(USE_DEBUG_SAFARI_THEME)
+SOFT_LINK_DEBUG_LIBRARY(SafariTheme)
+#else
+SOFT_LINK_LIBRARY(SafariTheme)
+#endif
+
+SOFT_LINK(SafariTheme, paintThemePart, void, __stdcall, (ThemePart part, CGContextRef context, const CGRect& rect, NSControlSize size, ThemeControlState state), (part, context, rect, size, state))
+
+const double cInitialTimerDelay = 0.25;
+const double cNormalTimerDelay = 0.05;
+
+PlatformScrollbar::PlatformScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize size)
+ : Scrollbar(client, orientation, size), m_hoveredPart(NoPart), m_pressedPart(NoPart), m_pressedPos(0),
+ m_scrollTimer(this, &PlatformScrollbar::autoscrollTimerFired),
+ m_overlapsResizer(false)
+{
+ // Obtain the correct scrollbar sizes from the system.
+ if (!cHorizontalWidth) {
+ // FIXME: Get metics from SafariTheme
+ }
+
+ if (orientation == VerticalScrollbar)
+ setFrameGeometry(IntRect(0, 0, cVerticalWidth[controlSize()], cVerticalHeight[controlSize()]));
+ else
+ setFrameGeometry(IntRect(0, 0, cHorizontalWidth[controlSize()], cHorizontalHeight[controlSize()]));
+}
+
+PlatformScrollbar::~PlatformScrollbar()
+{
+ stopTimerIfNeeded();
+}
+
+void PlatformScrollbar::updateThumbPosition()
+{
+ invalidateTrack();
+}
+
+void PlatformScrollbar::updateThumbProportion()
+{
+ invalidateTrack();
+}
+
+static IntRect trackRepaintRect(const IntRect& trackRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize)
+{
+ IntRect paintRect(trackRect);
+ if (orientation == HorizontalScrollbar)
+ paintRect.inflateX(cButtonLength[controlSize]);
+ else
+ paintRect.inflateY(cButtonLength[controlSize]);
+
+ return paintRect;
+}
+
+static IntRect buttonRepaintRect(const IntRect& buttonRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize, bool start)
+{
+ IntRect paintRect(buttonRect);
+ if (orientation == HorizontalScrollbar) {
+ paintRect.setWidth(cRealButtonLength[controlSize]);
+ if (!start)
+ paintRect.setX(buttonRect.x() - (cRealButtonLength[controlSize] - buttonRect.width()));
+ } else {
+ paintRect.setHeight(cRealButtonLength[controlSize]);
+ if (!start)
+ paintRect.setY(buttonRect.y() - (cRealButtonLength[controlSize] - buttonRect.height()));
+ }
+
+ return paintRect;
+}
+
+void PlatformScrollbar::invalidateTrack()
+{
+ IntRect rect = trackRepaintRect(trackRect(), m_orientation, controlSize());
+ rect.move(-x(), -y());
+ invalidateRect(rect);
+}
+
+void PlatformScrollbar::invalidatePart(ScrollbarPart part)
+{
+ if (part == NoPart)
+ return;
+
+ IntRect result;
+ switch (part) {
+ case BackButtonPart:
+ result = buttonRepaintRect(backButtonRect(), m_orientation, controlSize(), true);
+ break;
+ case ForwardButtonPart:
+ result = buttonRepaintRect(forwardButtonRect(), m_orientation, controlSize(), false);
+ break;
+ default: {
+ IntRect beforeThumbRect, thumbRect, afterThumbRect;
+ splitTrack(trackRect(), beforeThumbRect, thumbRect, afterThumbRect);
+ if (part == BackTrackPart)
+ result = beforeThumbRect;
+ else if (part == ForwardTrackPart)
+ result = afterThumbRect;
+ else
+ result = thumbRect;
+ }
+ }
+ result.move(-x(), -y());
+ invalidateRect(result);
+}
+
+int PlatformScrollbar::width() const
+{
+ return Widget::width();
+}
+
+int PlatformScrollbar::height() const
+{
+ return Widget::height();
+}
+
+void PlatformScrollbar::setRect(const IntRect& rect)
+{
+ // Get our window resizer rect and see if we overlap. Adjust to avoid the overlap
+ // if necessary.
+ IntRect adjustedRect(rect);
+ if (parent() && parent()->isFrameView()) {
+ bool overlapsResizer = false;
+ FrameView* view = static_cast<FrameView*>(parent());
+ IntRect resizerRect = view->windowResizerRect();
+ resizerRect.setLocation(view->convertFromContainingWindow(resizerRect.location()));
+ if (rect.intersects(resizerRect)) {
+ if (orientation() == HorizontalScrollbar) {
+ int overlap = rect.right() - resizerRect.x();
+ if (overlap > 0 && resizerRect.right() >= rect.right()) {
+ adjustedRect.setWidth(rect.width() - overlap);
+ overlapsResizer = true;
+ }
+ } else {
+ int overlap = rect.bottom() - resizerRect.y();
+ if (overlap > 0 && resizerRect.bottom() >= rect.bottom()) {
+ adjustedRect.setHeight(rect.height() - overlap);
+ overlapsResizer = true;
+ }
+ }
+ }
+
+ if (overlapsResizer != m_overlapsResizer) {
+ m_overlapsResizer = overlapsResizer;
+ view->adjustOverlappingScrollbarCount(m_overlapsResizer ? 1 : -1);
+ }
+ }
+
+ setFrameGeometry(adjustedRect);
+}
+
+void PlatformScrollbar::setParent(ScrollView* parentView)
+{
+ if (!parentView && m_overlapsResizer && parent() && parent()->isFrameView())
+ static_cast<FrameView*>(parent())->adjustOverlappingScrollbarCount(-1);
+ Widget::setParent(parentView);
+}
+
+void PlatformScrollbar::setEnabled(bool enabled)
+{
+ if (enabled != isEnabled()) {
+ Widget::setEnabled(enabled);
+ invalidate();
+ }
+}
+
+void PlatformScrollbar::paint(GraphicsContext* graphicsContext, const IntRect& damageRect)
+{
+ if (graphicsContext->updatingControlTints()) {
+ invalidate();
+ return;
+ }
+
+ if (graphicsContext->paintingDisabled())
+ return;
+
+ // Don't paint anything if the scrollbar doesn't intersect the damage rect.
+ if (!frameGeometry().intersects(damageRect))
+ return;
+
+ IntRect track = trackRect();
+ paintTrack(graphicsContext, track, true, damageRect);
+
+ if (hasButtons()) {
+ paintButton(graphicsContext, backButtonRect(), true, damageRect);
+ paintButton(graphicsContext, forwardButtonRect(), false, damageRect);
+ }
+
+ if (hasThumb() && damageRect.intersects(track)) {
+ IntRect startTrackRect, thumbRect, endTrackRect;
+ splitTrack(track, startTrackRect, thumbRect, endTrackRect);
+ paintThumb(graphicsContext, thumbRect, damageRect);
+ }
+}
+
+bool PlatformScrollbar::hasButtons() const
+{
+ return isEnabled() && (m_orientation == HorizontalScrollbar ? width() : height()) >= 2 * (cRealButtonLength[controlSize()] - cButtonHitInset[controlSize()]);
+}
+
+bool PlatformScrollbar::hasThumb() const
+{
+ return isEnabled() && (m_orientation == HorizontalScrollbar ? width() : height()) >= 2 * cButtonInset[controlSize()] + cThumbMinLength[controlSize()] + 1;
+}
+
+IntRect PlatformScrollbar::backButtonRect() const
+{
+ // Our desired rect is essentially 17x17.
+
+ // Our actual rect will shrink to half the available space when
+ // we have < 34 pixels left. This allows the scrollbar
+ // to scale down and function even at tiny sizes.
+ if (m_orientation == HorizontalScrollbar)
+ return IntRect(x(), y(), cButtonLength[controlSize()], cHorizontalHeight[controlSize()]);
+ return IntRect(x(), y(), cVerticalWidth[controlSize()], cButtonLength[controlSize()]);
+}
+
+IntRect PlatformScrollbar::forwardButtonRect() const
+{
+ // Our desired rect is essentially 17x17.
+
+ // Our actual rect will shrink to half the available space when
+ // we have < 34 pixels left. This allows the scrollbar
+ // to scale down and function even at tiny sizes.
+
+ if (m_orientation == HorizontalScrollbar)
+ return IntRect(x() + width() - cButtonLength[controlSize()], y(), cButtonLength[controlSize()], cHorizontalHeight[controlSize()]);
+ return IntRect(x(), y() + height() - cButtonLength[controlSize()], cVerticalWidth[controlSize()], cButtonLength[controlSize()]);
+}
+
+IntRect PlatformScrollbar::trackRect() const
+{
+ if (m_orientation == HorizontalScrollbar) {
+ if (!hasButtons())
+ return IntRect(x(), y(), width(), cHorizontalHeight[controlSize()]);
+ return IntRect(x() + cButtonLength[controlSize()], y(), width() - 2 * cButtonLength[controlSize()], cHorizontalHeight[controlSize()]);
+ }
+
+ if (!hasButtons())
+ return IntRect(x(), y(), cVerticalWidth[controlSize()], height());
+ return IntRect(x(), y() + cButtonLength[controlSize()], cVerticalWidth[controlSize()], height() - 2 * cButtonLength[controlSize()]);
+}
+
+IntRect PlatformScrollbar::thumbRect() const
+{
+ IntRect beforeThumbRect, thumbRect, afterThumbRect;
+ splitTrack(trackRect(), beforeThumbRect, thumbRect, afterThumbRect);
+ return thumbRect;
+}
+
+void PlatformScrollbar::splitTrack(const IntRect& trackRect, IntRect& beforeThumbRect, IntRect& thumbRect, IntRect& afterThumbRect) const
+{
+ // This function won't even get called unless we're big enough to have some combination of these three rects where at least
+ // one of them is non-empty.
+ int thumbPos = thumbPosition();
+ if (m_orientation == HorizontalScrollbar) {
+ thumbRect = IntRect(trackRect.x() + thumbPos, trackRect.y() + (trackRect.height() - cThumbHeight[controlSize()]) / 2, thumbLength(), cThumbHeight[controlSize()]);
+ beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), thumbPos, trackRect.height());
+ afterThumbRect = IntRect(thumbRect.x() + thumbRect.width(), trackRect.y(), trackRect.right() - thumbRect.right(), trackRect.height());
+ } else {
+ thumbRect = IntRect(trackRect.x() + (trackRect.width() - cThumbWidth[controlSize()]) / 2, trackRect.y() + thumbPos, cThumbWidth[controlSize()], thumbLength());
+ beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), trackRect.width(), thumbPos);
+ afterThumbRect = IntRect(trackRect.x(), thumbRect.y() + thumbRect.height(), trackRect.width(), trackRect.bottom() - thumbRect.bottom());
+ }
+}
+
+int PlatformScrollbar::thumbPosition() const
+{
+ if (isEnabled())
+ return (float)m_currentPos * (trackLength() - thumbLength()) / (m_totalSize - m_visibleSize);
+ return 0;
+}
+
+int PlatformScrollbar::thumbLength() const
+{
+ if (!isEnabled())
+ return 0;
+
+ float proportion = (float)(m_visibleSize) / m_totalSize;
+ int trackLen = trackLength();
+ int length = proportion * trackLen;
+ int minLength = cThumbMinLength[controlSize()];
+ length = max(length, minLength);
+ if (length > trackLen)
+ length = 0; // Once the thumb is below the track length, it just goes away (to make more room for the track).
+ return length;
+}
+
+int PlatformScrollbar::trackLength() const
+{
+ return (m_orientation == HorizontalScrollbar) ? trackRect().width() : trackRect().height();
+}
+
+void PlatformScrollbar::paintButton(GraphicsContext* context, const IntRect& rect, bool start, const IntRect& damageRect) const
+{
+ if (!SafariThemeLibrary())
+ return;
+
+ IntRect paintRect = buttonRepaintRect(rect, m_orientation, controlSize(), start);
+
+ if (!damageRect.intersects(paintRect))
+ return;
+
+ ThemePart part;
+ ThemeControlState state = 0;
+ if (m_client->isActive())
+ state |= ActiveState;
+ if (m_orientation == HorizontalScrollbar)
+ part = start ? ScrollLeftArrowPart : ScrollRightArrowPart;
+ else
+ part = start ? ScrollUpArrowPart : ScrollDownArrowPart;
+
+ if (isEnabled())
+ state |= EnabledState;
+ if ((m_pressedPart == BackButtonPart && start)
+ || (m_pressedPart == ForwardButtonPart && !start))
+ state |= PressedState;
+
+ paintThemePart(part, context->platformContext(), paintRect, controlSize() == SmallScrollbar ? NSSmallControlSize : NSRegularControlSize, state);
+}
+
+void PlatformScrollbar::paintTrack(GraphicsContext* context, const IntRect& rect, bool start, const IntRect& damageRect) const
+{
+ if (!SafariThemeLibrary())
+ return;
+
+ IntRect paintRect = hasButtons() ? trackRepaintRect(rect, m_orientation, controlSize()) : rect;
+
+ if (!damageRect.intersects(paintRect))
+ return;
+
+ ThemePart part = m_orientation == HorizontalScrollbar ? HScrollTrackPart : VScrollTrackPart;
+ ThemeControlState state = 0;
+ if (m_client->isActive())
+ state |= ActiveState;
+ if (hasButtons())
+ state |= EnabledState;
+
+ paintThemePart(part, context->platformContext(), paintRect, controlSize() == SmallScrollbar ? NSSmallControlSize : NSRegularControlSize, state);
+}
+
+void PlatformScrollbar::paintThumb(GraphicsContext* context, const IntRect& rect, const IntRect& damageRect) const
+{
+ if (!SafariThemeLibrary())
+ return;
+
+ if (!damageRect.intersects(rect))
+ return;
+
+ ThemePart part = m_orientation == HorizontalScrollbar ? HScrollThumbPart : VScrollThumbPart;
+ ThemeControlState state = 0;
+ if (m_client->isActive())
+ state |= ActiveState;
+ if (isEnabled())
+ state |= EnabledState;
+
+ paintThemePart(part, context->platformContext(), rect, controlSize() == SmallScrollbar ? NSSmallControlSize : NSRegularControlSize, state);
+}
+
+ScrollbarPart PlatformScrollbar::hitTest(const PlatformMouseEvent& evt)
+{
+ if (!isEnabled())
+ return NoPart;
+
+ IntPoint mousePosition = convertFromContainingWindow(evt.pos());
+ mousePosition.move(x(), y());
+
+ if (hasButtons()) {
+ if (backButtonRect().contains(mousePosition))
+ return BackButtonPart;
+
+ if (forwardButtonRect().contains(mousePosition))
+ return ForwardButtonPart;
+ }
+
+ if (!hasThumb())
+ return NoPart;
+
+ IntRect track = trackRect();
+ if (track.contains(mousePosition)) {
+ IntRect beforeThumbRect, thumbRect, afterThumbRect;
+ splitTrack(track, beforeThumbRect, thumbRect, afterThumbRect);
+ if (beforeThumbRect.contains(mousePosition))
+ return BackTrackPart;
+ if (thumbRect.contains(mousePosition))
+ return ThumbPart;
+ return ForwardTrackPart;
+ }
+ return NoPart;
+}
+
+bool PlatformScrollbar::handleMouseMoveEvent(const PlatformMouseEvent& evt)
+{
+ if (m_pressedPart == ThumbPart) {
+ // Drag the thumb.
+ int thumbPos = thumbPosition();
+ int thumbLen = thumbLength();
+ int trackLen = trackLength();
+ int maxPos = trackLen - thumbLen;
+ int delta = 0;
+ if (m_orientation == HorizontalScrollbar)
+ delta = convertFromContainingWindow(evt.pos()).x() - m_pressedPos;
+ else
+ delta = convertFromContainingWindow(evt.pos()).y() - m_pressedPos;
+
+ if (delta > 0)
+ // The mouse moved down/right.
+ delta = min(maxPos - thumbPos, delta);
+ else if (delta < 0)
+ // The mouse moved up/left.
+ delta = max(-thumbPos, delta);
+
+ if (delta != 0) {
+ setValue((float)(thumbPos + delta) * (m_totalSize - m_visibleSize) / (trackLen - thumbLen));
+ m_pressedPos += thumbPosition() - thumbPos;
+ }
+
+ return true;
+ }
+
+ if (m_pressedPart != NoPart)
+ m_pressedPos = (m_orientation == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y());
+
+ ScrollbarPart part = hitTest(evt);
+ if (part != m_hoveredPart) {
+ if (m_pressedPart != NoPart) {
+ if (part == m_pressedPart) {
+ // The mouse is moving back over the pressed part. We
+ // need to start up the timer action again.
+ startTimerIfNeeded(cNormalTimerDelay);
+ invalidatePart(m_pressedPart);
+ } else if (m_hoveredPart == m_pressedPart) {
+ // The mouse is leaving the pressed part. Kill our timer
+ // if needed.
+ stopTimerIfNeeded();
+ invalidatePart(m_pressedPart);
+ }
+ } else {
+ invalidatePart(part);
+ invalidatePart(m_hoveredPart);
+ }
+ m_hoveredPart = part;
+ }
+
+ return true;
+}
+
+bool PlatformScrollbar::handleMouseOutEvent(const PlatformMouseEvent& evt)
+{
+ invalidatePart(m_hoveredPart);
+ m_hoveredPart = NoPart;
+
+ return true;
+}
+
+bool PlatformScrollbar::handleMousePressEvent(const PlatformMouseEvent& evt)
+{
+ m_pressedPart = hitTest(evt);
+ m_pressedPos = (m_orientation == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y());
+ invalidatePart(m_pressedPart);
+ autoscrollPressedPart(cInitialTimerDelay);
+ return true;
+}
+
+bool PlatformScrollbar::handleMouseReleaseEvent(const PlatformMouseEvent& evt)
+{
+ invalidatePart(m_pressedPart);
+ m_pressedPart = NoPart;
+ m_pressedPos = 0;
+ stopTimerIfNeeded();
+
+ if (parent() && parent()->isFrameView())
+ static_cast<FrameView*>(parent())->frame()->eventHandler()->setMousePressed(false);
+
+ return true;
+}
+
+void PlatformScrollbar::startTimerIfNeeded(double delay)
+{
+ // Don't do anything for the thumb.
+ if (m_pressedPart == ThumbPart)
+ return;
+
+ // Handle the track. We halt track scrolling once the thumb is level
+ // with us.
+ if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse()) {
+ invalidatePart(m_pressedPart);
+ m_hoveredPart = ThumbPart;
+ return;
+ }
+
+ // We can't scroll if we've hit the beginning or end.
+ ScrollDirection dir = pressedPartScrollDirection();
+ if (dir == ScrollUp || dir == ScrollLeft) {
+ if (m_currentPos == 0)
+ return;
+ } else {
+ if (m_currentPos == m_totalSize - m_visibleSize)
+ return;
+ }
+
+ m_scrollTimer.startOneShot(delay);
+}
+
+void PlatformScrollbar::stopTimerIfNeeded()
+{
+ if (m_scrollTimer.isActive())
+ m_scrollTimer.stop();
+}
+
+void PlatformScrollbar::autoscrollPressedPart(double delay)
+{
+ // Don't do anything for the thumb or if nothing was pressed.
+ if (m_pressedPart == ThumbPart || m_pressedPart == NoPart)
+ return;
+
+ // Handle the track.
+ if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse()) {
+ invalidatePart(m_pressedPart);
+ m_hoveredPart = ThumbPart;
+ return;
+ }
+
+ // Handle the arrows and track.
+ if (scroll(pressedPartScrollDirection(), pressedPartScrollGranularity()))
+ startTimerIfNeeded(delay);
+}
+
+void PlatformScrollbar::autoscrollTimerFired(Timer<PlatformScrollbar>*)
+{
+ autoscrollPressedPart(cNormalTimerDelay);
+}
+
+ScrollDirection PlatformScrollbar::pressedPartScrollDirection()
+{
+ if (m_orientation == HorizontalScrollbar) {
+ if (m_pressedPart == BackButtonPart || m_pressedPart == BackTrackPart)
+ return ScrollLeft;
+ return ScrollRight;
+ } else {
+ if (m_pressedPart == BackButtonPart || m_pressedPart == BackTrackPart)
+ return ScrollUp;
+ return ScrollDown;
+ }
+}
+
+ScrollGranularity PlatformScrollbar::pressedPartScrollGranularity()
+{
+ if (m_pressedPart == BackButtonPart || m_pressedPart == ForwardButtonPart)
+ return ScrollByLine;
+ return ScrollByPage;
+}
+
+bool PlatformScrollbar::thumbUnderMouse()
+{
+ // Construct a rect.
+ IntRect thumb = thumbRect();
+ thumb.move(-x(), -y());
+ int begin = (m_orientation == HorizontalScrollbar) ? thumb.x() : thumb.y();
+ int end = (m_orientation == HorizontalScrollbar) ? thumb.right() : thumb.bottom();
+ return (begin <= m_pressedPos && m_pressedPos < end);
+}
+
+int PlatformScrollbar::horizontalScrollbarHeight(ScrollbarControlSize controlSize)
+{
+ return cHorizontalWidth[controlSize];
+}
+
+int PlatformScrollbar::verticalScrollbarWidth(ScrollbarControlSize controlSize)
+{
+ return cVerticalHeight[controlSize];
+}
+
+IntRect PlatformScrollbar::windowClipRect() const
+{
+ IntRect clipRect(0, 0, width(), height());
+ clipRect = convertToContainingWindow(clipRect);
+ if (m_client)
+ clipRect.intersect(m_client->windowClipRect());
+ return clipRect;
+}
+
+void PlatformScrollbar::paintGripper(HDC hdc, const IntRect& rect) const
+{
+}
+
+IntRect PlatformScrollbar::gripperRect(const IntRect& thumbRect) const
+{
+ return IntRect();
+}
+
+void PlatformScrollbar::themeChanged()
+{
+}
+
+}
+
+#endif // defined(USE_SAFARI_THEME)
diff --git a/WebCore/platform/win/PlatformScrollBarWin.cpp b/WebCore/platform/win/PlatformScrollBarWin.cpp
new file mode 100644
index 0000000..f59f27a
--- /dev/null
+++ b/WebCore/platform/win/PlatformScrollBarWin.cpp
@@ -0,0 +1,772 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Brent Fulgham
+ *
+ * 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 "PlatformScrollBar.h"
+
+#include "EventHandler.h"
+#include "FrameView.h"
+#include "Frame.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "PlatformMouseEvent.h"
+#include "SoftLinking.h"
+
+#include <windows.h>
+#include "RenderThemeWin.h"
+
+// Generic state constants
+#define TS_NORMAL 1
+#define TS_HOVER 2
+#define TS_ACTIVE 3
+#define TS_DISABLED 4
+#define TS_FOCUSED 5
+
+#define ABS_UPNORMAL 1
+#define ABS_DOWNNORMAL 5
+#define ABS_LEFTNORMAL 9
+#define ABS_RIGHTNORMAL 13
+
+static const unsigned SP_ABS_HOT_MODIFIER = 1;
+static const unsigned SP_ABS_PRESSED_MODIFIER = 2;
+static const unsigned SP_ABS_DISABLE_MODIFIER = 3;
+
+// Scrollbar constants
+#define SP_BUTTON 1
+#define SP_THUMBHOR 2
+#define SP_THUMBVERT 3
+#define SP_TRACKSTARTHOR 4
+#define SP_TRACKENDHOR 5
+#define SP_TRACKSTARTVERT 6
+#define SP_TRACKENDVERT 7
+#define SP_GRIPPERHOR 8
+#define SP_GRIPPERVERT 9
+
+using namespace std;
+
+namespace WebCore {
+
+// FIXME: We should get these numbers from SafariTheme
+static int cHorizontalWidth;
+static int cHorizontalHeight;
+static int cVerticalWidth;
+static int cVerticalHeight;
+static int cHorizontalButtonWidth;
+static int cVerticalButtonHeight;
+static int cRealButtonLength = 28;
+static int cButtonInset = 14;
+static int cButtonHitInset = 3;
+// cRealButtonLength - cButtonInset
+static int cThumbWidth;
+static int cThumbHeight;
+static int cThumbMinLength = 26;
+
+static HANDLE cScrollBarTheme = 0;
+
+// FIXME: Refactor the soft-linking code so that it can be shared with RenderThemeWin
+SOFT_LINK_LIBRARY(uxtheme)
+SOFT_LINK(uxtheme, OpenThemeData, HANDLE, WINAPI, (HWND hwnd, LPCWSTR pszClassList), (hwnd, pszClassList))
+SOFT_LINK(uxtheme, CloseThemeData, HRESULT, WINAPI, (HANDLE hTheme), (hTheme))
+SOFT_LINK(uxtheme, DrawThemeBackground, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, const RECT* pClipRect), (hTheme, hdc, iPartId, iStateId, pRect, pClipRect))
+SOFT_LINK(uxtheme, DrawThemeEdge, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, unsigned uEdge, unsigned uFlags, const RECT* pClipRect), (hTheme, hdc, iPartId, iStateId, pRect, uEdge, uFlags, pClipRect))
+SOFT_LINK(uxtheme, GetThemeContentRect, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, const RECT* pContentRect), (hTheme, hdc, iPartId, iStateId, pRect, pContentRect))
+SOFT_LINK(uxtheme, GetThemePartSize, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, RECT* pRect, int ts, SIZE* psz), (hTheme, hdc, iPartId, iStateId, pRect, ts, psz))
+SOFT_LINK(uxtheme, GetThemeSysFont, HRESULT, WINAPI, (HANDLE hTheme, int iFontId, OUT LOGFONT* pFont), (hTheme, iFontId, pFont))
+SOFT_LINK(uxtheme, GetThemeColor, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, int iPropId, OUT COLORREF* pColor), (hTheme, hdc, iPartId, iStateId, iPropId, pColor))
+
+static void checkAndInitScrollbarTheme()
+{
+ if (uxthemeLibrary() && !cScrollBarTheme)
+ cScrollBarTheme = OpenThemeData(0, L"Scrollbar");
+}
+
+// May need to add stuff to these later, so keep the graphics context retrieval/release in some helpers.
+static HDC prepareForDrawing(GraphicsContext* g, const IntRect& r)
+{
+ return g->getWindowsContext(r);
+}
+
+static void doneDrawing(GraphicsContext* g, HDC hdc, const IntRect& r)
+{
+ g->releaseWindowsContext(hdc, r);
+}
+// End Copied from RenderThemeWin
+
+const double cInitialTimerDelay = 0.25;
+const double cNormalTimerDelay = 0.05;
+
+PlatformScrollbar::PlatformScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize size)
+ : Scrollbar(client, orientation, size)
+ , m_hoveredPart(NoPart)
+ , m_pressedPart(NoPart)
+ , m_pressedPos(0)
+ , m_scrollTimer(this, &PlatformScrollbar::autoscrollTimerFired)
+ , m_overlapsResizer(false)
+{
+ // Obtain the correct scrollbar sizes from the system.
+ // FIXME: We should update these on a WM_SETTINGSCHANGE, too.
+ if (!cHorizontalHeight) {
+ cHorizontalHeight = ::GetSystemMetrics(SM_CYHSCROLL);
+ cHorizontalWidth = ::GetSystemMetrics(SM_CXHSCROLL);
+ cVerticalHeight = ::GetSystemMetrics(SM_CYVSCROLL);
+ cVerticalWidth = ::GetSystemMetrics(SM_CXVSCROLL);
+ cThumbWidth = ::GetSystemMetrics(SM_CXHTHUMB);
+ cThumbHeight = ::GetSystemMetrics(SM_CYVTHUMB);
+ cHorizontalButtonWidth = ::GetSystemMetrics(SM_CYVSCROLL);
+ cVerticalButtonHeight = ::GetSystemMetrics(SM_CXHSCROLL);
+ }
+
+ if (orientation == VerticalScrollbar)
+ setFrameGeometry(IntRect(0, 0, cVerticalWidth, cVerticalHeight));
+ else
+ setFrameGeometry(IntRect(0, 0, cHorizontalWidth, cHorizontalHeight));
+}
+
+PlatformScrollbar::~PlatformScrollbar()
+{
+ stopTimerIfNeeded();
+}
+
+void PlatformScrollbar::updateThumbPosition()
+{
+ invalidateTrack();
+}
+
+void PlatformScrollbar::updateThumbProportion()
+{
+ invalidateTrack();
+}
+
+static IntRect trackRepaintRect(const IntRect& trackRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize)
+{
+ const int cButtonLength = (orientation == VerticalScrollbar) ? cVerticalButtonHeight : cHorizontalButtonWidth;
+
+ IntRect paintRect(trackRect);
+ if (orientation == HorizontalScrollbar)
+ paintRect.inflateX(cButtonLength);
+ else
+ paintRect.inflateY(cButtonLength);
+
+ return paintRect;
+}
+
+static IntRect buttonRepaintRect(const IntRect& buttonRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize, bool start)
+{
+ IntRect paintRect(buttonRect);
+ if (orientation == HorizontalScrollbar) {
+ paintRect.setWidth(cRealButtonLength);
+ if (!start)
+ paintRect.setX(buttonRect.x() - (cRealButtonLength - buttonRect.width()));
+ } else {
+ paintRect.setHeight(cRealButtonLength);
+ if (!start)
+ paintRect.setY(buttonRect.y() - (cRealButtonLength - buttonRect.height()));
+ }
+
+ return paintRect;
+}
+
+void PlatformScrollbar::invalidateTrack()
+{
+ IntRect rect = trackRepaintRect(trackRect(), m_orientation, controlSize());
+ rect.move(-x(), -y());
+ invalidateRect(rect);
+}
+
+void PlatformScrollbar::invalidatePart(ScrollbarPart part)
+{
+ if (part == NoPart)
+ return;
+
+ IntRect result;
+ switch (part) {
+ case BackButtonPart:
+ result = buttonRepaintRect(backButtonRect(), m_orientation, controlSize(), true);
+ break;
+ case ForwardButtonPart:
+ result = buttonRepaintRect(forwardButtonRect(), m_orientation, controlSize(), false);
+ break;
+ default: {
+ IntRect beforeThumbRect, thumbRect, afterThumbRect;
+ splitTrack(trackRect(), beforeThumbRect, thumbRect, afterThumbRect);
+ if (part == BackTrackPart)
+ result = beforeThumbRect;
+ else if (part == ForwardTrackPart)
+ result = afterThumbRect;
+ else
+ result = thumbRect;
+ }
+ }
+ result.move(-x(), -y());
+ invalidateRect(result);
+}
+
+int PlatformScrollbar::width() const
+{
+ return Widget::width();
+}
+
+int PlatformScrollbar::height() const
+{
+ return Widget::height();
+}
+
+void PlatformScrollbar::setRect(const IntRect& rect)
+{
+ // Get our window resizer rect and see if we overlap. Adjust to avoid the overlap
+ // if necessary.
+ IntRect adjustedRect(rect);
+ if (parent() && parent()->isFrameView()) {
+ bool overlapsResizer = false;
+ FrameView* view = static_cast<FrameView*>(parent());
+ IntRect resizerRect = view->windowResizerRect();
+ resizerRect.setLocation(view->convertFromContainingWindow(resizerRect.location()));
+ if (rect.intersects(resizerRect)) {
+ if (orientation() == HorizontalScrollbar) {
+ int overlap = rect.right() - resizerRect.x();
+ if (overlap > 0 && resizerRect.right() >= rect.right()) {
+ adjustedRect.setWidth(rect.width() - overlap);
+ overlapsResizer = true;
+ }
+ } else {
+ int overlap = rect.bottom() - resizerRect.y();
+ if (overlap > 0 && resizerRect.bottom() >= rect.bottom()) {
+ adjustedRect.setHeight(rect.height() - overlap);
+ overlapsResizer = true;
+ }
+ }
+ }
+
+ if (overlapsResizer != m_overlapsResizer) {
+ m_overlapsResizer = overlapsResizer;
+ view->adjustOverlappingScrollbarCount(m_overlapsResizer ? 1 : -1);
+ }
+ }
+
+ setFrameGeometry(adjustedRect);
+}
+
+void PlatformScrollbar::setParent(ScrollView* parentView)
+{
+ if (!parentView && m_overlapsResizer && parent() && parent()->isFrameView())
+ static_cast<FrameView*>(parent())->adjustOverlappingScrollbarCount(-1);
+ Widget::setParent(parentView);
+}
+
+void PlatformScrollbar::setEnabled(bool enabled)
+{
+ if (enabled != isEnabled()) {
+ Widget::setEnabled(enabled);
+ invalidate();
+ }
+}
+
+void PlatformScrollbar::paint(GraphicsContext* graphicsContext, const IntRect& damageRect)
+{
+ if (graphicsContext->updatingControlTints()) {
+ invalidate();
+ return;
+ }
+
+ if (graphicsContext->paintingDisabled())
+ return;
+
+ // Don't paint anything if the scrollbar doesn't intersect the damage rect.
+ if (!frameGeometry().intersects(damageRect))
+ return;
+
+ IntRect track = trackRect();
+ paintTrack(graphicsContext, track, true, damageRect);
+
+ if (hasButtons()) {
+ paintButton(graphicsContext, backButtonRect(), true, damageRect);
+ paintButton(graphicsContext, forwardButtonRect(), false, damageRect);
+ }
+
+ if (hasThumb() && damageRect.intersects(track)) {
+ IntRect startTrackRect, thumbRect, endTrackRect;
+ splitTrack(track, startTrackRect, thumbRect, endTrackRect);
+ paintThumb(graphicsContext, thumbRect, damageRect);
+ }
+}
+
+bool PlatformScrollbar::hasButtons() const
+{
+ return isEnabled() && (m_orientation == HorizontalScrollbar ? width() : height()) >= 2 * (cRealButtonLength - cButtonHitInset);
+}
+
+bool PlatformScrollbar::hasThumb() const
+{
+ return isEnabled() && (m_orientation == HorizontalScrollbar ? width() : height()) >= 2 * cButtonInset + cThumbMinLength + 1;
+}
+
+IntRect PlatformScrollbar::backButtonRect() const
+{
+ // Our actual rect will shrink to half the available space when
+ // we have < 34 pixels left. This allows the scrollbar
+ // to scale down and function even at tiny sizes.
+ if (m_orientation == HorizontalScrollbar)
+ return IntRect(x(), y(), cHorizontalButtonWidth, cHorizontalHeight);
+ return IntRect(x(), y(), cVerticalWidth, cVerticalButtonHeight);
+}
+
+IntRect PlatformScrollbar::forwardButtonRect() const
+{
+ // Our desired rect is essentially 17x17.
+
+ // Our actual rect will shrink to half the available space when
+ // we have < 34 pixels left. This allows the scrollbar
+ // to scale down and function even at tiny sizes.
+ if (m_orientation == HorizontalScrollbar)
+ return IntRect(x() + width() - cHorizontalButtonWidth, y(), cHorizontalButtonWidth, cHorizontalHeight);
+ return IntRect(x(), y() + height() - cVerticalButtonHeight, cVerticalWidth, cVerticalButtonHeight);
+}
+
+IntRect PlatformScrollbar::trackRect() const
+{
+ if (m_orientation == HorizontalScrollbar) {
+ if (!hasButtons())
+ return IntRect(x(), y(), width(), cHorizontalHeight);
+ return IntRect(x() + cHorizontalButtonWidth, y(), width() - 2 * cHorizontalButtonWidth, cHorizontalHeight);
+ }
+
+ if (!hasButtons())
+ return IntRect(x(), y(), cVerticalWidth, height());
+ return IntRect(x(), y() + cVerticalButtonHeight, cVerticalWidth, height() - 2 * cVerticalButtonHeight);
+}
+
+IntRect PlatformScrollbar::thumbRect() const
+{
+ IntRect beforeThumbRect, thumbRect, afterThumbRect;
+ splitTrack(trackRect(), beforeThumbRect, thumbRect, afterThumbRect);
+ return thumbRect;
+}
+
+IntRect PlatformScrollbar::gripperRect(const IntRect& thumbRect) const
+{
+ return IntRect();
+}
+
+void PlatformScrollbar::splitTrack(const IntRect& trackRect, IntRect& beforeThumbRect, IntRect& thumbRect, IntRect& afterThumbRect) const
+{
+ // This function won't even get called unless we're big enough to have some combination of these three rects where at least
+ // one of them is non-empty.
+ int thumbPos = thumbPosition();
+ if (m_orientation == HorizontalScrollbar) {
+ thumbRect = IntRect(trackRect.x() + thumbPos, trackRect.y() + (trackRect.height() - cThumbHeight) / 2, thumbLength(), cThumbHeight);
+ beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), thumbPos, trackRect.height());
+ afterThumbRect = IntRect(thumbRect.x() + thumbRect.width(), trackRect.y(), trackRect.right() - thumbRect.right(), trackRect.height());
+ } else {
+ thumbRect = IntRect(trackRect.x() + (trackRect.width() - cThumbWidth) / 2, trackRect.y() + thumbPos, cThumbWidth, thumbLength());
+ beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), trackRect.width(), thumbPos);
+ afterThumbRect = IntRect(trackRect.x(), thumbRect.y() + thumbRect.height(), trackRect.width(), trackRect.bottom() - thumbRect.bottom());
+ }
+}
+
+int PlatformScrollbar::thumbPosition() const
+{
+ if (isEnabled())
+ return (float)m_currentPos * (trackLength() - thumbLength()) / (m_totalSize - m_visibleSize);
+ return 0;
+}
+
+int PlatformScrollbar::thumbLength() const
+{
+ if (!isEnabled())
+ return 0;
+
+ float proportion = (float)(m_visibleSize) / m_totalSize;
+ int trackLen = trackLength();
+ int length = proportion * trackLen;
+ int minLength = cThumbMinLength;
+ length = max(length, minLength);
+ if (length > trackLen)
+ length = 0; // Once the thumb is below the track length, it just goes away (to make more room for the track).
+ return length;
+}
+
+int PlatformScrollbar::trackLength() const
+{
+ return (m_orientation == HorizontalScrollbar) ? trackRect().width() : trackRect().height();
+}
+
+void PlatformScrollbar::paintButton(GraphicsContext* context, const IntRect& rect, bool start, const IntRect& damageRect) const
+{
+ IntRect paintRect = buttonRepaintRect(rect, m_orientation, controlSize(), start);
+
+ if (!damageRect.intersects(paintRect))
+ return;
+
+ unsigned part = 0;
+ unsigned state = 0;
+ unsigned classicPart = 0;
+ unsigned classicState = 0;
+
+ if (m_orientation == HorizontalScrollbar) {
+ state = start ? ABS_LEFTNORMAL : ABS_RIGHTNORMAL;
+ classicPart = start ? DFCS_SCROLLLEFT : DFCS_SCROLLRIGHT;
+ } else {
+ state = start ? ABS_UPNORMAL : ABS_DOWNNORMAL;
+ classicPart = start ? DFCS_SCROLLUP : DFCS_SCROLLDOWN;
+ }
+
+ if (!isEnabled()) {
+ state += SP_ABS_DISABLE_MODIFIER;
+ classicState |= DFCS_INACTIVE;
+ } else if ((m_pressedPart == BackButtonPart && start)
+ || (m_pressedPart == ForwardButtonPart && !start)) {
+ state += SP_ABS_PRESSED_MODIFIER;
+ classicState |= DFCS_PUSHED | DFCS_FLAT;
+ } else if (m_client->isActive()) {
+ state += SP_ABS_HOT_MODIFIER;
+ classicState |= DFCS_HOT;
+ }
+
+ HDC hdc = prepareForDrawing(context, rect);
+ RECT widgetRect = rect;
+ checkAndInitScrollbarTheme();
+
+ if (cScrollBarTheme)
+ DrawThemeBackground(cScrollBarTheme, hdc, SP_BUTTON, state, &widgetRect, NULL);
+ else
+ DrawFrameControl(hdc, &widgetRect, classicPart, classicState);
+
+ doneDrawing(context, hdc, rect);
+}
+
+void PlatformScrollbar::paintTrack(GraphicsContext* context, const IntRect& rect, bool start, const IntRect& damageRect) const
+{
+ IntRect paintRect = hasButtons() ? trackRepaintRect(rect, m_orientation, controlSize()) : rect;
+
+ if (!damageRect.intersects(paintRect))
+ return;
+
+ unsigned part = 0;
+ unsigned classicPart = DFC_SCROLL;
+ if (m_orientation == HorizontalScrollbar)
+ part = start ? SP_TRACKSTARTHOR : SP_TRACKENDHOR;
+ else
+ part = start ? SP_TRACKSTARTVERT : SP_TRACKENDVERT;
+
+ unsigned state = TS_DISABLED;
+ unsigned classicState = DFCS_MONO;
+ if (m_client->isActive())
+ state |= TS_ACTIVE;
+ else
+ classicState |= DFCS_INACTIVE;
+
+ if (hasButtons())
+ state |= TS_NORMAL;
+
+ HDC hdc = prepareForDrawing(context, rect);
+ RECT widgetRect = rect;
+ checkAndInitScrollbarTheme();
+
+ if (cScrollBarTheme)
+ DrawThemeBackground(cScrollBarTheme, hdc, part, state, &widgetRect, NULL);
+ else
+ DrawFrameControl(hdc, &widgetRect, DFC_SCROLL, classicState);
+
+ doneDrawing(context, hdc, rect);
+}
+
+void PlatformScrollbar::paintThumb(GraphicsContext* context, const IntRect& rect, const IntRect& damageRect) const
+{
+ if (!damageRect.intersects(rect))
+ return;
+
+ unsigned part = (m_orientation == HorizontalScrollbar) ? SP_THUMBHOR : SP_THUMBVERT;
+ unsigned state = 0;
+
+ if (!isEnabled())
+ state += SP_ABS_DISABLE_MODIFIER;
+ else if (m_client->isActive())
+ state += SP_ABS_HOT_MODIFIER;
+
+ HDC hdc = prepareForDrawing(context, rect);
+ RECT widgetRect = rect;
+ checkAndInitScrollbarTheme();
+
+ if (cScrollBarTheme) {
+ DrawThemeBackground(cScrollBarTheme, hdc, part, state, &widgetRect, NULL);
+ paintGripper(hdc, widgetRect);
+ } else {
+ HGDIOBJ hSaveBrush = SelectObject(hdc, GetSysColorBrush(COLOR_BTNFACE));
+ DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_RECT);
+ SelectObject(hdc,hSaveBrush);
+ }
+
+ doneDrawing(context, hdc, rect);
+}
+
+void PlatformScrollbar::paintGripper(HDC hdc, const IntRect& rect) const
+{
+ unsigned part = (m_orientation == HorizontalScrollbar) ? SP_GRIPPERHOR : SP_GRIPPERVERT;
+ unsigned state = 0;
+
+ if (m_client->isActive())
+ state |= TS_ACTIVE;
+
+ RECT widgetRect = rect;
+ checkAndInitScrollbarTheme();
+
+ if (cScrollBarTheme)
+ DrawThemeBackground(cScrollBarTheme, hdc, part, state, &widgetRect, NULL);
+}
+
+ScrollbarPart PlatformScrollbar::hitTest(const PlatformMouseEvent& evt)
+{
+ if (!isEnabled())
+ return NoPart;
+
+ IntPoint mousePosition = convertFromContainingWindow(evt.pos());
+ mousePosition.move(x(), y());
+
+ if (hasButtons()) {
+ if (backButtonRect().contains(mousePosition))
+ return BackButtonPart;
+
+ if (forwardButtonRect().contains(mousePosition))
+ return ForwardButtonPart;
+ }
+
+ if (!hasThumb())
+ return NoPart;
+
+ IntRect track = trackRect();
+ if (track.contains(mousePosition)) {
+ IntRect beforeThumbRect, thumbRect, afterThumbRect;
+ splitTrack(track, beforeThumbRect, thumbRect, afterThumbRect);
+ if (beforeThumbRect.contains(mousePosition))
+ return BackTrackPart;
+ if (thumbRect.contains(mousePosition))
+ return ThumbPart;
+ return ForwardTrackPart;
+ }
+
+ return NoPart;
+}
+
+bool PlatformScrollbar::handleMouseMoveEvent(const PlatformMouseEvent& evt)
+{
+ if (m_pressedPart == ThumbPart) {
+ // Drag the thumb.
+ int thumbPos = thumbPosition();
+ int thumbLen = thumbLength();
+ int trackLen = trackLength();
+ int maxPos = trackLen - thumbLen;
+ int delta = 0;
+ if (m_orientation == HorizontalScrollbar)
+ delta = convertFromContainingWindow(evt.pos()).x() - m_pressedPos;
+ else
+ delta = convertFromContainingWindow(evt.pos()).y() - m_pressedPos;
+
+ if (delta > 0)
+ // The mouse moved down/right.
+ delta = min(maxPos - thumbPos, delta);
+ else if (delta < 0)
+ // The mouse moved up/left.
+ delta = max(-thumbPos, delta);
+
+ if (delta != 0) {
+ setValue((float)(thumbPos + delta) * (m_totalSize - m_visibleSize) / (trackLen - thumbLen));
+ m_pressedPos += thumbPosition() - thumbPos;
+ }
+
+ return true;
+ }
+
+ if (m_pressedPart != NoPart)
+ m_pressedPos = (m_orientation == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y());
+
+ ScrollbarPart part = hitTest(evt);
+ if (part != m_hoveredPart) {
+ if (m_pressedPart != NoPart) {
+ if (part == m_pressedPart) {
+ // The mouse is moving back over the pressed part. We
+ // need to start up the timer action again.
+ startTimerIfNeeded(cNormalTimerDelay);
+ invalidatePart(m_pressedPart);
+ } else if (m_hoveredPart == m_pressedPart) {
+ // The mouse is leaving the pressed part. Kill our timer
+ // if needed.
+ stopTimerIfNeeded();
+ invalidatePart(m_pressedPart);
+ }
+ } else {
+ invalidatePart(part);
+ invalidatePart(m_hoveredPart);
+ }
+ m_hoveredPart = part;
+ }
+
+ return true;
+}
+
+bool PlatformScrollbar::handleMouseOutEvent(const PlatformMouseEvent& evt)
+{
+ invalidatePart(m_hoveredPart);
+ m_hoveredPart = NoPart;
+
+ return true;
+}
+
+bool PlatformScrollbar::handleMousePressEvent(const PlatformMouseEvent& evt)
+{
+ m_pressedPart = hitTest(evt);
+ m_pressedPos = (m_orientation == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y());
+ invalidatePart(m_pressedPart);
+ autoscrollPressedPart(cInitialTimerDelay);
+ return true;
+}
+
+bool PlatformScrollbar::handleMouseReleaseEvent(const PlatformMouseEvent& evt)
+{
+ invalidatePart(m_pressedPart);
+ m_pressedPart = NoPart;
+ m_pressedPos = 0;
+ stopTimerIfNeeded();
+
+ if (parent() && parent()->isFrameView())
+ static_cast<FrameView*>(parent())->frame()->eventHandler()->setMousePressed(false);
+
+ return true;
+}
+
+void PlatformScrollbar::startTimerIfNeeded(double delay)
+{
+ // Don't do anything for the thumb.
+ if (m_pressedPart == ThumbPart)
+ return;
+
+ // Handle the track. We halt track scrolling once the thumb is level
+ // with us.
+ if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse()) {
+ invalidatePart(m_pressedPart);
+ m_hoveredPart = ThumbPart;
+ return;
+ }
+
+ // We can't scroll if we've hit the beginning or end.
+ ScrollDirection dir = pressedPartScrollDirection();
+ if (dir == ScrollUp || dir == ScrollLeft) {
+ if (m_currentPos == 0)
+ return;
+ } else {
+ if (m_currentPos == m_totalSize - m_visibleSize)
+ return;
+ }
+
+ m_scrollTimer.startOneShot(delay);
+}
+
+void PlatformScrollbar::stopTimerIfNeeded()
+{
+ if (m_scrollTimer.isActive())
+ m_scrollTimer.stop();
+}
+
+void PlatformScrollbar::autoscrollPressedPart(double delay)
+{
+ // Don't do anything for the thumb or if nothing was pressed.
+ if (m_pressedPart == ThumbPart || m_pressedPart == NoPart)
+ return;
+
+ // Handle the track.
+ if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse()) {
+ invalidatePart(m_pressedPart);
+ m_hoveredPart = ThumbPart;
+ return;
+ }
+
+ // Handle the arrows and track.
+ if (scroll(pressedPartScrollDirection(), pressedPartScrollGranularity()))
+ startTimerIfNeeded(delay);
+}
+
+void PlatformScrollbar::autoscrollTimerFired(Timer<PlatformScrollbar>*)
+{
+ autoscrollPressedPart(cNormalTimerDelay);
+}
+
+ScrollDirection PlatformScrollbar::pressedPartScrollDirection()
+{
+ if (m_orientation == HorizontalScrollbar) {
+ if (m_pressedPart == BackButtonPart || m_pressedPart == BackTrackPart)
+ return ScrollLeft;
+ return ScrollRight;
+ } else {
+ if (m_pressedPart == BackButtonPart || m_pressedPart == BackTrackPart)
+ return ScrollUp;
+ return ScrollDown;
+ }
+}
+
+ScrollGranularity PlatformScrollbar::pressedPartScrollGranularity()
+{
+ if (m_pressedPart == BackButtonPart || m_pressedPart == ForwardButtonPart)
+ return ScrollByLine;
+ return ScrollByPage;
+}
+
+bool PlatformScrollbar::thumbUnderMouse()
+{
+ // Construct a rect.
+ IntRect thumb = thumbRect();
+ thumb.move(-x(), -y());
+ int begin = (m_orientation == HorizontalScrollbar) ? thumb.x() : thumb.y();
+ int end = (m_orientation == HorizontalScrollbar) ? thumb.right() : thumb.bottom();
+ return (begin <= m_pressedPos && m_pressedPos < end);
+}
+
+int PlatformScrollbar::horizontalScrollbarHeight(ScrollbarControlSize controlSize)
+{
+ return cHorizontalWidth;
+}
+
+int PlatformScrollbar::verticalScrollbarWidth(ScrollbarControlSize controlSize)
+{
+ return cVerticalHeight;
+}
+
+IntRect PlatformScrollbar::windowClipRect() const
+{
+ IntRect clipRect(0, 0, width(), height());
+
+ clipRect = convertToContainingWindow(clipRect);
+ if (m_client)
+ clipRect.intersect(m_client->windowClipRect());
+
+ return clipRect;
+}
+
+void PlatformScrollbar::themeChanged()
+{
+}
+
+}
+
diff --git a/WebCore/platform/win/PopupMenuWin.cpp b/WebCore/platform/win/PopupMenuWin.cpp
new file mode 100644
index 0000000..466d881
--- /dev/null
+++ b/WebCore/platform/win/PopupMenuWin.cpp
@@ -0,0 +1,826 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc.
+ *
+ * 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 "PopupMenu.h"
+
+#include "Document.h"
+#include "FloatRect.h"
+#include "FontSelector.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLNames.h"
+#include "Page.h"
+#include "PlatformMouseEvent.h"
+#include "PlatformScreen.h"
+#include "PlatformScrollBar.h"
+#include "RenderTheme.h"
+#include "RenderView.h"
+#include "SimpleFontData.h"
+#include <tchar.h>
+#include <windows.h>
+
+using std::min;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// Default Window animation duration in milliseconds
+static const int defaultAnimationDuration = 200;
+// Maximum height of a popup window
+static const int maxPopupHeight = 320;
+
+static const int popupWindowAlphaPercent = 95;
+
+const int optionSpacingMiddle = 1;
+const int popupWindowBorderWidth = 1;
+
+static LPCTSTR kPopupWindowClassName = _T("PopupWindowClass");
+static ATOM registerPopup();
+static LRESULT CALLBACK PopupWndProc(HWND, UINT, WPARAM, LPARAM);
+
+// FIXME: Remove this as soon as practical.
+static inline bool isASCIIPrintable(unsigned c)
+{
+ return c >= 0x20 && c <= 0x7E;
+}
+
+PopupMenu::PopupMenu(PopupMenuClient* client)
+ : RefCounted<PopupMenu>(0)
+ , m_popupClient(client)
+ , m_scrollBar(0)
+ , m_popup(0)
+ , m_DC(0)
+ , m_bmp(0)
+ , m_wasClicked(false)
+ , m_itemHeight(0)
+ , m_scrollOffset(0)
+ , m_wheelDelta(0)
+ , m_focusedIndex(0)
+ , m_scrollbarCapturingMouse(false)
+{
+}
+
+PopupMenu::~PopupMenu()
+{
+ if (m_bmp)
+ ::DeleteObject(m_bmp);
+ if (m_DC)
+ ::DeleteObject(m_DC);
+ if (m_popup)
+ ::DestroyWindow(m_popup);
+}
+
+void PopupMenu::show(const IntRect& r, FrameView* v, int index)
+{
+ calculatePositionAndSize(r, v);
+ if (clientRect().isEmpty())
+ return;
+
+ if (!m_popup) {
+ registerPopup();
+
+ DWORD exStyle = WS_EX_LAYERED | WS_EX_LTRREADING;
+
+ // Even though we already know our size and location at this point, we pass (0,0,0,0) as our size/location here.
+ // We need to wait until after the call to ::SetWindowLongPtr to set our size so that in our WM_SIZE handler we can get access to the PopupMenu object
+ m_popup = ::CreateWindowEx(exStyle, kPopupWindowClassName, _T("PopupMenu"),
+ WS_POPUP | WS_BORDER,
+ 0, 0, 0, 0,
+ v->containingWindow(), 0, 0, 0);
+
+ if (!m_popup)
+ return;
+
+ ::SetWindowLongPtr(m_popup, 0, (LONG_PTR)this);
+ ::SetLayeredWindowAttributes(m_popup, 0, (255 * popupWindowAlphaPercent) / 100, LWA_ALPHA);
+ }
+
+ if (!m_scrollBar)
+ if (visibleItems() < client()->listSize()) {
+ // We need a scroll bar
+ m_scrollBar = new PlatformScrollbar(this, VerticalScrollbar, SmallScrollbar);
+ m_scrollBar->setContainingWindow(m_popup);
+ }
+
+ ::SetWindowPos(m_popup, HWND_TOP, m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height(), 0);
+
+ // Determine whether we should animate our popups
+ // Note: Must use 'BOOL' and 'FALSE' instead of 'bool' and 'false' to avoid stack corruption with SystemParametersInfo
+ BOOL shouldAnimate = FALSE;
+#ifdef CAN_ANIMATE_TRANSPARENT_WINDOWS_SMOOTHLY
+ ::SystemParametersInfo(SPI_GETCOMBOBOXANIMATION, 0, &shouldAnimate, 0);
+#endif
+
+ if (shouldAnimate) {
+ RECT viewRect = {0};
+ ::GetWindowRect(v->containingWindow(), &viewRect);
+
+ if (!::IsRectEmpty(&viewRect)) {
+ // Popups should slide into view away from the <select> box
+ // NOTE: This may have to change for Vista
+ DWORD slideDirection = (m_windowRect.y() < viewRect.top + v->contentsToWindow(r.location()).y()) ? AW_VER_NEGATIVE : AW_VER_POSITIVE;
+
+ ::AnimateWindow(m_popup, defaultAnimationDuration, AW_SLIDE | slideDirection | AW_ACTIVATE);
+ }
+ } else
+ ::ShowWindow(m_popup, SW_SHOWNORMAL);
+ ::SetCapture(m_popup);
+
+ if (client()) {
+ int index = client()->selectedIndex();
+ if (index >= 0)
+ setFocusedIndex(index);
+ }
+}
+
+void PopupMenu::hide()
+{
+ ::ShowWindow(m_popup, SW_HIDE);
+}
+
+const int endOfLinePadding = 2;
+void PopupMenu::calculatePositionAndSize(const IntRect& r, FrameView* v)
+{
+ // r is in absolute document coordinates, but we want to be in screen coordinates
+
+ // First, move to WebView coordinates
+ IntRect rScreenCoords(v->contentsToWindow(r.location()), r.size());
+
+ // Then, translate to screen coordinates
+ POINT location(rScreenCoords.location());
+ if (!::ClientToScreen(v->containingWindow(), &location))
+ return;
+
+ rScreenCoords.setLocation(location);
+
+ // First, determine the popup's height
+ int itemCount = client()->listSize();
+ m_itemHeight = client()->clientStyle()->font().height() + optionSpacingMiddle;
+ int naturalHeight = m_itemHeight * itemCount;
+ int popupHeight = min(maxPopupHeight, naturalHeight);
+ // The popup should show an integral number of items (i.e. no partial items should be visible)
+ popupHeight -= popupHeight % m_itemHeight;
+
+ // Next determine its width
+ int popupWidth = 0;
+ for (int i = 0; i < itemCount; ++i) {
+ String text = client()->itemText(i);
+ if (text.isEmpty())
+ continue;
+
+ popupWidth = max(popupWidth, client()->clientStyle()->font().width(TextRun(text.characters(), text.length())));
+ }
+
+ if (naturalHeight > maxPopupHeight)
+ // We need room for a scrollbar
+ popupWidth += PlatformScrollbar::verticalScrollbarWidth(SmallScrollbar);
+
+ // Add padding to align the popup text with the <select> text
+ // Note: We can't add paddingRight() because that value includes the width
+ // of the dropdown button, so we must use our own endOfLinePadding constant.
+ popupWidth += max(0, endOfLinePadding - client()->clientInsetRight()) + max(0, client()->clientPaddingLeft() - client()->clientInsetLeft());
+
+ // Leave room for the border
+ popupWidth += 2 * popupWindowBorderWidth;
+ popupHeight += 2 * popupWindowBorderWidth;
+
+ // The popup should be at least as wide as the control on the page
+ popupWidth = max(rScreenCoords.width() - client()->clientInsetLeft() - client()->clientInsetRight(), popupWidth);
+
+ // Always left-align items in the popup. This matches popup menus on the mac.
+ int popupX = rScreenCoords.x() + client()->clientInsetLeft();
+
+ IntRect popupRect(popupX, rScreenCoords.bottom(), popupWidth, popupHeight);
+
+ // The popup needs to stay within the bounds of the screen and not overlap any toolbars
+ FloatRect screen = screenAvailableRect(v);
+
+ // Check that we don't go off the screen vertically
+ if (popupRect.bottom() > screen.height()) {
+ // The popup will go off the screen, so try placing it above the client
+ if (rScreenCoords.y() - popupRect.height() < 0) {
+ // The popup won't fit above, either, so place it whereever's bigger and resize it to fit
+ if ((rScreenCoords.y() + rScreenCoords.height() / 2) < (screen.height() / 2)) {
+ // Below is bigger
+ popupRect.setHeight(screen.height() - popupRect.y());
+ } else {
+ // Above is bigger
+ popupRect.setY(0);
+ popupRect.setHeight(rScreenCoords.y());
+ }
+ } else {
+ // The popup fits above, so reposition it
+ popupRect.setY(rScreenCoords.y() - popupRect.height());
+ }
+ }
+
+ // Check that we don't go off the screen horizontally
+ if (popupRect.x() < screen.x()) {
+ popupRect.setWidth(popupRect.width() - (screen.x() - popupRect.x()));
+ popupRect.setX(screen.x());
+ }
+ m_windowRect = popupRect;
+ return;
+}
+
+bool PopupMenu::setFocusedIndex(int i, bool hotTracking)
+{
+ if (i < 0 || i >= client()->listSize() || i == focusedIndex())
+ return false;
+
+ if (!client()->itemIsEnabled(i))
+ return false;
+
+ invalidateItem(focusedIndex());
+ invalidateItem(i);
+
+ m_focusedIndex = i;
+
+ if (!hotTracking)
+ client()->setTextFromItem(i);
+
+ if (!scrollToRevealSelection())
+ ::UpdateWindow(m_popup);
+
+ return true;
+}
+
+int PopupMenu::visibleItems() const
+{
+ return clientRect().height() / m_itemHeight;
+}
+
+int PopupMenu::listIndexAtPoint(const IntPoint& point) const
+{
+ return m_scrollOffset + point.y() / m_itemHeight;
+}
+
+int PopupMenu::focusedIndex() const
+{
+ return m_focusedIndex;
+}
+
+void PopupMenu::focusFirst()
+{
+ if (!client())
+ return;
+
+ int size = client()->listSize();
+
+ for (int i = 0; i < size; ++i)
+ if (client()->itemIsEnabled(i)) {
+ setFocusedIndex(i);
+ break;
+ }
+}
+
+void PopupMenu::focusLast()
+{
+ if (!client())
+ return;
+
+ int size = client()->listSize();
+
+ for (int i = size - 1; i > 0; --i)
+ if (client()->itemIsEnabled(i)) {
+ setFocusedIndex(i);
+ break;
+ }
+}
+
+bool PopupMenu::down(unsigned lines)
+{
+ if (!client())
+ return false;
+
+ int size = client()->listSize();
+
+ int lastSelectableIndex, selectedListIndex;
+ lastSelectableIndex = selectedListIndex = focusedIndex();
+ for (int i = selectedListIndex + 1; i >= 0 && i < size; ++i)
+ if (client()->itemIsEnabled(i)) {
+ lastSelectableIndex = i;
+ if (i >= selectedListIndex + (int)lines)
+ break;
+ }
+
+ return setFocusedIndex(lastSelectableIndex);
+}
+
+bool PopupMenu::up(unsigned lines)
+{
+ if (!client())
+ return false;
+
+ int size = client()->listSize();
+
+ int lastSelectableIndex, selectedListIndex;
+ lastSelectableIndex = selectedListIndex = focusedIndex();
+ for (int i = selectedListIndex - 1; i >= 0 && i < size; --i)
+ if (client()->itemIsEnabled(i)) {
+ lastSelectableIndex = i;
+ if (i <= selectedListIndex - (int)lines)
+ break;
+ }
+
+ return setFocusedIndex(lastSelectableIndex);
+}
+
+void PopupMenu::invalidateItem(int index)
+{
+ if (!m_popup)
+ return;
+
+ IntRect damageRect(clientRect());
+ damageRect.setY(m_itemHeight * (index - m_scrollOffset));
+ damageRect.setHeight(m_itemHeight);
+ if (m_scrollBar)
+ damageRect.setWidth(damageRect.width() - m_scrollBar->frameGeometry().width());
+
+ RECT r = damageRect;
+ ::InvalidateRect(m_popup, &r, TRUE);
+}
+
+IntRect PopupMenu::clientRect() const
+{
+ IntRect clientRect = m_windowRect;
+ clientRect.inflate(-popupWindowBorderWidth);
+ clientRect.setLocation(IntPoint(0, 0));
+ return clientRect;
+}
+
+void PopupMenu::incrementWheelDelta(int delta)
+{
+ m_wheelDelta += delta;
+}
+
+void PopupMenu::reduceWheelDelta(int delta)
+{
+ ASSERT(delta >= 0);
+ ASSERT(delta <= abs(m_wheelDelta));
+
+ if (m_wheelDelta > 0)
+ m_wheelDelta -= delta;
+ else if (m_wheelDelta < 0)
+ m_wheelDelta += delta;
+ else
+ return;
+}
+
+bool PopupMenu::scrollToRevealSelection()
+{
+ if (!m_scrollBar)
+ return false;
+
+ int index = focusedIndex();
+
+ if (index < m_scrollOffset) {
+ m_scrollBar->setValue(index);
+ return true;
+ }
+
+ if (index >= m_scrollOffset + visibleItems()) {
+ m_scrollBar->setValue(index - visibleItems() + 1);
+ return true;
+ }
+
+ return false;
+}
+
+void PopupMenu::updateFromElement()
+{
+ if (!m_popup)
+ return;
+
+ m_focusedIndex = client()->selectedIndex();
+
+ ::InvalidateRect(m_popup, 0, TRUE);
+ if (!scrollToRevealSelection())
+ ::UpdateWindow(m_popup);
+}
+
+bool PopupMenu::itemWritingDirectionIsNatural()
+{
+ return true;
+}
+
+const int separatorPadding = 4;
+const int separatorHeight = 1;
+void PopupMenu::paint(const IntRect& damageRect, HDC hdc)
+{
+ if (!m_popup)
+ return;
+
+ if (!m_DC) {
+ m_DC = ::CreateCompatibleDC(::GetDC(m_popup));
+ if (!m_DC)
+ return;
+ }
+
+ if (m_bmp) {
+ bool keepBitmap = false;
+ BITMAP bitmap;
+ if (GetObject(m_bmp, sizeof(bitmap), &bitmap))
+ keepBitmap = bitmap.bmWidth == clientRect().width()
+ && bitmap.bmHeight == clientRect().height();
+ if (!keepBitmap) {
+ DeleteObject(m_bmp);
+ m_bmp = 0;
+ }
+ }
+ if (!m_bmp) {
+ BITMAPINFO bitmapInfo;
+ bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bitmapInfo.bmiHeader.biWidth = clientRect().width();
+ bitmapInfo.bmiHeader.biHeight = -clientRect().height();
+ bitmapInfo.bmiHeader.biPlanes = 1;
+ bitmapInfo.bmiHeader.biBitCount = 32;
+ bitmapInfo.bmiHeader.biCompression = BI_RGB;
+ bitmapInfo.bmiHeader.biSizeImage = 0;
+ bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
+ bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
+ bitmapInfo.bmiHeader.biClrUsed = 0;
+ bitmapInfo.bmiHeader.biClrImportant = 0;
+
+ void* pixels = 0;
+ m_bmp = ::CreateDIBSection(m_DC, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0);
+ if (!m_bmp)
+ return;
+
+ ::SelectObject(m_DC, m_bmp);
+ }
+
+ GraphicsContext context(m_DC);
+
+ int itemCount = client()->listSize();
+
+ // listRect is the damageRect translated into the coordinates of the entire menu list (which is itemCount * m_itemHeight pixels tall)
+ IntRect listRect = damageRect;
+ listRect.move(IntSize(0, m_scrollOffset * m_itemHeight));
+
+ RenderStyle* clientStyle = client()->clientStyle();
+
+ for (int y = listRect.y(); y < listRect.bottom(); y += m_itemHeight) {
+ int index = y / m_itemHeight;
+
+ Color optionBackgroundColor, optionTextColor;
+ RenderStyle* itemStyle = client()->itemStyle(index);
+ if (index == focusedIndex()) {
+ optionBackgroundColor = theme()->activeListBoxSelectionBackgroundColor();
+ optionTextColor = theme()->activeListBoxSelectionForegroundColor();
+ } else {
+ optionBackgroundColor = client()->itemBackgroundColor(index);
+ optionTextColor = itemStyle->color();
+ }
+
+ // itemRect is in client coordinates
+ IntRect itemRect(0, (index - m_scrollOffset) * m_itemHeight, damageRect.width(), m_itemHeight);
+
+ // Draw the background for this menu item
+ if (itemStyle->visibility() != HIDDEN)
+ context.fillRect(itemRect, optionBackgroundColor);
+
+ if (client()->itemIsSeparator(index)) {
+ IntRect separatorRect(itemRect.x() + separatorPadding, itemRect.y() + (itemRect.height() - separatorHeight) / 2, itemRect.width() - 2 * separatorPadding, separatorHeight);
+ context.fillRect(separatorRect, optionTextColor);
+ continue;
+ }
+
+ String itemText = client()->itemText(index);
+
+ unsigned length = itemText.length();
+ const UChar* string = itemText.characters();
+ TextRun textRun(string, length, false, 0, 0, itemText.defaultWritingDirection() == WTF::Unicode::RightToLeft);
+
+ context.setFillColor(optionTextColor);
+
+ Font itemFont = client()->clientStyle()->font();
+ if (client()->itemIsLabel(index)) {
+ FontDescription d = itemFont.fontDescription();
+ d.setBold(true);
+ itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing());
+ itemFont.update(m_popupClient->fontSelector());
+ }
+ context.setFont(itemFont);
+
+ // Draw the item text
+ if (itemStyle->visibility() != HIDDEN) {
+ int textX = max(0, client()->clientPaddingLeft() - client()->clientInsetLeft());
+ int textY = itemRect.y() + itemFont.ascent() + (itemRect.height() - itemFont.height()) / 2;
+ context.drawBidiText(textRun, IntPoint(textX, textY));
+ }
+ }
+
+ if (m_scrollBar)
+ m_scrollBar->paint(&context, damageRect);
+
+ if (!hdc)
+ hdc = ::GetDC(m_popup);
+
+ ::BitBlt(hdc, damageRect.x(), damageRect.y(), damageRect.width(), damageRect.height(), m_DC, damageRect.x(), damageRect.y(), SRCCOPY);
+}
+
+void PopupMenu::valueChanged(Scrollbar* scrollBar)
+{
+ ASSERT(m_scrollBar);
+
+ if (!m_popup)
+ return;
+
+ int offset = scrollBar->value();
+
+ if (m_scrollOffset == offset)
+ return;
+
+ int scrolledLines = m_scrollOffset - offset;
+ m_scrollOffset = offset;
+
+ UINT flags = SW_INVALIDATE;
+
+#ifdef CAN_SET_SMOOTH_SCROLLING_DURATION
+ BOOL shouldSmoothScroll = FALSE;
+ ::SystemParametersInfo(SPI_GETLISTBOXSMOOTHSCROLLING, 0, &shouldSmoothScroll, 0);
+ if (shouldSmoothScroll)
+ flags |= MAKEWORD(SW_SMOOTHSCROLL, smoothScrollAnimationDuration);
+#endif
+
+ IntRect listRect = clientRect();
+ if (m_scrollBar)
+ listRect.setWidth(listRect.width() - m_scrollBar->frameGeometry().width());
+ RECT r = listRect;
+ ::ScrollWindowEx(m_popup, 0, scrolledLines * m_itemHeight, &r, 0, 0, 0, flags);
+ if (m_scrollBar) {
+ r = m_scrollBar->frameGeometry();
+ ::InvalidateRect(m_popup, &r, TRUE);
+ }
+ ::UpdateWindow(m_popup);
+}
+
+IntRect PopupMenu::windowClipRect() const
+{
+ return m_windowRect;
+}
+
+static ATOM registerPopup()
+{
+ static bool haveRegisteredWindowClass = false;
+
+ if (haveRegisteredWindowClass)
+ return true;
+
+ WNDCLASSEX wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+
+ wcex.style = 0;
+ wcex.lpfnWndProc = PopupWndProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = sizeof(PopupMenu*); // For the PopupMenu pointer
+ wcex.hInstance = Page::instanceHandle();
+ wcex.hIcon = 0;
+ wcex.hCursor = LoadCursor(0, IDC_ARROW);
+ wcex.hbrBackground = 0;
+ wcex.lpszMenuName = 0;
+ wcex.lpszClassName = kPopupWindowClassName;
+ wcex.hIconSm = 0;
+
+ haveRegisteredWindowClass = true;
+
+ return ::RegisterClassEx(&wcex);
+}
+
+const int smoothScrollAnimationDuration = 5000;
+static LRESULT CALLBACK PopupWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT lResult = 0;
+ LONG_PTR longPtr = GetWindowLongPtr(hWnd, 0);
+ PopupMenu* popup = reinterpret_cast<PopupMenu*>(longPtr);
+
+ switch (message) {
+ case WM_SIZE:
+ if (popup && popup->scrollBar()) {
+ IntSize size(LOWORD(lParam), HIWORD(lParam));
+ popup->scrollBar()->setRect(IntRect(size.width() - popup->scrollBar()->width(), 0, popup->scrollBar()->width(), size.height()));
+
+ int visibleItems = popup->visibleItems();
+ popup->scrollBar()->setEnabled(visibleItems < popup->client()->listSize());
+ popup->scrollBar()->setSteps(1, max(1, visibleItems - 1));
+ popup->scrollBar()->setProportion(visibleItems, popup->client()->listSize());
+ }
+ break;
+ case WM_ACTIVATE:
+ if (popup && popup->client() && wParam == WA_INACTIVE)
+ popup->client()->hidePopup();
+ break;
+ case WM_KILLFOCUS:
+ if (popup && popup->client() && (HWND)wParam != popup->popupHandle())
+ // Focus is going elsewhere, so hide
+ popup->client()->hidePopup();
+ break;
+ case WM_KEYDOWN:
+ if (popup && popup->client()) {
+ lResult = 0;
+ switch (LOWORD(wParam)) {
+ case VK_DOWN:
+ case VK_RIGHT:
+ popup->down();
+ break;
+ case VK_UP:
+ case VK_LEFT:
+ popup->up();
+ break;
+ case VK_HOME:
+ popup->focusFirst();
+ break;
+ case VK_END:
+ popup->focusLast();
+ break;
+ case VK_PRIOR:
+ if (popup->focusedIndex() != popup->scrollOffset()) {
+ // Set the selection to the first visible item
+ int firstVisibleItem = popup->scrollOffset();
+ popup->up(popup->focusedIndex() - firstVisibleItem);
+ } else
+ // The first visible item is selected, so move the selection back one page
+ popup->up(popup->visibleItems());
+ break;
+ case VK_NEXT:
+ if (popup) {
+ int lastVisibleItem = popup->scrollOffset() + popup->visibleItems() - 1;
+ if (popup->focusedIndex() != lastVisibleItem) {
+ // Set the selection to the last visible item
+ popup->down(lastVisibleItem - popup->focusedIndex());
+ } else
+ // The last visible item is selected, so move the selection forward one page
+ popup->down(popup->visibleItems());
+ }
+ break;
+ case VK_TAB:
+ ::SendMessage(popup->client()->clientDocument()->view()->containingWindow(), message, wParam, lParam);
+ popup->client()->hidePopup();
+ break;
+ default:
+ if (isASCIIPrintable(wParam))
+ // Send the keydown to the WebView so it can be used for type-to-select.
+ ::PostMessage(popup->client()->clientDocument()->view()->containingWindow(), message, wParam, lParam);
+ else
+ lResult = 1;
+ break;
+ }
+ }
+ break;
+ case WM_CHAR:
+ if (popup && popup->client()) {
+ lResult = 0;
+ int index;
+ switch (wParam) {
+ case 0x0D: // Enter/Return
+ popup->client()->hidePopup();
+ index = popup->focusedIndex();
+ ASSERT(index >= 0);
+ popup->client()->valueChanged(index);
+ break;
+ case 0x1B: // Escape
+ popup->client()->hidePopup();
+ break;
+ case 0x09: // TAB
+ case 0x08: // Backspace
+ case 0x0A: // Linefeed
+ default: // Character
+ lResult = 1;
+ break;
+ }
+ }
+ break;
+ case WM_MOUSEMOVE:
+ if (popup) {
+ IntPoint mousePoint(MAKEPOINTS(lParam));
+ if (popup->scrollBar()) {
+ IntRect scrollBarRect = popup->scrollBar()->frameGeometry();
+ if (popup->scrollbarCapturingMouse() || scrollBarRect.contains(mousePoint)) {
+ // Put the point into coordinates relative to the scroll bar
+ mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y());
+ PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(mousePoint.x(), mousePoint.y()));
+ popup->scrollBar()->handleMouseMoveEvent(event);
+ break;
+ }
+ }
+
+ BOOL shouldHotTrack = FALSE;
+ ::SystemParametersInfo(SPI_GETHOTTRACKING, 0, &shouldHotTrack, 0);
+
+ RECT bounds;
+ GetClientRect(popup->popupHandle(), &bounds);
+ if ((shouldHotTrack || wParam & MK_LBUTTON) && ::PtInRect(&bounds, mousePoint))
+ popup->setFocusedIndex(popup->listIndexAtPoint(mousePoint), true);
+
+ // Release capture if the left button isn't down, and the mousePoint is outside the popup window.
+ // This way, the WebView will get future mouse events in the rest of the window.
+ if (!(wParam & MK_LBUTTON) && !::PtInRect(&bounds, mousePoint)) {
+ ::ReleaseCapture();
+ break;
+ }
+ }
+ break;
+ case WM_LBUTTONDOWN:
+ if (popup) {
+ ::SetCapture(popup->popupHandle());
+ IntPoint mousePoint(MAKEPOINTS(lParam));
+ if (popup->scrollBar()) {
+ IntRect scrollBarRect = popup->scrollBar()->frameGeometry();
+ if (scrollBarRect.contains(mousePoint)) {
+ // Put the point into coordinates relative to the scroll bar
+ mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y());
+ PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(mousePoint.x(), mousePoint.y()));
+ popup->scrollBar()->handleMousePressEvent(event);
+ popup->setScrollbarCapturingMouse(true);
+ break;
+ }
+ }
+
+ popup->setFocusedIndex(popup->listIndexAtPoint(mousePoint), true);
+ }
+ break;
+ case WM_LBUTTONUP:
+ if (popup) {
+ IntPoint mousePoint(MAKEPOINTS(lParam));
+ if (popup->scrollBar()) {
+ ::ReleaseCapture();
+ IntRect scrollBarRect = popup->scrollBar()->frameGeometry();
+ if (popup->scrollbarCapturingMouse() || scrollBarRect.contains(mousePoint)) {
+ popup->setScrollbarCapturingMouse(false);
+ // Put the point into coordinates relative to the scroll bar
+ mousePoint.move(-scrollBarRect.x(), -scrollBarRect.y());
+ PlatformMouseEvent event(hWnd, message, wParam, MAKELPARAM(mousePoint.x(), mousePoint.y()));
+ popup->scrollBar()->handleMouseReleaseEvent(event);
+ // FIXME: This is a hack to work around PlatformScrollbar not invalidating correctly when it doesn't have a parent widget
+ RECT r = scrollBarRect;
+ ::InvalidateRect(popup->popupHandle(), &r, TRUE);
+ break;
+ }
+ }
+ // Only release capture and hide the popup if the mouse is inside the popup window.
+ RECT bounds;
+ GetClientRect(popup->popupHandle(), &bounds);
+ if (popup->client() && ::PtInRect(&bounds, mousePoint)) {
+ ::ReleaseCapture();
+ popup->client()->hidePopup();
+ int index = popup->focusedIndex();
+ if (index >= 0)
+ popup->client()->valueChanged(index);
+ }
+ }
+ break;
+ case WM_MOUSEWHEEL:
+ if (popup && popup->scrollBar()) {
+ int i = 0;
+ for (popup->incrementWheelDelta(GET_WHEEL_DELTA_WPARAM(wParam)); abs(popup->wheelDelta()) >= WHEEL_DELTA; popup->reduceWheelDelta(WHEEL_DELTA))
+ if (popup->wheelDelta() > 0)
+ ++i;
+ else
+ --i;
+
+ popup->scrollBar()->scroll(i > 0 ? ScrollUp : ScrollDown, ScrollByLine, abs(i));
+ }
+ break;
+ case WM_PAINT:
+ if (popup) {
+ PAINTSTRUCT paintInfo;
+ ::BeginPaint(popup->popupHandle(), &paintInfo);
+ popup->paint(paintInfo.rcPaint, paintInfo.hdc);
+ ::EndPaint(popup->popupHandle(), &paintInfo);
+ lResult = 0;
+ }
+ break;
+ case WM_PRINTCLIENT:
+ if (popup)
+ popup->paint(popup->clientRect(), (HDC)wParam);
+ break;
+ default:
+ lResult = DefWindowProc(hWnd, message, wParam, lParam);
+ }
+
+ return lResult;
+}
+
+}
diff --git a/WebCore/platform/win/ScrollViewWin.cpp b/WebCore/platform/win/ScrollViewWin.cpp
new file mode 100644
index 0000000..705898a
--- /dev/null
+++ b/WebCore/platform/win/ScrollViewWin.cpp
@@ -0,0 +1,858 @@
+/*
+ * Copyright (C) 2006, 2007, 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 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 "Chrome.h"
+#include "ChromeClient.h"
+#include "FloatRect.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "IntRect.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "PlatformScrollBar.h"
+#include "PlatformMouseEvent.h"
+#include "PlatformWheelEvent.h"
+#include "RenderTheme.h"
+#include "ScrollBar.h"
+#include <algorithm>
+#include <winsock2.h>
+#include <windows.h>
+#include <wtf/Assertions.h>
+#include <wtf/HashSet.h>
+
+using namespace std;
+
+namespace WebCore {
+
+class ScrollView::ScrollViewPrivate : public ScrollbarClient {
+public:
+ ScrollViewPrivate(ScrollView* view)
+ : m_view(view)
+ , m_hasStaticBackground(false)
+ , m_scrollbarsSuppressed(false)
+ , m_inUpdateScrollbars(false)
+ , m_scrollbarsAvoidingResizer(0)
+ , m_vScrollbarMode(ScrollbarAuto)
+ , m_hScrollbarMode(ScrollbarAuto)
+ , m_visible(false)
+ , m_attachedToWindow(false)
+ {
+ }
+
+ ~ScrollViewPrivate()
+ {
+ setHasHorizontalScrollbar(false);
+ setHasVerticalScrollbar(false);
+ }
+
+ void setHasHorizontalScrollbar(bool hasBar);
+ void setHasVerticalScrollbar(bool hasBar);
+
+ virtual void valueChanged(Scrollbar*);
+ virtual IntRect windowClipRect() const;
+ virtual bool isActive() const;
+
+ void scrollBackingStore(const IntSize& scrollDelta);
+
+ void setAllowsScrolling(bool);
+ bool allowsScrolling() const;
+
+ ScrollView* m_view;
+ IntSize m_scrollOffset;
+ IntSize m_contentsSize;
+ bool m_hasStaticBackground;
+ bool m_scrollbarsSuppressed;
+ bool m_inUpdateScrollbars;
+ int m_scrollbarsAvoidingResizer;
+ ScrollbarMode m_vScrollbarMode;
+ ScrollbarMode m_hScrollbarMode;
+ RefPtr<PlatformScrollbar> m_vBar;
+ RefPtr<PlatformScrollbar> m_hBar;
+ HRGN m_dirtyRegion;
+ HashSet<Widget*> m_children;
+ bool m_visible;
+ bool m_attachedToWindow;
+};
+
+void ScrollView::ScrollViewPrivate::setHasHorizontalScrollbar(bool hasBar)
+{
+ if (Scrollbar::hasPlatformScrollbars()) {
+ if (hasBar && !m_hBar) {
+ m_hBar = new PlatformScrollbar(this, HorizontalScrollbar, RegularScrollbar);
+ m_view->addChild(m_hBar.get());
+ } else if (!hasBar && m_hBar) {
+ m_view->removeChild(m_hBar.get());
+ m_hBar = 0;
+ }
+ }
+}
+
+void ScrollView::ScrollViewPrivate::setHasVerticalScrollbar(bool hasBar)
+{
+ if (Scrollbar::hasPlatformScrollbars()) {
+ if (hasBar && !m_vBar) {
+ m_vBar = new PlatformScrollbar(this, VerticalScrollbar, RegularScrollbar);
+ m_view->addChild(m_vBar.get());
+ } else if (!hasBar && m_vBar) {
+ m_view->removeChild(m_vBar.get());
+ m_vBar = 0;
+ }
+ }
+}
+
+void ScrollView::ScrollViewPrivate::valueChanged(Scrollbar* bar)
+{
+ // Figure out if we really moved.
+ IntSize newOffset = m_scrollOffset;
+ if (bar) {
+ if (bar == m_hBar)
+ newOffset.setWidth(bar->value());
+ else if (bar == m_vBar)
+ newOffset.setHeight(bar->value());
+ }
+ IntSize scrollDelta = newOffset - m_scrollOffset;
+ if (scrollDelta == IntSize())
+ return;
+ m_scrollOffset = newOffset;
+
+ if (m_scrollbarsSuppressed)
+ return;
+
+ static_cast<FrameView*>(m_view)->frame()->sendScrollEvent();
+ scrollBackingStore(scrollDelta);
+}
+
+void ScrollView::ScrollViewPrivate::scrollBackingStore(const IntSize& scrollDelta)
+{
+ // Since scrolling is double buffered, we will be blitting the scroll view's intersection
+ // with the clip rect every time to keep it smooth.
+ HWND containingWindowHandle = m_view->containingWindow();
+ IntRect clipRect = m_view->windowClipRect();
+ IntRect scrollViewRect = m_view->convertToContainingWindow(IntRect(0, 0, m_view->visibleWidth(), m_view->visibleHeight()));
+ IntRect updateRect = clipRect;
+ updateRect.intersect(scrollViewRect);
+ RECT r = updateRect;
+ ::InvalidateRect(containingWindowHandle, &r, false);
+
+ if (!m_hasStaticBackground) // The main frame can just blit the WebView window
+ // FIXME: Find a way to blit subframes without blitting overlapping content
+ m_view->scrollBackingStore(-scrollDelta.width(), -scrollDelta.height(), scrollViewRect, clipRect);
+ else {
+ // We need to go ahead and repaint the entire backing store. Do it now before moving the
+ // plugins.
+ m_view->addToDirtyRegion(updateRect);
+ m_view->updateBackingStore();
+ }
+
+ // This call will move child HWNDs (plugins) and invalidate them as well.
+ m_view->geometryChanged();
+
+ // Now update the window (which should do nothing but a blit of the backing store's updateRect and so should
+ // be very fast).
+ ::UpdateWindow(containingWindowHandle);
+}
+
+void ScrollView::ScrollViewPrivate::setAllowsScrolling(bool flag)
+{
+ if (flag && m_vScrollbarMode == ScrollbarAlwaysOff)
+ m_vScrollbarMode = ScrollbarAuto;
+ else if (!flag)
+ m_vScrollbarMode = ScrollbarAlwaysOff;
+
+ if (flag && m_hScrollbarMode == ScrollbarAlwaysOff)
+ m_hScrollbarMode = ScrollbarAuto;
+ else if (!flag)
+ m_hScrollbarMode = ScrollbarAlwaysOff;
+
+ m_view->updateScrollbars(m_scrollOffset);
+}
+
+bool ScrollView::ScrollViewPrivate::allowsScrolling() const
+{
+ // Return YES if either horizontal or vertical scrolling is allowed.
+ return m_hScrollbarMode != ScrollbarAlwaysOff || m_vScrollbarMode != ScrollbarAlwaysOff;
+}
+
+IntRect ScrollView::ScrollViewPrivate::windowClipRect() const
+{
+ return static_cast<const FrameView*>(m_view)->windowClipRect(false);
+}
+
+bool ScrollView::ScrollViewPrivate::isActive() const
+{
+ Page* page = static_cast<const FrameView*>(m_view)->frame()->page();
+ return page && page->focusController()->isActive();
+}
+
+ScrollView::ScrollView()
+ : m_data(new ScrollViewPrivate(this))
+{
+}
+
+ScrollView::~ScrollView()
+{
+ delete m_data;
+}
+
+void ScrollView::updateContents(const IntRect& rect, bool now)
+{
+ if (rect.isEmpty())
+ return;
+
+ IntPoint windowPoint = contentsToWindow(rect.location());
+ IntRect containingWindowRect = rect;
+ containingWindowRect.setLocation(windowPoint);
+
+ RECT containingWindowRectWin = containingWindowRect;
+ HWND containingWindowHandle = containingWindow();
+
+ ::InvalidateRect(containingWindowHandle, &containingWindowRectWin, false);
+
+ // Cache the dirty spot.
+ addToDirtyRegion(containingWindowRect);
+
+ if (now)
+ ::UpdateWindow(containingWindowHandle);
+}
+
+void ScrollView::update()
+{
+ ::UpdateWindow(containingWindow());
+}
+
+int ScrollView::visibleWidth() const
+{
+ return max(0, width() - (m_data->m_vBar ? m_data->m_vBar->width() : 0));
+}
+
+int ScrollView::visibleHeight() const
+{
+ return max(0, height() - (m_data->m_hBar ? m_data->m_hBar->height() : 0));
+}
+
+FloatRect ScrollView::visibleContentRect() const
+{
+ return FloatRect(contentsX(), contentsY(), visibleWidth(), visibleHeight());
+}
+
+FloatRect ScrollView::visibleContentRectConsideringExternalScrollers() const
+{
+ // external scrollers not supported for now
+ return visibleContentRect();
+}
+
+void ScrollView::setContentsPos(int newX, int newY)
+{
+ int dx = newX - contentsX();
+ int dy = newY - contentsY();
+ scrollBy(dx, dy);
+}
+
+void ScrollView::resizeContents(int w, int h)
+{
+ IntSize newContentsSize(w, h);
+ if (m_data->m_contentsSize != newContentsSize) {
+ m_data->m_contentsSize = newContentsSize;
+ updateScrollbars(m_data->m_scrollOffset);
+ }
+}
+
+void ScrollView::setFrameGeometry(const IntRect& newGeometry)
+{
+ IntRect oldGeometry = frameGeometry();
+ Widget::setFrameGeometry(newGeometry);
+
+ if (newGeometry == oldGeometry)
+ return;
+
+ if (newGeometry.width() != oldGeometry.width() || newGeometry.height() != oldGeometry.height()) {
+ updateScrollbars(m_data->m_scrollOffset);
+ static_cast<FrameView*>(this)->setNeedsLayout();
+ }
+
+ geometryChanged();
+}
+
+int ScrollView::contentsX() const
+{
+ return scrollOffset().width();
+}
+
+int ScrollView::contentsY() const
+{
+ return scrollOffset().height();
+}
+
+int ScrollView::contentsWidth() const
+{
+ return m_data->m_contentsSize.width();
+}
+
+int ScrollView::contentsHeight() const
+{
+ return m_data->m_contentsSize.height();
+}
+
+IntPoint ScrollView::windowToContents(const IntPoint& windowPoint) const
+{
+ IntPoint viewPoint = convertFromContainingWindow(windowPoint);
+ return viewPoint + scrollOffset();
+}
+
+IntPoint ScrollView::contentsToWindow(const IntPoint& contentsPoint) const
+{
+ IntPoint viewPoint = contentsPoint - scrollOffset();
+ return convertToContainingWindow(viewPoint);
+}
+
+IntPoint ScrollView::convertChildToSelf(const Widget* child, const IntPoint& point) const
+{
+ IntPoint newPoint = point;
+ if (child != m_data->m_hBar && child != m_data->m_vBar)
+ newPoint = point - scrollOffset();
+ return Widget::convertChildToSelf(child, newPoint);
+}
+
+IntPoint ScrollView::convertSelfToChild(const Widget* child, const IntPoint& point) const
+{
+ IntPoint newPoint = point;
+ if (child != m_data->m_hBar && child != m_data->m_vBar)
+ newPoint = point + scrollOffset();
+ return Widget::convertSelfToChild(child, newPoint);
+}
+
+IntSize ScrollView::scrollOffset() const
+{
+ return m_data->m_scrollOffset;
+}
+
+IntSize ScrollView::maximumScroll() const
+{
+ IntSize delta = (m_data->m_contentsSize - IntSize(visibleWidth(), visibleHeight())) - scrollOffset();
+ delta.clampNegativeToZero();
+ return delta;
+}
+
+void ScrollView::scrollBy(int dx, int dy)
+{
+ IntSize scrollOffset = m_data->m_scrollOffset;
+ IntSize newScrollOffset = scrollOffset + IntSize(dx, dy).shrunkTo(maximumScroll());
+ newScrollOffset.clampNegativeToZero();
+
+ if (newScrollOffset == scrollOffset)
+ return;
+
+ updateScrollbars(newScrollOffset);
+}
+
+void ScrollView::scrollRectIntoViewRecursively(const IntRect& r)
+{
+ IntPoint p(max(0, r.x()), max(0, r.y()));
+ ScrollView* view = this;
+ while (view) {
+ view->setContentsPos(p.x(), p.y());
+ p.move(view->x() - view->scrollOffset().width(), view->y() - view->scrollOffset().height());
+ view = static_cast<ScrollView*>(view->parent());
+ }
+}
+
+WebCore::ScrollbarMode ScrollView::hScrollbarMode() const
+{
+ return m_data->m_hScrollbarMode;
+}
+
+WebCore::ScrollbarMode ScrollView::vScrollbarMode() const
+{
+ return m_data->m_vScrollbarMode;
+}
+
+void ScrollView::suppressScrollbars(bool suppressed, bool repaintOnSuppress)
+{
+ m_data->m_scrollbarsSuppressed = suppressed;
+ if (repaintOnSuppress && !suppressed) {
+ if (m_data->m_hBar)
+ m_data->m_hBar->invalidate();
+ if (m_data->m_vBar)
+ m_data->m_vBar->invalidate();
+
+ // Invalidate the scroll corner too on unsuppress.
+ IntRect hCorner;
+ if (m_data->m_hBar && width() - m_data->m_hBar->width() > 0) {
+ hCorner = IntRect(m_data->m_hBar->width(),
+ height() - m_data->m_hBar->height(),
+ width() - m_data->m_hBar->width(),
+ m_data->m_hBar->height());
+ invalidateRect(hCorner);
+ }
+
+ if (m_data->m_vBar && height() - m_data->m_vBar->height() > 0) {
+ IntRect vCorner(width() - m_data->m_vBar->width(),
+ m_data->m_vBar->height(),
+ m_data->m_vBar->width(),
+ height() - m_data->m_vBar->height());
+ if (vCorner != hCorner)
+ invalidateRect(vCorner);
+ }
+ }
+}
+
+void ScrollView::setHScrollbarMode(ScrollbarMode newMode)
+{
+ if (m_data->m_hScrollbarMode != newMode) {
+ m_data->m_hScrollbarMode = newMode;
+ updateScrollbars(m_data->m_scrollOffset);
+ }
+}
+
+void ScrollView::setVScrollbarMode(ScrollbarMode newMode)
+{
+ if (m_data->m_vScrollbarMode != newMode) {
+ m_data->m_vScrollbarMode = newMode;
+ updateScrollbars(m_data->m_scrollOffset);
+ }
+}
+
+void ScrollView::setScrollbarsMode(ScrollbarMode newMode)
+{
+ if (m_data->m_hScrollbarMode != newMode ||
+ m_data->m_vScrollbarMode != newMode) {
+ m_data->m_hScrollbarMode = m_data->m_vScrollbarMode = newMode;
+ updateScrollbars(m_data->m_scrollOffset);
+ }
+}
+
+void ScrollView::setStaticBackground(bool flag)
+{
+ m_data->m_hasStaticBackground = flag;
+}
+
+void ScrollView::updateScrollbars(const IntSize& desiredOffset)
+{
+ // Don't allow re-entrancy into this function.
+ if (m_data->m_inUpdateScrollbars)
+ return;
+
+ // FIXME: This code is here so we don't have to fork FrameView.h/.cpp.
+ // In the end, FrameView should just merge with ScrollView.
+ if (static_cast<const FrameView*>(this)->frame()->prohibitsScrolling())
+ return;
+
+ m_data->m_inUpdateScrollbars = true;
+
+ bool hasVerticalScrollbar = m_data->m_vBar;
+ bool hasHorizontalScrollbar = m_data->m_hBar;
+ bool oldHasVertical = hasVerticalScrollbar;
+ bool oldHasHorizontal = hasHorizontalScrollbar;
+ ScrollbarMode hScroll = m_data->m_hScrollbarMode;
+ ScrollbarMode vScroll = m_data->m_vScrollbarMode;
+
+ const int cVerticalWidth = PlatformScrollbar::verticalScrollbarWidth();
+ const int cHorizontalHeight = PlatformScrollbar::horizontalScrollbarHeight();
+
+ for (int pass = 0; pass < 2; pass++) {
+ bool scrollsVertically;
+ bool scrollsHorizontally;
+
+ if (!m_data->m_scrollbarsSuppressed && (hScroll == ScrollbarAuto || vScroll == ScrollbarAuto)) {
+ // Do a layout if pending before checking if scrollbars are needed.
+ if (hasVerticalScrollbar != oldHasVertical || hasHorizontalScrollbar != oldHasHorizontal)
+ static_cast<FrameView*>(this)->layout();
+
+ scrollsVertically = (vScroll == ScrollbarAlwaysOn) || (vScroll == ScrollbarAuto && contentsHeight() > height());
+ if (scrollsVertically)
+ scrollsHorizontally = (hScroll == ScrollbarAlwaysOn) || (hScroll == ScrollbarAuto && contentsWidth() + cVerticalWidth > width());
+ else {
+ scrollsHorizontally = (hScroll == ScrollbarAlwaysOn) || (hScroll == ScrollbarAuto && contentsWidth() > width());
+ if (scrollsHorizontally)
+ scrollsVertically = (vScroll == ScrollbarAlwaysOn) || (vScroll == ScrollbarAuto && contentsHeight() + cHorizontalHeight > height());
+ }
+ }
+ else {
+ scrollsHorizontally = (hScroll == ScrollbarAuto) ? hasHorizontalScrollbar : (hScroll == ScrollbarAlwaysOn);
+ scrollsVertically = (vScroll == ScrollbarAuto) ? hasVerticalScrollbar : (vScroll == ScrollbarAlwaysOn);
+ }
+
+ if (hasVerticalScrollbar != scrollsVertically) {
+ m_data->setHasVerticalScrollbar(scrollsVertically);
+ hasVerticalScrollbar = scrollsVertically;
+ }
+
+ if (hasHorizontalScrollbar != scrollsHorizontally) {
+ m_data->setHasHorizontalScrollbar(scrollsHorizontally);
+ hasHorizontalScrollbar = scrollsHorizontally;
+ }
+ }
+
+ // Set up the range (and page step/line step).
+ IntSize maxScrollPosition(contentsWidth() - visibleWidth(), contentsHeight() - visibleHeight());
+ IntSize scroll = desiredOffset.shrunkTo(maxScrollPosition);
+ scroll.clampNegativeToZero();
+
+ if (m_data->m_hBar) {
+ int clientWidth = visibleWidth();
+ m_data->m_hBar->setEnabled(contentsWidth() > clientWidth);
+ int pageStep = (clientWidth - PAGE_KEEP);
+ if (pageStep < 0) pageStep = clientWidth;
+ IntRect oldRect(m_data->m_hBar->frameGeometry());
+ IntRect hBarRect = IntRect(0,
+ height() - m_data->m_hBar->height(),
+ width() - (m_data->m_vBar ? m_data->m_vBar->width() : 0),
+ m_data->m_hBar->height());
+ m_data->m_hBar->setRect(hBarRect);
+ if (!m_data->m_scrollbarsSuppressed && oldRect != m_data->m_hBar->frameGeometry())
+ m_data->m_hBar->invalidate();
+
+ if (m_data->m_scrollbarsSuppressed)
+ m_data->m_hBar->setSuppressInvalidation(true);
+ m_data->m_hBar->setSteps(LINE_STEP, pageStep);
+ m_data->m_hBar->setProportion(clientWidth, contentsWidth());
+ m_data->m_hBar->setValue(scroll.width());
+ if (m_data->m_scrollbarsSuppressed)
+ m_data->m_hBar->setSuppressInvalidation(false);
+ }
+
+ if (m_data->m_vBar) {
+ int clientHeight = visibleHeight();
+ m_data->m_vBar->setEnabled(contentsHeight() > clientHeight);
+ int pageStep = (clientHeight - PAGE_KEEP);
+ if (pageStep < 0) pageStep = clientHeight;
+ IntRect oldRect(m_data->m_vBar->frameGeometry());
+ IntRect vBarRect = IntRect(width() - m_data->m_vBar->width(),
+ 0,
+ m_data->m_vBar->width(),
+ height() - (m_data->m_hBar ? m_data->m_hBar->height() : 0));
+ m_data->m_vBar->setRect(vBarRect);
+ if (!m_data->m_scrollbarsSuppressed && oldRect != m_data->m_vBar->frameGeometry())
+ m_data->m_vBar->invalidate();
+
+ if (m_data->m_scrollbarsSuppressed)
+ m_data->m_vBar->setSuppressInvalidation(true);
+ m_data->m_vBar->setSteps(LINE_STEP, pageStep);
+ m_data->m_vBar->setProportion(clientHeight, contentsHeight());
+ m_data->m_vBar->setValue(scroll.height());
+ if (m_data->m_scrollbarsSuppressed)
+ m_data->m_vBar->setSuppressInvalidation(false);
+ }
+
+ if (oldHasVertical != (m_data->m_vBar != 0) || oldHasHorizontal != (m_data->m_hBar != 0))
+ geometryChanged();
+
+ // See if our offset has changed in a situation where we might not have scrollbars.
+ // This can happen when editing a body with overflow:hidden and scrolling to reveal selection.
+ // It can also happen when maximizing a window that has scrollbars (but the new maximized result
+ // does not).
+ IntSize scrollDelta = scroll - m_data->m_scrollOffset;
+ if (scrollDelta != IntSize()) {
+ m_data->m_scrollOffset = scroll;
+ m_data->scrollBackingStore(scrollDelta);
+ }
+
+ m_data->m_inUpdateScrollbars = false;
+}
+
+PlatformScrollbar* ScrollView::scrollbarUnderMouse(const PlatformMouseEvent& mouseEvent)
+{
+ IntPoint viewPoint = convertFromContainingWindow(mouseEvent.pos());
+ if (m_data->m_hBar && m_data->m_hBar->frameGeometry().contains(viewPoint))
+ return m_data->m_hBar.get();
+ if (m_data->m_vBar && m_data->m_vBar->frameGeometry().contains(viewPoint))
+ return m_data->m_vBar.get();
+ return 0;
+}
+
+void ScrollView::addChild(Widget* child)
+{
+ child->setParent(this);
+ child->setContainingWindow(containingWindow());
+ m_data->m_children.add(child);
+}
+
+void ScrollView::removeChild(Widget* child)
+{
+ child->setParent(0);
+ m_data->m_children.remove(child);
+}
+
+void ScrollView::paint(GraphicsContext* context, const IntRect& rect)
+{
+ // FIXME: This code is here so we don't have to fork FrameView.h/.cpp.
+ // In the end, FrameView should just merge with ScrollView.
+ ASSERT(isFrameView());
+
+ if (context->paintingDisabled() && !context->updatingControlTints())
+ return;
+
+ IntRect documentDirtyRect = rect;
+ documentDirtyRect.intersect(frameGeometry());
+
+ context->save();
+
+ context->translate(x(), y());
+ documentDirtyRect.move(-x(), -y());
+
+ context->translate(-contentsX(), -contentsY());
+ documentDirtyRect.move(contentsX(), contentsY());
+
+ context->clip(enclosingIntRect(visibleContentRect()));
+
+ static_cast<const FrameView*>(this)->frame()->paint(context, documentDirtyRect);
+
+ context->restore();
+
+ // Now paint the scrollbars.
+ if (!m_data->m_scrollbarsSuppressed && (m_data->m_hBar || m_data->m_vBar)) {
+ context->save();
+ IntRect scrollViewDirtyRect = rect;
+ scrollViewDirtyRect.intersect(frameGeometry());
+ context->translate(x(), y());
+ scrollViewDirtyRect.move(-x(), -y());
+ if (m_data->m_hBar)
+ m_data->m_hBar->paint(context, scrollViewDirtyRect);
+ if (m_data->m_vBar)
+ m_data->m_vBar->paint(context, scrollViewDirtyRect);
+
+ // Fill the scroll corner with white.
+ IntRect hCorner;
+ if (m_data->m_hBar && width() - m_data->m_hBar->width() > 0) {
+ hCorner = IntRect(m_data->m_hBar->width(),
+ height() - m_data->m_hBar->height(),
+ width() - m_data->m_hBar->width(),
+ m_data->m_hBar->height());
+ if (hCorner.intersects(scrollViewDirtyRect))
+ context->fillRect(hCorner, Color::white);
+ }
+
+ if (m_data->m_vBar && height() - m_data->m_vBar->height() > 0) {
+ IntRect vCorner(width() - m_data->m_vBar->width(),
+ m_data->m_vBar->height(),
+ m_data->m_vBar->width(),
+ height() - m_data->m_vBar->height());
+ if (vCorner != hCorner && vCorner.intersects(scrollViewDirtyRect))
+ context->fillRect(vCorner, Color::white);
+ }
+
+ context->restore();
+ }
+}
+
+void ScrollView::themeChanged()
+{
+ PlatformScrollbar::themeChanged();
+ theme()->themeChanged();
+ invalidate();
+}
+
+void ScrollView::wheelEvent(PlatformWheelEvent& e)
+{
+ if (!m_data->allowsScrolling())
+ return;
+
+ // Determine how much we want to scroll. If we can move at all, we will accept the event.
+ IntSize maxScrollDelta = maximumScroll();
+ if ((e.deltaX() < 0 && maxScrollDelta.width() > 0) ||
+ (e.deltaX() > 0 && scrollOffset().width() > 0) ||
+ (e.deltaY() < 0 && maxScrollDelta.height() > 0) ||
+ (e.deltaY() > 0 && scrollOffset().height() > 0)) {
+ e.accept();
+ scrollBy(-e.deltaX() * LINE_STEP, -e.deltaY() * LINE_STEP);
+ }
+}
+
+HashSet<Widget*>* ScrollView::children()
+{
+ return &(m_data->m_children);
+}
+
+void ScrollView::geometryChanged() const
+{
+ HashSet<Widget*>::const_iterator end = m_data->m_children.end();
+ for (HashSet<Widget*>::const_iterator current = m_data->m_children.begin(); current != end; ++current)
+ (*current)->geometryChanged();
+}
+
+bool ScrollView::scroll(ScrollDirection direction, ScrollGranularity granularity)
+{
+ if (direction == ScrollUp || direction == ScrollDown) {
+ if (m_data->m_vBar)
+ return m_data->m_vBar->scroll(direction, granularity);
+ } else {
+ if (m_data->m_hBar)
+ return m_data->m_hBar->scroll(direction, granularity);
+ }
+ return false;
+}
+
+IntRect ScrollView::windowResizerRect()
+{
+ ASSERT(isFrameView());
+ const FrameView* frameView = static_cast<const FrameView*>(this);
+ Page* page = frameView->frame() ? frameView->frame()->page() : 0;
+ if (!page)
+ return IntRect();
+ return page->chrome()->windowResizerRect();
+}
+
+bool ScrollView::resizerOverlapsContent() const
+{
+ return !m_data->m_scrollbarsAvoidingResizer;
+}
+
+void ScrollView::adjustOverlappingScrollbarCount(int overlapDelta)
+{
+ int oldCount = m_data->m_scrollbarsAvoidingResizer;
+ m_data->m_scrollbarsAvoidingResizer += overlapDelta;
+ if (parent() && parent()->isFrameView())
+ static_cast<FrameView*>(parent())->adjustOverlappingScrollbarCount(overlapDelta);
+ else if (!m_data->m_scrollbarsSuppressed) {
+ // If we went from n to 0 or from 0 to n and we're the outermost view,
+ // we need to invalidate the windowResizerRect(), since it will now need to paint
+ // differently.
+ if (oldCount > 0 && m_data->m_scrollbarsAvoidingResizer == 0 ||
+ oldCount == 0 && m_data->m_scrollbarsAvoidingResizer > 0)
+ invalidateRect(windowResizerRect());
+ }
+}
+
+void ScrollView::setParent(ScrollView* parentView)
+{
+ if (!parentView && m_data->m_scrollbarsAvoidingResizer && parent() && parent()->isFrameView())
+ static_cast<FrameView*>(parent())->adjustOverlappingScrollbarCount(false);
+ Widget::setParent(parentView);
+}
+
+void ScrollView::attachToWindow()
+{
+ if (m_data->m_attachedToWindow)
+ return;
+
+ m_data->m_attachedToWindow = true;
+
+ if (m_data->m_visible) {
+ HashSet<Widget*>::iterator end = m_data->m_children.end();
+ for (HashSet<Widget*>::iterator it = m_data->m_children.begin(); it != end; ++it)
+ (*it)->attachToWindow();
+ }
+}
+
+void ScrollView::detachFromWindow()
+{
+ if (!m_data->m_attachedToWindow)
+ return;
+
+ if (m_data->m_visible) {
+ HashSet<Widget*>::iterator end = m_data->m_children.end();
+ for (HashSet<Widget*>::iterator it = m_data->m_children.begin(); it != end; ++it)
+ (*it)->detachFromWindow();
+ }
+
+ m_data->m_attachedToWindow = false;
+}
+
+void ScrollView::show()
+{
+ if (!m_data->m_visible) {
+ m_data->m_visible = true;
+ if (isAttachedToWindow()) {
+ HashSet<Widget*>::iterator end = m_data->m_children.end();
+ for (HashSet<Widget*>::iterator it = m_data->m_children.begin(); it != end; ++it)
+ (*it)->attachToWindow();
+ }
+ }
+
+ Widget::show();
+}
+
+void ScrollView::hide()
+{
+ if (m_data->m_visible) {
+ if (isAttachedToWindow()) {
+ HashSet<Widget*>::iterator end = m_data->m_children.end();
+ for (HashSet<Widget*>::iterator it = m_data->m_children.begin(); it != end; ++it)
+ (*it)->detachFromWindow();
+ }
+ m_data->m_visible = false;
+ }
+
+ Widget::hide();
+}
+
+bool ScrollView::isAttachedToWindow() const
+{
+ return m_data->m_attachedToWindow;
+}
+
+void ScrollView::addToDirtyRegion(const IntRect& containingWindowRect)
+{
+ ASSERT(isFrameView());
+ const FrameView* frameView = static_cast<const FrameView*>(this);
+ Page* page = frameView->frame() ? frameView->frame()->page() : 0;
+ if (!page)
+ return;
+ page->chrome()->addToDirtyRegion(containingWindowRect);
+}
+
+void ScrollView::scrollBackingStore(int dx, int dy, const IntRect& scrollViewRect, const IntRect& clipRect)
+{
+ ASSERT(isFrameView());
+ const FrameView* frameView = static_cast<const FrameView*>(this);
+ Page* page = frameView->frame() ? frameView->frame()->page() : 0;
+ if (!page)
+ return;
+ page->chrome()->scrollBackingStore(dx, dy, scrollViewRect, clipRect);
+}
+
+void ScrollView::updateBackingStore()
+{
+ ASSERT(isFrameView());
+ const FrameView* frameView = static_cast<const FrameView*>(this);
+ Page* page = frameView->frame() ? frameView->frame()->page() : 0;
+ if (!page)
+ return;
+ page->chrome()->updateBackingStore();
+}
+
+void ScrollView::setAllowsScrolling(bool flag)
+{
+ m_data->setAllowsScrolling(flag);
+}
+
+bool ScrollView::allowsScrolling() const
+{
+ return m_data->allowsScrolling();
+}
+
+bool ScrollView::inWindow() const
+{
+ // Needed for back/forward cache.
+ notImplemented();
+ return true;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/win/SearchPopupMenuWin.cpp b/WebCore/platform/win/SearchPopupMenuWin.cpp
new file mode 100644
index 0000000..f2709bb
--- /dev/null
+++ b/WebCore/platform/win/SearchPopupMenuWin.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc.
+ *
+ * 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 "SearchPopupMenu.h"
+
+#include "AtomicString.h"
+#include <wtf/RetainPtr.h>
+
+namespace WebCore {
+
+SearchPopupMenu::SearchPopupMenu(PopupMenuClient* client)
+ : PopupMenu(client)
+{
+}
+
+bool SearchPopupMenu::enabled()
+{
+ return true;
+}
+
+static RetainPtr<CFStringRef> autosaveKey(const String& name)
+{
+ String key = "com.apple.WebKit.searchField:" + name;
+ return RetainPtr<CFStringRef>(AdoptCF, key.createCFString());
+}
+
+void SearchPopupMenu::saveRecentSearches(const AtomicString& name, const Vector<String>& searchItems)
+{
+ if (name.isEmpty())
+ return;
+
+ RetainPtr<CFMutableArrayRef> items;
+
+ size_t size = searchItems.size();
+ if (size) {
+ items.adoptCF(CFArrayCreateMutable(0, size, &kCFTypeArrayCallBacks));
+ for (size_t i = 0; i < size; ++i) {
+ RetainPtr<CFStringRef> item(AdoptCF, searchItems[i].createCFString());
+ CFArrayAppendValue(items.get(), item.get());
+ }
+ }
+
+ CFPreferencesSetAppValue(autosaveKey(name).get(), items.get(), kCFPreferencesCurrentApplication);
+ CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
+}
+
+void SearchPopupMenu::loadRecentSearches(const AtomicString& name, Vector<String>& searchItems)
+{
+ if (name.isEmpty())
+ return;
+
+ searchItems.clear();
+ RetainPtr<CFArrayRef> items(AdoptCF, reinterpret_cast<CFArrayRef>(CFPreferencesCopyAppValue(autosaveKey(name).get(), kCFPreferencesCurrentApplication)));
+
+ if (!items || CFGetTypeID(items.get()) != CFArrayGetTypeID())
+ return;
+
+ size_t size = CFArrayGetCount(items.get());
+ for (size_t i = 0; i < size; ++i) {
+ CFStringRef item = (CFStringRef)CFArrayGetValueAtIndex(items.get(), i);
+ if (CFGetTypeID(item) == CFStringGetTypeID())
+ searchItems.append(item);
+ }
+}
+
+}
diff --git a/WebCore/platform/win/SharedBufferWin.cpp b/WebCore/platform/win/SharedBufferWin.cpp
new file mode 100644
index 0000000..99422f2
--- /dev/null
+++ b/WebCore/platform/win/SharedBufferWin.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 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 "SharedBuffer.h"
+
+namespace WebCore {
+
+PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String& filePath)
+{
+ if (filePath.isEmpty())
+ return 0;
+
+ String nullifiedPath = filePath;
+ FILE* fileDescriptor = 0;
+ if (_wfopen_s(&fileDescriptor, nullifiedPath.charactersWithNullTermination(), TEXT("r+b")) || !fileDescriptor) {
+ LOG_ERROR("Failed to open file %s to create shared buffer", filePath.ascii().data());
+ return 0;
+ }
+
+ RefPtr<SharedBuffer> result;
+
+ // Stat the file to get its size
+ struct _stat64 fileStat;
+ if (_fstat64(_fileno(fileDescriptor), &fileStat))
+ goto exit;
+
+ result = new SharedBuffer();
+ result->m_buffer.resize(fileStat.st_size);
+ if (result->m_buffer.size() != fileStat.st_size) {
+ result = 0;
+ goto exit;
+ }
+
+ if (fread(result->m_buffer.data(), 1, fileStat.st_size, fileDescriptor) != fileStat.st_size)
+ LOG_ERROR("Failed to fully read contents of file %s - errno(%i)", filePath.ascii().data(), errno);
+
+exit:
+ fclose(fileDescriptor);
+ return result.release();
+}
+
+}; // namespace WebCore
diff --git a/WebCore/platform/win/SharedTimerWin.cpp b/WebCore/platform/win/SharedTimerWin.cpp
new file mode 100644
index 0000000..8f00ad8
--- /dev/null
+++ b/WebCore/platform/win/SharedTimerWin.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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 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 "Page.h"
+#include "SystemTime.h"
+#include "Widget.h"
+#include <wtf/Assertions.h>
+
+// Note: wx headers set defines that affect the configuration of windows.h
+// so we must include the wx header first to get unicode versions of functions,
+// etc.
+#if PLATFORM(WX)
+#include <wx/wx.h>
+#endif
+
+#include <windows.h>
+
+// These aren't in winuser.h with the MSVS 2003 Platform SDK,
+// so use default values in that case.
+#ifndef USER_TIMER_MINIMUM
+#define USER_TIMER_MINIMUM 0x0000000A
+#endif
+
+#ifndef USER_TIMER_MAXIMUM
+#define USER_TIMER_MAXIMUM 0x7FFFFFFF
+#endif
+
+#if PLATFORM(WIN)
+#include "PluginView.h"
+#endif
+
+namespace WebCore {
+
+static UINT timerID;
+static void (*sharedTimerFiredFunction)();
+
+static HWND timerWindowHandle = 0;
+static UINT timerFiredMessage = 0;
+const LPCWSTR kTimerWindowClassName = L"TimerWindowClass";
+static bool processingCustomTimerMessage = false;
+const int sharedTimerID = 1000;
+
+LRESULT CALLBACK TimerWindowWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+#if PLATFORM(WIN)
+ // Windows Media Player has a modal message loop that will deliver messages
+ // to us at inappropriate times and we will crash if we handle them when
+ // they are delivered. We repost all messages so that we will get to handle
+ // them once the modal loop exits.
+ if (PluginView::isCallingPlugin()) {
+ PostMessage(hWnd, message, wParam, lParam);
+ return 0;
+ }
+#endif
+
+ if (message == timerFiredMessage) {
+ processingCustomTimerMessage = true;
+ sharedTimerFiredFunction();
+ processingCustomTimerMessage = false;
+ } else if (message == WM_TIMER && wParam == sharedTimerID)
+ sharedTimerFiredFunction();
+ else
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ return 0;
+}
+
+static void initializeOffScreenTimerWindow()
+{
+ if (timerWindowHandle)
+ return;
+
+ WNDCLASSEX wcex;
+ memset(&wcex, 0, sizeof(WNDCLASSEX));
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.lpfnWndProc = TimerWindowWndProc;
+ wcex.hInstance = Page::instanceHandle();
+ wcex.lpszClassName = kTimerWindowClassName;
+ RegisterClassEx(&wcex);
+
+ timerWindowHandle = CreateWindow(kTimerWindowClassName, 0, 0,
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, HWND_MESSAGE, 0, Page::instanceHandle(), 0);
+ timerFiredMessage = RegisterWindowMessage(L"com.apple.WebKit.TimerFired");
+}
+
+void setSharedTimerFiredFunction(void (*f)())
+{
+ sharedTimerFiredFunction = f;
+}
+
+void setSharedTimerFireTime(double fireTime)
+{
+ ASSERT(sharedTimerFiredFunction);
+
+ double interval = fireTime - currentTime();
+ unsigned intervalInMS;
+ if (interval < 0)
+ intervalInMS = 0;
+ else {
+ interval *= 1000;
+ if (interval > USER_TIMER_MAXIMUM)
+ intervalInMS = USER_TIMER_MAXIMUM;
+ else
+ intervalInMS = (unsigned)interval;
+ }
+
+ if (timerID) {
+ KillTimer(0, timerID);
+ timerID = 0;
+ }
+
+ // We don't allow nested PostMessages, since the custom messages will effectively starve
+ // painting and user input. (Win32 has a tri-level queue with application messages >
+ // user input > WM_PAINT/WM_TIMER.)
+ // In addition, if the queue contains input events that have been there since the last call to
+ // GetQueueStatus, PeekMessage or GetMessage we favor timers.
+ initializeOffScreenTimerWindow();
+ if (intervalInMS < USER_TIMER_MINIMUM && !processingCustomTimerMessage &&
+ !LOWORD(::GetQueueStatus(QS_ALLINPUT))) {
+ // Windows SetTimer does not allow timeouts smaller than 10ms (USER_TIMER_MINIMUM)
+ PostMessage(timerWindowHandle, timerFiredMessage, 0, 0);
+ } else
+ timerID = SetTimer(timerWindowHandle, sharedTimerID, intervalInMS, 0);
+}
+
+void stopSharedTimer()
+{
+ if (timerID) {
+ KillTimer(0, timerID);
+ timerID = 0;
+ }
+}
+
+}
diff --git a/WebCore/platform/win/SoftLinking.h b/WebCore/platform/win/SoftLinking.h
new file mode 100644
index 0000000..761cb7a
--- /dev/null
+++ b/WebCore/platform/win/SoftLinking.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2007 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 SoftLinking_h
+#define SoftLinking_h
+
+#include <windows.h>
+#include <wtf/Assertions.h>
+
+#define SOFT_LINK_LIBRARY_HELPER(lib, suffix) \
+ static HMODULE lib##Library() \
+ { \
+ static HMODULE library = LoadLibraryW(L###lib suffix); \
+ ASSERT(library); \
+ return library; \
+ }
+
+#define SOFT_LINK_LIBRARY(lib) SOFT_LINK_LIBRARY_HELPER(lib, L".dll")
+#define SOFT_LINK_DEBUG_LIBRARY(lib) SOFT_LINK_LIBRARY_HELPER(lib, L"_debug.dll")
+
+#define SOFT_LINK(library, functionName, resultType, callingConvention, parameterDeclarations, parameterNames) \
+ static resultType callingConvention init##functionName parameterDeclarations; \
+ static resultType (callingConvention*softLink##functionName) parameterDeclarations = init##functionName; \
+ \
+ static resultType callingConvention init##functionName parameterDeclarations \
+ { \
+ softLink##functionName = (resultType (callingConvention*) parameterDeclarations) GetProcAddress(library##Library(), #functionName); \
+ ASSERT(softLink##functionName); \
+ return softLink##functionName parameterNames; \
+ }\
+ \
+ inline resultType functionName parameterDeclarations \
+ {\
+ return softLink##functionName parameterNames; \
+ }
+
+#endif // SoftLinking_h
diff --git a/WebCore/platform/win/SoundWin.cpp b/WebCore/platform/win/SoundWin.cpp
new file mode 100644
index 0000000..443e7d9
--- /dev/null
+++ b/WebCore/platform/win/SoundWin.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2006, 2007 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 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 "Sound.h"
+
+#include <Windows.h>
+
+namespace WebCore {
+
+void systemBeep() { MessageBeep(static_cast<UINT>(-1)); }
+
+} // namespace WebCore
+
diff --git a/WebCore/platform/win/SystemTimeWin.cpp b/WebCore/platform/win/SystemTimeWin.cpp
new file mode 100644
index 0000000..76f77ae
--- /dev/null
+++ b/WebCore/platform/win/SystemTimeWin.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2006, 2007 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 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 "SystemTime.h"
+
+#include "NotImplemented.h"
+#include <windows.h>
+
+namespace WebCore {
+
+double currentTime()
+{
+ FILETIME ft;
+ GetSystemTimeAsFileTime(&ft);
+
+ // As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a
+ // ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can
+ // prevent alignment faults on 64-bit Windows).
+
+ ULARGE_INTEGER t;
+ memcpy(&t, &ft, sizeof(t));
+
+ // Windows file times are in 100s of nanoseconds.
+ // To convert to seconds, we have to divide by 10,000,000, which is more quickly
+ // done by multiplying by 0.0000001.
+
+ // Between January 1, 1601 and January 1, 1970, there were 369 complete years,
+ // of which 89 were leap years (1700, 1800, and 1900 were not leap years).
+ // That is a total of 134774 days, which is 11644473600 seconds.
+
+ return t.QuadPart * 0.0000001 - 11644473600.0;
+}
+
+float userIdleTime()
+{
+ // Needed for back/forward cache.
+ notImplemented();
+ return 0.0F;
+}
+
+}
diff --git a/WebCore/platform/win/TemporaryLinkStubs.cpp b/WebCore/platform/win/TemporaryLinkStubs.cpp
new file mode 100644
index 0000000..4a8a093
--- /dev/null
+++ b/WebCore/platform/win/TemporaryLinkStubs.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2006, 2007 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 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 "CachedPage.h"
+#include "NotImplemented.h"
+#include "SSLKeyGenerator.h"
+
+namespace WebCore {
+
+// <keygen>
+String signedPublicKeyAndChallengeString(unsigned, const String&, const KURL&) { notImplemented(); return String(); }
+Vector<String> supportedKeySizes() { notImplemented(); return Vector<String>(); }
+
+}
diff --git a/WebCore/platform/win/WCDataObject.cpp b/WebCore/platform/win/WCDataObject.cpp
new file mode 100644
index 0000000..940595d
--- /dev/null
+++ b/WebCore/platform/win/WCDataObject.cpp
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2007 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 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 "WCDataObject.h"
+
+#include "PlatformString.h"
+
+namespace WebCore {
+
+class WCEnumFormatEtc : public IEnumFORMATETC
+{
+public:
+ WCEnumFormatEtc(const Vector<FORMATETC>& formats);
+ WCEnumFormatEtc(const Vector<FORMATETC*>& formats);
+
+ //IUnknown members
+ STDMETHOD(QueryInterface)(REFIID, void**);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+ //IEnumFORMATETC members
+ STDMETHOD(Next)(ULONG, LPFORMATETC, ULONG*);
+ STDMETHOD(Skip)(ULONG);
+ STDMETHOD(Reset)(void);
+ STDMETHOD(Clone)(IEnumFORMATETC**);
+
+private:
+ long m_ref;
+ Vector<FORMATETC> m_formats;
+ size_t m_current;
+};
+
+
+
+WCEnumFormatEtc::WCEnumFormatEtc(const Vector<FORMATETC>& formats)
+: m_ref(1)
+, m_current(0)
+{
+ for(size_t i = 0; i < formats.size(); ++i)
+ m_formats.append(formats[i]);
+}
+
+WCEnumFormatEtc::WCEnumFormatEtc(const Vector<FORMATETC*>& formats)
+: m_ref(1)
+, m_current(0)
+{
+ for(size_t i = 0; i < formats.size(); ++i)
+ m_formats.append(*formats[i]);
+}
+
+STDMETHODIMP WCEnumFormatEtc::QueryInterface(REFIID riid, void** ppvObject)
+{
+ *ppvObject = 0;
+ if (IsEqualIID(riid, IID_IUnknown) ||
+ IsEqualIID(riid, IID_IEnumFORMATETC)) {
+ *ppvObject = this;
+ AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+STDMETHODIMP_(ULONG) WCEnumFormatEtc::AddRef(void)
+{
+ return InterlockedIncrement(&m_ref);
+}
+
+STDMETHODIMP_(ULONG) WCEnumFormatEtc::Release(void)
+{
+ long c = InterlockedDecrement(&m_ref);
+ if (c == 0)
+ delete this;
+ return c;
+}
+
+STDMETHODIMP WCEnumFormatEtc::Next(ULONG celt, LPFORMATETC lpFormatEtc, ULONG* pceltFetched)
+{
+ if(pceltFetched != 0)
+ *pceltFetched=0;
+
+ ULONG cReturn = celt;
+
+ if(celt <= 0 || lpFormatEtc == 0 || m_current >= m_formats.size())
+ return S_FALSE;
+
+ if(pceltFetched == 0 && celt != 1) // pceltFetched can be 0 only for 1 item request
+ return S_FALSE;
+
+ while (m_current < m_formats.size() && cReturn > 0) {
+ *lpFormatEtc++ = m_formats[m_current++];
+ --cReturn;
+ }
+ if (pceltFetched != 0)
+ *pceltFetched = celt - cReturn;
+
+ return (cReturn == 0) ? S_OK : S_FALSE;
+}
+
+STDMETHODIMP WCEnumFormatEtc::Skip(ULONG celt)
+{
+ if((m_current + int(celt)) >= m_formats.size())
+ return S_FALSE;
+ m_current += celt;
+ return S_OK;
+}
+
+STDMETHODIMP WCEnumFormatEtc::Reset(void)
+{
+ m_current = 0;
+ return S_OK;
+}
+
+STDMETHODIMP WCEnumFormatEtc::Clone(IEnumFORMATETC** ppCloneEnumFormatEtc)
+{
+ if(!ppCloneEnumFormatEtc)
+ return E_POINTER;
+
+ WCEnumFormatEtc *newEnum = new WCEnumFormatEtc(m_formats);
+ if(!newEnum)
+ return E_OUTOFMEMORY;
+
+ newEnum->AddRef();
+ newEnum->m_current = m_current;
+ *ppCloneEnumFormatEtc = newEnum;
+ return S_OK;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+
+HRESULT WCDataObject::createInstance(WCDataObject** result)
+{
+ if (!result)
+ return E_POINTER;
+ *result = new WCDataObject();
+ return S_OK;
+}
+
+WCDataObject::WCDataObject()
+: m_ref(1)
+{
+}
+
+WCDataObject::~WCDataObject()
+{
+ for(size_t i = 0; i < m_medium.size(); ++i) {
+ ReleaseStgMedium(m_medium[i]);
+ delete m_medium[i];
+ }
+ WTF::deleteAllValues(m_formats);
+}
+
+STDMETHODIMP WCDataObject::QueryInterface(REFIID riid,void** ppvObject)
+{
+ *ppvObject = 0;
+ if (IID_IUnknown==riid || IID_IDataObject==riid)
+ *ppvObject=this;
+ if (*ppvObject) {
+ AddRef();
+ return S_OK;
+ }
+ return E_NOINTERFACE;
+}
+
+STDMETHODIMP_(ULONG) WCDataObject::AddRef( void)
+{
+ return InterlockedIncrement(&m_ref);
+}
+
+STDMETHODIMP_(ULONG) WCDataObject::Release( void)
+{
+ long c = InterlockedDecrement(&m_ref);
+ if (c == 0)
+ delete this;
+ return c;
+}
+
+STDMETHODIMP WCDataObject::GetData(FORMATETC* pformatetcIn, STGMEDIUM* pmedium)
+{
+ if(!pformatetcIn || !pmedium)
+ return E_POINTER;
+ pmedium->hGlobal = 0;
+
+ for(size_t i=0; i < m_formats.size(); ++i) {
+ if(/*pformatetcIn->tymed & m_formats[i]->tymed &&*/ // tymed can be 0 (TYMED_NULL) - but it can have a medium that contains an pUnkForRelease
+ pformatetcIn->lindex == m_formats[i]->lindex &&
+ pformatetcIn->dwAspect == m_formats[i]->dwAspect &&
+ pformatetcIn->cfFormat == m_formats[i]->cfFormat) {
+ CopyMedium(pmedium, m_medium[i], m_formats[i]);
+ return S_OK;
+ }
+ }
+ return DV_E_FORMATETC;
+}
+
+STDMETHODIMP WCDataObject::GetDataHere(FORMATETC*, STGMEDIUM*)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP WCDataObject::QueryGetData(FORMATETC* pformatetc)
+{
+ if(!pformatetc)
+ return E_POINTER;
+
+ if (!(DVASPECT_CONTENT & pformatetc->dwAspect))
+ return (DV_E_DVASPECT);
+ HRESULT hr = DV_E_TYMED;
+ for(size_t i = 0; i < m_formats.size(); ++i) {
+ if(pformatetc->tymed & m_formats[i]->tymed) {
+ if(pformatetc->cfFormat == m_formats[i]->cfFormat)
+ return S_OK;
+ else
+ hr = DV_E_CLIPFORMAT;
+ }
+ else
+ hr = DV_E_TYMED;
+ }
+ return hr;
+}
+
+STDMETHODIMP WCDataObject::GetCanonicalFormatEtc(FORMATETC*, FORMATETC*)
+{
+ return DATA_S_SAMEFORMATETC;
+}
+
+STDMETHODIMP WCDataObject::SetData(FORMATETC* pformatetc, STGMEDIUM* pmedium, BOOL fRelease)
+{
+ if(!pformatetc || !pmedium)
+ return E_POINTER;
+
+ FORMATETC* fetc=new FORMATETC;
+ if (!fetc)
+ return E_OUTOFMEMORY;
+
+ STGMEDIUM* pStgMed = new STGMEDIUM;
+
+ if(!pStgMed) {
+ delete fetc;
+ return E_OUTOFMEMORY;
+ }
+
+ ZeroMemory(fetc,sizeof(FORMATETC));
+ ZeroMemory(pStgMed,sizeof(STGMEDIUM));
+
+ *fetc = *pformatetc;
+ m_formats.append(fetc);
+
+ if(fRelease)
+ *pStgMed = *pmedium;
+ else
+ CopyMedium(pStgMed, pmedium, pformatetc);
+ m_medium.append(pStgMed);
+
+ return S_OK;
+}
+
+void WCDataObject::CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc)
+{
+ switch(pMedSrc->tymed)
+ {
+ case TYMED_HGLOBAL:
+ pMedDest->hGlobal = (HGLOBAL)OleDuplicateData(pMedSrc->hGlobal,pFmtSrc->cfFormat, 0);
+ break;
+ case TYMED_GDI:
+ pMedDest->hBitmap = (HBITMAP)OleDuplicateData(pMedSrc->hBitmap,pFmtSrc->cfFormat, 0);
+ break;
+ case TYMED_MFPICT:
+ pMedDest->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(pMedSrc->hMetaFilePict,pFmtSrc->cfFormat, 0);
+ break;
+ case TYMED_ENHMF:
+ pMedDest->hEnhMetaFile = (HENHMETAFILE)OleDuplicateData(pMedSrc->hEnhMetaFile,pFmtSrc->cfFormat, 0);
+ break;
+ case TYMED_FILE:
+ pMedSrc->lpszFileName = (LPOLESTR)OleDuplicateData(pMedSrc->lpszFileName,pFmtSrc->cfFormat, 0);
+ break;
+ case TYMED_ISTREAM:
+ pMedDest->pstm = pMedSrc->pstm;
+ pMedSrc->pstm->AddRef();
+ break;
+ case TYMED_ISTORAGE:
+ pMedDest->pstg = pMedSrc->pstg;
+ pMedSrc->pstg->AddRef();
+ break;
+ default:
+ break;
+ }
+ pMedDest->tymed = pMedSrc->tymed;
+ pMedDest->pUnkForRelease = 0;
+ if(pMedSrc->pUnkForRelease != 0) {
+ pMedDest->pUnkForRelease = pMedSrc->pUnkForRelease;
+ pMedSrc->pUnkForRelease->AddRef();
+ }
+}
+STDMETHODIMP WCDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc)
+{
+ if(!ppenumFormatEtc)
+ return E_POINTER;
+
+ *ppenumFormatEtc=0;
+ switch (dwDirection)
+ {
+ case DATADIR_GET:
+ *ppenumFormatEtc= new WCEnumFormatEtc(m_formats);
+ if(!(*ppenumFormatEtc))
+ return E_OUTOFMEMORY;
+ break;
+
+ case DATADIR_SET:
+ default:
+ return E_NOTIMPL;
+ break;
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP WCDataObject::DAdvise(FORMATETC*, DWORD, IAdviseSink*,DWORD*)
+{
+ return OLE_E_ADVISENOTSUPPORTED;
+}
+
+STDMETHODIMP WCDataObject::DUnadvise(DWORD)
+{
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE WCDataObject::EnumDAdvise(IEnumSTATDATA**)
+{
+ return OLE_E_ADVISENOTSUPPORTED;
+}
+
+void WCDataObject::clearData(CLIPFORMAT format)
+{
+ size_t ptr = 0;
+ while (ptr < m_formats.size()) {
+ if (m_formats[ptr]->cfFormat == format) {
+ FORMATETC* current = m_formats[ptr];
+ m_formats[ptr] = m_formats[m_formats.size() - 1];
+ m_formats[m_formats.size() - 1] = 0;
+ m_formats.removeLast();
+ delete current;
+ STGMEDIUM* medium = m_medium[ptr];
+ m_medium[ptr] = m_medium[m_medium.size() - 1];
+ m_medium[m_medium.size() - 1] = 0;
+ m_medium.removeLast();
+ ReleaseStgMedium(medium);
+ delete medium;
+ continue;
+ }
+ ptr++;
+ }
+}
+
+
+}
diff --git a/WebCore/platform/win/WCDataObject.h b/WebCore/platform/win/WCDataObject.h
new file mode 100644
index 0000000..bdfb013
--- /dev/null
+++ b/WebCore/platform/win/WCDataObject.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 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 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 WCDataObject_h
+#define WCDataObject_h
+
+#include <wtf/Vector.h>
+#include <ShlObj.h>
+#include <objidl.h>
+
+namespace WebCore {
+
+class String;
+
+class WCDataObject : public IDataObject {
+public:
+ void CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc);
+
+ //IUnknown
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+ virtual ULONG STDMETHODCALLTYPE AddRef(void);
+ virtual ULONG STDMETHODCALLTYPE Release(void);
+
+ //IDataObject
+ virtual HRESULT STDMETHODCALLTYPE GetData(FORMATETC* pformatIn, STGMEDIUM* pmedium);
+ virtual HRESULT STDMETHODCALLTYPE GetDataHere(FORMATETC* pformat, STGMEDIUM* pmedium);
+ virtual HRESULT STDMETHODCALLTYPE QueryGetData(FORMATETC* pformat);
+ virtual HRESULT STDMETHODCALLTYPE GetCanonicalFormatEtc(FORMATETC* pformatectIn,FORMATETC* pformatOut);
+ virtual HRESULT STDMETHODCALLTYPE SetData(FORMATETC* pformat, STGMEDIUM*pmedium, BOOL release);
+ virtual HRESULT STDMETHODCALLTYPE EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC** ppenumFormatEtc);
+ virtual HRESULT STDMETHODCALLTYPE DAdvise(FORMATETC*, DWORD, IAdviseSink*, DWORD*);
+ virtual HRESULT STDMETHODCALLTYPE DUnadvise(DWORD);
+ virtual HRESULT STDMETHODCALLTYPE EnumDAdvise(IEnumSTATDATA**);
+
+ void clearData(CLIPFORMAT);
+
+ static HRESULT createInstance(WCDataObject**);
+private:
+ WCDataObject();
+ virtual ~WCDataObject();
+ long m_ref;
+ Vector<FORMATETC*> m_formats;
+ Vector<STGMEDIUM*> m_medium;
+};
+
+}
+
+#endif //!WCDataObject_h
diff --git a/WebCore/platform/win/WebCoreHistory.cpp b/WebCore/platform/win/WebCoreHistory.cpp
new file mode 100644
index 0000000..1d3fdf9
--- /dev/null
+++ b/WebCore/platform/win/WebCoreHistory.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2006, 2007 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 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 "WebCoreHistory.h"
+
+namespace WebCore {
+
+static WebCoreHistoryProvider* _historyProvider = 0;
+
+void WebCoreHistory::setHistoryProvider(WebCoreHistoryProvider* h)
+{
+ if (_historyProvider == h)
+ return;
+
+ delete _historyProvider;
+ _historyProvider = h;
+}
+
+WebCoreHistoryProvider* WebCoreHistory::historyProvider()
+{
+ return _historyProvider;
+}
+
+}
diff --git a/WebCore/platform/win/WebCoreHistory.h b/WebCore/platform/win/WebCoreHistory.h
new file mode 100644
index 0000000..9082b85
--- /dev/null
+++ b/WebCore/platform/win/WebCoreHistory.h
@@ -0,0 +1,46 @@
+/*
+* Copyright (C) 2006, 2007 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 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 WEBCORE_HISTORY_H_
+#define WEBCORE_HISTORY_H_
+
+#include <unicode/umachine.h>
+
+namespace WebCore {
+
+class WebCoreHistoryProvider {
+public:
+ virtual bool containsURL(const UChar* unicode, unsigned length) = 0;
+};
+
+class WebCoreHistory {
+public:
+ static void setHistoryProvider(WebCoreHistoryProvider*);
+ static WebCoreHistoryProvider* historyProvider();
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/win/WebCoreTextRenderer.cpp b/WebCore/platform/win/WebCoreTextRenderer.cpp
new file mode 100644
index 0000000..2e48815
--- /dev/null
+++ b/WebCore/platform/win/WebCoreTextRenderer.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2007 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 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 "WebCoreTextRenderer.h"
+
+#include "Font.h"
+#include "FontDescription.h"
+#include "GraphicsContext.h"
+#include "StringTruncator.h"
+#include <wtf/unicode/Unicode.h>
+
+namespace WebCore {
+
+static bool isOneLeftToRightRun(const TextRun& run)
+{
+ for (int i = 0; i < run.length(); i++) {
+ WTF::Unicode::Direction direction = WTF::Unicode::direction(run[i]);
+ if (direction == WTF::Unicode::RightToLeft || direction > WTF::Unicode::OtherNeutral)
+ return false;
+ }
+ return true;
+}
+
+static void doDrawTextAtPoint(GraphicsContext& context, const String& text, const IntPoint& point, const Font& font, const Color& color, int underlinedIndex)
+{
+ TextRun run(text.characters(), text.length());
+
+ context.setFillColor(color);
+ if (isOneLeftToRightRun(run))
+ font.drawText(&context, run, point);
+ else {
+ context.setFont(font);
+ context.drawBidiText(run, point);
+ }
+
+ if (underlinedIndex >= 0) {
+ ASSERT(underlinedIndex < static_cast<int>(text.length()));
+
+ int beforeWidth;
+ if (underlinedIndex > 0) {
+ TextRun beforeRun(text.characters(), underlinedIndex);
+ beforeWidth = font.width(beforeRun);
+ } else
+ beforeWidth = 0;
+
+ TextRun underlinedRun(text.characters() + underlinedIndex, 1);
+ int underlinedWidth = font.width(underlinedRun);
+
+ IntPoint underlinePoint(point);
+ underlinePoint.move(beforeWidth, 1);
+
+ context.setStrokeColor(color);
+ context.drawLineForText(underlinePoint, underlinedWidth, false);
+ }
+}
+
+void WebCoreDrawTextAtPoint(GraphicsContext& context, const String& text, const IntPoint& point, const Font& font, const Color& color, int underlinedIndex)
+{
+ context.save();
+
+ doDrawTextAtPoint(context, text, point, font, color, underlinedIndex);
+
+ context.restore();
+}
+
+void WebCoreDrawDoubledTextAtPoint(GraphicsContext& context, const String& text, const IntPoint& point, const Font& font, const Color& topColor, const Color& bottomColor, int underlinedIndex)
+{
+ context.save();
+
+ IntPoint textPos = point;
+
+ doDrawTextAtPoint(context, text, textPos, font, bottomColor, underlinedIndex);
+ textPos.move(0, -1);
+ doDrawTextAtPoint(context, text, textPos, font, topColor, underlinedIndex);
+
+ context.restore();
+}
+
+float WebCoreTextFloatWidth(const String& text, const Font& font)
+{
+ return StringTruncator::width(text, font, false);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/win/WebCoreTextRenderer.h b/WebCore/platform/win/WebCoreTextRenderer.h
new file mode 100644
index 0000000..59b82dc
--- /dev/null
+++ b/WebCore/platform/win/WebCoreTextRenderer.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2007 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 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.
+ */
+
+namespace WebCore {
+
+ class Color;
+ class Font;
+ class GraphicsContext;
+ class IntPoint;
+ class String;
+
+ void WebCoreDrawTextAtPoint(GraphicsContext&, const String&, const IntPoint&, const Font&, const Color&, int underlinedIndex = -1);
+ void WebCoreDrawDoubledTextAtPoint(GraphicsContext&, const String&, const IntPoint&, const Font&, const Color& topColor, const Color& bottomColor, int underlinedIndex = -1);
+ float WebCoreTextFloatWidth(const String&, const Font&);
+
+} // namespace WebCore
diff --git a/WebCore/platform/win/WheelEventWin.cpp b/WebCore/platform/win/WheelEventWin.cpp
new file mode 100644
index 0000000..4a6132a
--- /dev/null
+++ b/WebCore/platform/win/WheelEventWin.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2006, 2007 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 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 "PlatformWheelEvent.h"
+
+#include <windows.h>
+#include <windowsx.h>
+
+namespace WebCore {
+
+#define HIGH_BIT_MASK_SHORT 0x8000
+
+static IntPoint positionForEvent(HWND hWnd, LPARAM lParam)
+{
+ POINT point = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
+ ScreenToClient(hWnd, &point);
+ return point;
+}
+
+static IntPoint globalPositionForEvent(HWND hWnd, LPARAM lParam)
+{
+ POINT point = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
+ return point;
+}
+
+PlatformWheelEvent::PlatformWheelEvent(HWND hWnd, WPARAM wParam, LPARAM lParam, bool isHorizontal)
+ : m_position(positionForEvent(hWnd, lParam))
+ , m_globalPosition(globalPositionForEvent(hWnd, lParam))
+ , m_isAccepted(false)
+ , m_shiftKey(wParam & MK_SHIFT)
+ , m_ctrlKey(wParam & MK_CONTROL)
+ , m_altKey(GetKeyState(VK_MENU) & HIGH_BIT_MASK_SHORT)
+ , m_metaKey(m_altKey) // FIXME: We'll have to test other browsers
+ , m_isContinuous(false)
+{
+ float delta = short(HIWORD(wParam)) / (float)WHEEL_DELTA;
+ if (isHorizontal) {
+ // Windows sends a positive delta for scrolling right, while AppKit
+ // sends a negative delta. EventHandler expects the AppKit values,
+ // so we have to negate our horizontal delta to match.
+ m_deltaX = -delta;
+ m_deltaY = 0;
+ } else {
+ m_deltaX = 0;
+ m_deltaY = delta;
+ }
+}
+
+}
diff --git a/WebCore/platform/win/WidgetWin.cpp b/WebCore/platform/win/WidgetWin.cpp
new file mode 100644
index 0000000..fc0adba
--- /dev/null
+++ b/WebCore/platform/win/WidgetWin.cpp
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2006, 2007 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 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 "Document.h"
+#include "Element.h"
+#include "GraphicsContext.h"
+#include "FrameWin.h"
+#include "IntRect.h"
+#include "FrameView.h"
+#include "WidgetClient.h"
+#include <winsock2.h>
+#include <windows.h>
+
+namespace WebCore {
+
+class WidgetPrivate
+{
+public:
+ WidgetClient* client;
+ ScrollView* parent;
+ HWND containingWindow;
+ IntRect frameRect;
+ bool enabled;
+ Widget* capturingChild;
+ bool suppressInvalidation;
+};
+
+Widget::Widget()
+ : data(new WidgetPrivate)
+{
+ data->client = 0;
+ data->parent = 0;
+ data->containingWindow = 0;
+ data->enabled = true;
+ data->capturingChild = 0;
+ data->suppressInvalidation = false;
+}
+
+Widget::~Widget()
+{
+ ASSERT(!parent());
+ delete data;
+}
+
+void Widget::setContainingWindow(HWND containingWindow)
+{
+ data->containingWindow = containingWindow;
+}
+
+HWND Widget::containingWindow() const
+{
+ return data->containingWindow;
+}
+
+void Widget::setClient(WidgetClient* c)
+{
+ data->client = c;
+}
+
+WidgetClient* Widget::client() const
+{
+ return data->client;
+}
+
+IntRect Widget::frameGeometry() const
+{
+ return data->frameRect;
+}
+
+void Widget::setFrameGeometry(const IntRect &rect)
+{
+ data->frameRect = rect;
+}
+
+void Widget::setParent(ScrollView* v)
+{
+ if (!v || !v->isAttachedToWindow())
+ detachFromWindow();
+ data->parent = v;
+ if (v && v->isAttachedToWindow())
+ attachToWindow();
+}
+
+ScrollView* Widget::parent() const
+{
+ return data->parent;
+}
+
+void Widget::removeFromParent()
+{
+ if (parent())
+ parent()->removeChild(this);
+}
+
+void Widget::show()
+{
+}
+
+void Widget::hide()
+{
+}
+
+HCURSOR lastSetCursor = 0;
+bool ignoreNextSetCursor = false;
+
+void Widget::setCursor(const Cursor& cursor)
+{
+ // This is set by PluginViewWin so it can ignore set setCursor call made by
+ // EventHandler.cpp.
+ if (ignoreNextSetCursor) {
+ ignoreNextSetCursor = false;
+ return;
+ }
+
+ if (HCURSOR c = cursor.impl()->nativeCursor()) {
+ lastSetCursor = c;
+ SetCursor(c);
+ }
+}
+
+IntPoint Widget::convertToContainingWindow(const IntPoint& point) const
+{
+ IntPoint windowPoint = point;
+ for (const Widget *parentWidget = parent(), *childWidget = this;
+ parentWidget;
+ childWidget = parentWidget, parentWidget = parentWidget->parent())
+ windowPoint = parentWidget->convertChildToSelf(childWidget, windowPoint);
+ return windowPoint;
+}
+
+IntPoint Widget::convertFromContainingWindow(const IntPoint& point) const
+{
+ IntPoint widgetPoint = point;
+ for (const Widget *parentWidget = parent(), *childWidget = this;
+ parentWidget;
+ childWidget = parentWidget, parentWidget = parentWidget->parent())
+ widgetPoint = parentWidget->convertSelfToChild(childWidget, widgetPoint);
+ return widgetPoint;
+}
+
+IntRect Widget::convertToContainingWindow(const IntRect& rect) const
+{
+ IntRect convertedRect = rect;
+ convertedRect.setLocation(convertToContainingWindow(convertedRect.location()));
+ return convertedRect;
+}
+
+IntPoint Widget::convertChildToSelf(const Widget* child, const IntPoint& point) const
+{
+ return IntPoint(point.x() + child->x(), point.y() + child->y());
+}
+
+IntPoint Widget::convertSelfToChild(const Widget* child, const IntPoint& point) const
+{
+ return IntPoint(point.x() - child->x(), point.y() - child->y());
+}
+
+void Widget::paint(GraphicsContext*, const IntRect&)
+{
+}
+
+bool Widget::isEnabled() const
+{
+ return data->enabled;
+}
+
+void Widget::setEnabled(bool e)
+{
+ if (e != data->enabled) {
+ data->enabled = e;
+ invalidate();
+ }
+}
+
+bool Widget::suppressInvalidation() const
+{
+ return data->suppressInvalidation;
+}
+
+void Widget::setSuppressInvalidation(bool suppress)
+{
+ data->suppressInvalidation = suppress;
+}
+
+void Widget::invalidate()
+{
+ invalidateRect(IntRect(0, 0, width(), height()));
+}
+
+void Widget::invalidateRect(const IntRect& r)
+{
+ if (data->suppressInvalidation)
+ return;
+
+ if (!parent()) {
+ RECT rect = r;
+ ::InvalidateRect(containingWindow(), &rect, false);
+ if (isFrameView())
+ static_cast<FrameView*>(this)->addToDirtyRegion(r);
+ return;
+ }
+
+ // Get the root widget.
+ ScrollView* outermostView = parent();
+ while (outermostView && outermostView->parent())
+ outermostView = outermostView->parent();
+ if (!outermostView)
+ return;
+
+ IntRect windowRect = convertToContainingWindow(r);
+
+ // Get our clip rect and intersect with it to ensure we don't invalidate too much.
+ IntRect clipRect = windowClipRect();
+ windowRect.intersect(clipRect);
+
+ RECT rect = windowRect;
+ ::InvalidateRect(containingWindow(), &rect, false);
+ outermostView->addToDirtyRegion(windowRect);
+}
+
+void Widget::setFocus()
+{
+}
+
+void Widget::setIsSelected(bool)
+{
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/win/WindowMessageBroadcaster.cpp b/WebCore/platform/win/WindowMessageBroadcaster.cpp
new file mode 100644
index 0000000..2c2ef79
--- /dev/null
+++ b/WebCore/platform/win/WindowMessageBroadcaster.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2007 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 "WindowMessageBroadcaster.h"
+
+#include "WindowMessageListener.h"
+
+namespace WebCore {
+
+typedef HashMap<HWND, WindowMessageBroadcaster*> InstanceMap;
+
+static InstanceMap& instancesMap()
+{
+ static InstanceMap instances;
+ return instances;
+}
+
+void WindowMessageBroadcaster::addListener(HWND hwnd, WindowMessageListener* listener)
+{
+ WindowMessageBroadcaster* broadcaster = instancesMap().get(hwnd);
+ if (!broadcaster) {
+ broadcaster = new WindowMessageBroadcaster(hwnd);
+ instancesMap().add(hwnd, broadcaster);
+ }
+
+ broadcaster->addListener(listener);
+}
+
+void WindowMessageBroadcaster::removeListener(HWND hwnd, WindowMessageListener* listener)
+{
+ WindowMessageBroadcaster* broadcaster = instancesMap().get(hwnd);
+ if (!broadcaster)
+ return;
+
+ broadcaster->removeListener(listener);
+}
+
+WindowMessageBroadcaster::WindowMessageBroadcaster(HWND hwnd)
+ : m_subclassedWindow(hwnd)
+ , m_originalWndProc(0)
+{
+ ASSERT_ARG(hwnd, IsWindow(hwnd));
+}
+
+WindowMessageBroadcaster::~WindowMessageBroadcaster()
+{
+}
+
+void WindowMessageBroadcaster::addListener(WindowMessageListener* listener)
+{
+ if (!m_originalWndProc) {
+#pragma warning(disable: 4244 4312)
+ m_originalWndProc = reinterpret_cast<WNDPROC>(SetWindowLongPtr(m_subclassedWindow, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(SubclassedWndProc)));
+ ASSERT(m_originalWndProc);
+ }
+
+ m_listeners.add(listener);
+}
+
+void WindowMessageBroadcaster::removeListener(WindowMessageListener* listener)
+{
+ ListenerSet::iterator found = m_listeners.find(listener);
+ if (found == m_listeners.end())
+ return;
+
+ m_listeners.remove(found);
+
+ if (m_listeners.isEmpty())
+ destroy();
+}
+
+void WindowMessageBroadcaster::destroy()
+{
+ m_listeners.clear();
+ unsubclassWindow();
+ instancesMap().remove(m_subclassedWindow);
+ delete this;
+}
+
+void WindowMessageBroadcaster::unsubclassWindow()
+{
+ ASSERT(m_originalWndProc);
+
+ SetWindowLongPtr(m_subclassedWindow, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(m_originalWndProc));
+ m_originalWndProc = 0;
+}
+
+LRESULT CALLBACK WindowMessageBroadcaster::SubclassedWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ WindowMessageBroadcaster* broadcaster = instancesMap().get(hwnd);
+ ASSERT(broadcaster);
+
+ ListenerSet::const_iterator end = broadcaster->listeners().end();
+ for (ListenerSet::const_iterator it = broadcaster->listeners().begin(); it != end; ++it)
+ (*it)->windowReceivedMessage(hwnd, message, wParam, lParam);
+
+ WNDPROC originalWndProc = broadcaster->originalWndProc();
+
+ // This will delete broadcaster.
+ if (message == WM_DESTROY)
+ broadcaster->destroy();
+
+ return CallWindowProc(originalWndProc, hwnd, message, wParam, lParam);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/win/WindowMessageBroadcaster.h b/WebCore/platform/win/WindowMessageBroadcaster.h
new file mode 100644
index 0000000..734f4b1
--- /dev/null
+++ b/WebCore/platform/win/WindowMessageBroadcaster.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2007 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 WindowMessageBroadcaster_h
+#define WindowMessageBroadcaster_h
+
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+ class WindowMessageListener;
+
+ class WindowMessageBroadcaster : Noncopyable {
+ public:
+ static void addListener(HWND, WindowMessageListener*);
+ static void removeListener(HWND, WindowMessageListener*);
+
+ private:
+ typedef HashSet<WindowMessageListener*> ListenerSet;
+
+ static LRESULT CALLBACK SubclassedWndProc(HWND, UINT, WPARAM, LPARAM);
+
+ WindowMessageBroadcaster(HWND);
+ ~WindowMessageBroadcaster();
+
+ void addListener(WindowMessageListener*);
+ void removeListener(WindowMessageListener*);
+ const ListenerSet& listeners() const { return m_listeners; }
+
+ void destroy();
+ void unsubclassWindow();
+
+ WNDPROC originalWndProc() const { return m_originalWndProc; }
+
+ HWND m_subclassedWindow;
+ WNDPROC m_originalWndProc;
+ ListenerSet m_listeners;
+ };
+
+} // namespace WebCore
+
+#endif // WindowMessageBroadcaster_h
diff --git a/WebCore/platform/win/WindowMessageListener.h b/WebCore/platform/win/WindowMessageListener.h
new file mode 100644
index 0000000..b99cb35
--- /dev/null
+++ b/WebCore/platform/win/WindowMessageListener.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2007 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 WindowMessageListener_h
+#define WindowMessageListener_h
+
+typedef struct HWND__* HWND;
+typedef long LPARAM;
+typedef unsigned UINT;
+typedef unsigned WPARAM;
+
+namespace WebCore {
+
+ class WindowMessageListener {
+ public:
+ virtual void windowReceivedMessage(HWND, UINT message, WPARAM, LPARAM) = 0;
+ };
+
+} // namespace WebCore
+
+#endif // WindowMessageListener_h