diff options
author | Upstream <upstream-import@none> | 1970-01-12 13:46:40 +0000 |
---|---|---|
committer | Upstream <upstream-import@none> | 1970-01-12 13:46:40 +0000 |
commit | d8543bb6618c17b12da906afa77d216f58cf4058 (patch) | |
tree | c58dc05ed86825bd0ef8d305d58c8205106b540f /WebCore/platform/win | |
download | external_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.zip external_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.tar.gz external_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.tar.bz2 |
external/webkit r30707
Diffstat (limited to 'WebCore/platform/win')
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 |