diff options
Diffstat (limited to 'WebCore/platform')
411 files changed, 18982 insertions, 3921 deletions
diff --git a/WebCore/platform/ContextMenu.cpp b/WebCore/platform/ContextMenu.cpp index cca11b5..ee6aa4e 100644 --- a/WebCore/platform/ContextMenu.cpp +++ b/WebCore/platform/ContextMenu.cpp @@ -27,6 +27,8 @@ #include "config.h" #include "ContextMenu.h" +#if ENABLE(CONTEXT_MENUS) + #include "ContextMenuController.h" #include "ContextMenuClient.h" #include "CSSComputedStyleDeclaration.h" @@ -359,10 +361,10 @@ void ContextMenu::populate() appendItem(StopItem); appendItem(ReloadItem); #else - if (loader->canGoBackOrForward(-1)) + if (frame->page() && frame->page()->canGoBackOrForward(-1)) appendItem(BackItem); - if (loader->canGoBackOrForward(1)) + if (frame->page() && frame->page()->canGoBackOrForward(1)) appendItem(ForwardItem); // use isLoadingInAPISense rather than isLoading because Stop/Reload are @@ -514,6 +516,7 @@ void ContextMenu::populate() } } +#if ENABLE(INSPECTOR) void ContextMenu::addInspectElementItem() { Node* node = m_hitTestResult.innerNonSharedNode(); @@ -535,6 +538,7 @@ void ContextMenu::addInspectElementItem() appendItem(*separatorItem()); appendItem(InspectElementItem); } +#endif // ENABLE(INSPECTOR) void ContextMenu::checkOrEnableIfNeeded(ContextMenuItem& item) const { @@ -717,10 +721,10 @@ void ContextMenu::checkOrEnableIfNeeded(ContextMenuItem& item) const #endif #if PLATFORM(GTK) case ContextMenuItemTagGoBack: - shouldEnable = frame->loader()->canGoBackOrForward(-1); + shouldEnable = frame->page() && frame->page()->canGoBackOrForward(-1); break; case ContextMenuItemTagGoForward: - shouldEnable = frame->loader()->canGoBackOrForward(1); + shouldEnable = frame->page() && frame->page()->canGoBackOrForward(1); break; case ContextMenuItemTagStop: shouldEnable = frame->loader()->documentLoader()->isLoadingInAPISense(); @@ -772,7 +776,9 @@ void ContextMenu::checkOrEnableIfNeeded(ContextMenuItem& item) const case ContextMenuItemTagTextDirectionMenu: case ContextMenuItemTagPDFSinglePageScrolling: case ContextMenuItemTagPDFFacingPagesScrolling: +#if ENABLE(INSPECTOR) case ContextMenuItemTagInspectElement: +#endif case ContextMenuItemBaseApplicationTag: break; } @@ -781,4 +787,6 @@ void ContextMenu::checkOrEnableIfNeeded(ContextMenuItem& item) const item.setEnabled(shouldEnable); } -} +} // namespace WebCore + +#endif // ENABLE(CONTEXT_MENUS) diff --git a/WebCore/platform/ContextMenuItem.h b/WebCore/platform/ContextMenuItem.h index 3a4cdfa..6b9d0a9 100644 --- a/WebCore/platform/ContextMenuItem.h +++ b/WebCore/platform/ContextMenuItem.h @@ -46,6 +46,8 @@ typedef struct _GtkMenuItem GtkMenuItem; #include <QAction> #elif PLATFORM(WX) class wxMenuItem; +#elif PLATFORM(HAIKU) +class BMenuItem; #endif namespace WebCore { @@ -119,7 +121,9 @@ namespace WebCore { ContextMenuItemTagRightToLeft, ContextMenuItemTagPDFSinglePageScrolling, ContextMenuItemTagPDFFacingPagesScrolling, +#if ENABLE(INSPECTOR) ContextMenuItemTagInspectElement, +#endif ContextMenuItemTagTextDirectionMenu, // Text Direction sub-menu ContextMenuItemTagTextDirectionDefault, ContextMenuItemTagTextDirectionLeftToRight, @@ -204,6 +208,8 @@ namespace WebCore { bool checked; bool enabled; }; +#elif PLATFORM(HAIKU) + typedef BMenuItem* PlatformMenuItemDescription; #else typedef void* PlatformMenuItemDescription; #endif diff --git a/WebCore/platform/Cookie.h b/WebCore/platform/Cookie.h new file mode 100644 index 0000000..0fe3851 --- /dev/null +++ b/WebCore/platform/Cookie.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2009 Joseph Pecoraro. 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 Cookie_h +#define Cookie_h + +#include "PlatformString.h" +#include "StringHash.h" + +namespace WebCore { + + // This struct is currently only used to provide more cookies information + // to the Web Inspector. + + struct Cookie { + Cookie(const String& name, const String& value, const String& domain, + const String& path, double expires, bool httpOnly, bool secure, + bool session) + : name(name) + , value(value) + , domain(domain) + , path(path) + , expires(expires) + , httpOnly(httpOnly) + , secure(secure) + , session(session) + { + } + + String name; + String value; + String domain; + String path; + double expires; + bool httpOnly; + bool secure; + bool session; + }; + + struct CookieHash { + static unsigned hash(Cookie key) + { + return StringHash::hash(key.name) + StringHash::hash(key.domain) + StringHash::hash(key.path) + key.secure; + } + + static bool equal(Cookie a, Cookie b) + { + return a.name == b.name && a.domain == b.domain && a.path == b.path && a.secure == b.secure; + } + }; +} + +namespace WTF { + template<typename T> struct DefaultHash; + template<> struct DefaultHash<WebCore::Cookie> { + typedef WebCore::CookieHash Hash; + }; +} + +#endif diff --git a/WebCore/platform/CookieJar.h b/WebCore/platform/CookieJar.h index 6159386..987543e 100644 --- a/WebCore/platform/CookieJar.h +++ b/WebCore/platform/CookieJar.h @@ -26,15 +26,21 @@ #ifndef CookieJar_h #define CookieJar_h +#include <wtf/Vector.h> + namespace WebCore { + class Document; class KURL; class String; - class Document; + + struct Cookie; String cookies(const Document*, const KURL&); void setCookies(Document*, const KURL&, const String&); bool cookiesEnabled(const Document*); + bool getRawCookies(const Document*, const KURL&, Vector<Cookie>&); + void deleteCookie(const Document*, const KURL&, const String&); } diff --git a/WebCore/platform/CrossThreadCopier.cpp b/WebCore/platform/CrossThreadCopier.cpp index 9ca626f..d02da6c 100644 --- a/WebCore/platform/CrossThreadCopier.cpp +++ b/WebCore/platform/CrossThreadCopier.cpp @@ -41,7 +41,7 @@ namespace WebCore { CrossThreadCopierBase<false, String>::Type CrossThreadCopierBase<false, String>::copy(const String& str) { - return str.copy(); + return str.crossThreadString(); } CrossThreadCopierBase<false, ResourceError>::Type CrossThreadCopierBase<false, ResourceError>::copy(const ResourceError& error) diff --git a/WebCore/platform/CrossThreadCopier.h b/WebCore/platform/CrossThreadCopier.h index d12d72d..178e056 100644 --- a/WebCore/platform/CrossThreadCopier.h +++ b/WebCore/platform/CrossThreadCopier.h @@ -46,6 +46,7 @@ namespace WebCore { class String; struct CrossThreadResourceResponseData; struct CrossThreadResourceRequestData; + struct ThreadableLoaderOptions; template<typename T> struct CrossThreadCopierPassThrough { typedef T Type; @@ -65,6 +66,9 @@ namespace WebCore { template<typename T> struct CrossThreadCopierBase<false, T*> : public CrossThreadCopierPassThrough<T*> { }; + template<> struct CrossThreadCopierBase<false, ThreadableLoaderOptions> : public CrossThreadCopierPassThrough<ThreadableLoaderOptions> { + }; + // Custom copy methods. template<typename T> struct CrossThreadCopierBase<false, RefPtr<ThreadSafeShared<T> > > { typedef PassRefPtr<T> Type; diff --git a/WebCore/platform/Cursor.h b/WebCore/platform/Cursor.h index ea75191..2d041d2 100644 --- a/WebCore/platform/Cursor.h +++ b/WebCore/platform/Cursor.h @@ -40,6 +40,8 @@ typedef struct _GdkCursor GdkCursor; #include <QCursor> #elif PLATFORM(CHROMIUM) #include "PlatformCursor.h" +#elif PLATFORM(HAIKU) +#include <app/Cursor.h> #endif #if PLATFORM(MAC) @@ -86,6 +88,9 @@ namespace WebCore { #elif PLATFORM(CHROMIUM) // See PlatformCursor.h typedef void* PlatformCursorHandle; +#elif PLATFORM(HAIKU) + typedef BCursor* PlatformCursor; + typedef BCursor* PlatformCursorHandle; #else typedef void* PlatformCursor; typedef void* PlatformCursorHandle; diff --git a/WebCore/platform/DragData.cpp b/WebCore/platform/DragData.cpp index bf2275a..4518909 100644 --- a/WebCore/platform/DragData.cpp +++ b/WebCore/platform/DragData.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "DragData.h" +#if ENABLE(DRAG_SUPPORT) namespace WebCore { #if !PLATFORM(MAC) @@ -39,4 +40,6 @@ DragData::DragData(DragDataRef data, const IntPoint& clientPosition, const IntPo } #endif -} +} // namespace WebCore + +#endif // ENABLE(DRAG_SUPPORT) diff --git a/WebCore/platform/DragData.h b/WebCore/platform/DragData.h index a1555e3..116ffdd 100644 --- a/WebCore/platform/DragData.h +++ b/WebCore/platform/DragData.h @@ -58,6 +58,9 @@ typedef void* DragDataRef; typedef void* DragDataRef; #elif PLATFORM(CHROMIUM) #include "DragDataRef.h" +#elif PLATFORM(HAIKU) +class BMessage; +typedef class BMessage* DragDataRef; #endif diff --git a/WebCore/platform/DragImage.cpp b/WebCore/platform/DragImage.cpp index adf9a57..aff4aba 100644 --- a/WebCore/platform/DragImage.cpp +++ b/WebCore/platform/DragImage.cpp @@ -25,6 +25,8 @@ #include "config.h" #include "DragImage.h" + +#if ENABLE(DRAG_SUPPORT) #include "DragController.h" #include "Frame.h" @@ -71,4 +73,6 @@ DragImageRef createDragImageForSelection(Frame* frame) return image; } -} +} // namespace WebCore + +#endif // ENABLE(DRAG_SUPPORT) diff --git a/WebCore/platform/DragImage.h b/WebCore/platform/DragImage.h index 4887066..00bd7ed 100644 --- a/WebCore/platform/DragImage.h +++ b/WebCore/platform/DragImage.h @@ -48,6 +48,8 @@ class wxDragImage; #include "DragImageRef.h" #elif PLATFORM(GTK) typedef struct _GdkPixbuf GdkPixbuf; +#elif PLATFORM(HAIKU) +class BBitmap; #endif //We need to #define YOffset as it needs to be shared with WebKit @@ -72,8 +74,13 @@ namespace WebCore { typedef wxDragImage* DragImageRef; #elif PLATFORM(GTK) typedef GdkPixbuf* DragImageRef; +<<<<<<< HEAD:WebCore/platform/DragImage.h #elif PLATFORM(ANDROID) typedef void* DragImageRef; +======= +#elif PLATFORM(HAIKU) + typedef BBitmap* DragImageRef; +>>>>>>> webkit.org at 49305:WebCore/platform/DragImage.h #endif IntSize dragImageSize(DragImageRef); diff --git a/WebCore/platform/FileSystem.h b/WebCore/platform/FileSystem.h index e23b6da..958eb73 100644 --- a/WebCore/platform/FileSystem.h +++ b/WebCore/platform/FileSystem.h @@ -170,6 +170,10 @@ char* filenameFromString(const String&); String filenameForDisplay(const String&); #endif +#if PLATFORM(CHROMIUM) +String pathGetDisplayFileName(const String&); +#endif + } // namespace WebCore #endif // FileSystem_h diff --git a/WebCore/platform/HostWindow.h b/WebCore/platform/HostWindow.h index 3a024de..80f6bdc 100644 --- a/WebCore/platform/HostWindow.h +++ b/WebCore/platform/HostWindow.h @@ -48,12 +48,15 @@ public: virtual IntPoint screenToWindow(const IntPoint&) const = 0; virtual IntRect windowToScreen(const IntRect&) const = 0; - // Method for retrieving the native window. - virtual PlatformWidget platformWindow() const = 0; + // Method for retrieving the native client of the page. + virtual PlatformPageClient platformPageClient() const = 0; // For scrolling a rect into view recursively. Useful in the cases where a WebView is embedded inside some containing // platform-specific ScrollView. virtual void scrollRectIntoView(const IntRect&, const ScrollView*) const = 0; + + // To notify WebKit of scrollbar mode changes. + virtual void scrollbarsModeDidChange() const = 0; }; } // namespace WebCore diff --git a/WebCore/platform/KURL.cpp b/WebCore/platform/KURL.cpp index ec8c55c..ffacc19 100644 --- a/WebCore/platform/KURL.cpp +++ b/WebCore/platform/KURL.cpp @@ -302,13 +302,13 @@ void KURL::invalidate() m_fragmentEnd = 0; } -KURL::KURL(const char* url) +KURL::KURL(ParsedURLStringTag, const char* url) { parse(url, 0); ASSERT(url == m_string); } -KURL::KURL(const String& url) +KURL::KURL(ParsedURLStringTag, const String& url) { parse(url); ASSERT(url == m_string); @@ -529,7 +529,7 @@ void KURL::init(const KURL& base, const String& relative, const TextEncoding& en KURL KURL::copy() const { KURL result = *this; - result.m_string = result.m_string.copy(); + result.m_string = result.m_string.crossThreadString(); return result; } @@ -1641,7 +1641,7 @@ String mimeTypeFromDataURL(const String& url) const KURL& blankURL() { - DEFINE_STATIC_LOCAL(KURL, staticBlankURL, ("about:blank")); + DEFINE_STATIC_LOCAL(KURL, staticBlankURL, (ParsedURLString, "about:blank")); return staticBlankURL; } diff --git a/WebCore/platform/KURL.h b/WebCore/platform/KURL.h index 0809f7e..73fadd1 100644 --- a/WebCore/platform/KURL.h +++ b/WebCore/platform/KURL.h @@ -55,15 +55,18 @@ namespace WebCore { class TextEncoding; struct KURLHash; +enum ParsedURLStringTag { ParsedURLString }; + class KURL { public: // Generates a URL which contains a null string. KURL() { invalidate(); } - // The argument is an absolute URL string. The string is assumed to be - // an already encoded (ASCII-only) valid absolute URL. - explicit KURL(const char*); - explicit KURL(const String&); + // The argument is an absolute URL string. The string is assumed to be output of KURL::string() called on a valid + // KURL object, or indiscernible from such. + // It is usually best to avoid repeatedly parsing a string, unless memory saving outweigh the possible slow-downs. + KURL(ParsedURLStringTag, const char*); + KURL(ParsedURLStringTag, const String&); // Resolves the relative URL with the given base URL. If provided, the // TextEncoding is used to encode non-ASCII characers. The base URL can be diff --git a/WebCore/platform/KURLGoogle.cpp b/WebCore/platform/KURLGoogle.cpp index 1cb08c1..b323332 100644 --- a/WebCore/platform/KURLGoogle.cpp +++ b/WebCore/platform/KURLGoogle.cpp @@ -331,7 +331,7 @@ const String& KURLGooglePrivate::string() const // Creates with NULL-terminated string input representing an absolute URL. // WebCore generally calls this only with hardcoded strings, so the input is // ASCII. We treat is as UTF-8 just in case. -KURL::KURL(const char *url) +KURL::KURL(ParsedURLStringTag, const char *url) { // FIXME The Mac code checks for beginning with a slash and converting to a // file: URL. We will want to add this as well once we can compile on a @@ -349,7 +349,7 @@ KURL::KURL(const char *url) // to a string and then converted back. In this case, the URL is already // canonical and in proper escaped form so needs no encoding. We treat it was // UTF-8 just in case. -KURL::KURL(const String& url) +KURL::KURL(ParsedURLStringTag, const String& url) { if (!url.isNull()) m_url.init(KURL(), url, 0); @@ -728,13 +728,8 @@ String decodeURLEscapeSequences(const String& str) // cause security holes. We never call this function for components, and // just return the ASCII versions instead. // -// However, this static function is called directly in some cases. It appears -// that this only happens for javascript: URLs, so this is essentially the -// JavaScript URL decoder. It assumes UTF-8 encoding. -// -// IE doesn't unescape %00, forcing you to use \x00 in JS strings, so we do -// the same. This also eliminates NULL-related problems should a consumer -// incorrectly call this function for non-JavaScript. +// This function is also used to decode javascript: URLs and as a general +// purpose unescaping function. // // FIXME These should be merged to the KURL.cpp implementation. String decodeURLEscapeSequences(const String& str, const TextEncoding& encoding) @@ -757,15 +752,9 @@ String decodeURLEscapeSequences(const String& str, const TextEncoding& encoding) for (int i = 0; i < inputLength; i++) { if (input[i] == '%') { unsigned char ch; - if (url_canon::DecodeEscaped(input, &i, inputLength, &ch)) { - if (!ch) { - // Never unescape NULLs. - unescaped.push_back('%'); - unescaped.push_back('0'); - unescaped.push_back('0'); - } else - unescaped.push_back(ch); - } else { + if (url_canon::DecodeEscaped(input, &i, inputLength, &ch)) + unescaped.push_back(ch); + else { // Invalid escape sequence, copy the percent literal. unescaped.push_back('%'); } @@ -936,7 +925,7 @@ unsigned KURL::pathAfterLastSlash() const const KURL& blankURL() { - static KURL staticBlankURL("about:blank"); + static KURL staticBlankURL(ParsedURLString, "about:blank"); return staticBlankURL; } diff --git a/WebCore/platform/KURLHash.h b/WebCore/platform/KURLHash.h index 4deb078..7448a49 100644 --- a/WebCore/platform/KURLHash.h +++ b/WebCore/platform/KURLHash.h @@ -52,7 +52,7 @@ namespace WTF { template<> struct HashTraits<WebCore::KURL> : GenericHashTraits<WebCore::KURL> { static const bool emptyValueIsZero = true; - static void constructDeletedValue(WebCore::KURL& slot) { new (&slot) WebCore::KURL(WebCore::String(HashTableDeletedValue)); } + static void constructDeletedValue(WebCore::KURL& slot) { new (&slot) WebCore::KURL(WebCore::ParsedURLString, WebCore::String(HashTableDeletedValue)); } static bool isDeletedValue(const WebCore::KURL& slot) { return slot.string().isHashTableDeletedValue(); } }; diff --git a/WebCore/platform/LocalizedStrings.h b/WebCore/platform/LocalizedStrings.h index 7c586d3..0fa9f71 100644 --- a/WebCore/platform/LocalizedStrings.h +++ b/WebCore/platform/LocalizedStrings.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2003, 2006, 2009 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 @@ -38,6 +38,7 @@ namespace WebCore { String fileButtonChooseFileLabel(); String fileButtonNoFileSelectedLabel(); String copyImageUnknownFileLabel(); +#if ENABLE(CONTEXT_MENUS) String contextMenuItemTagOpenLinkInNewWindow(); String contextMenuItemTagDownloadLinkToDisk(); String contextMenuItemTagCopyLinkToClipboard(); @@ -103,6 +104,7 @@ namespace WebCore { String contextMenuItemTagChangeBack(const String& replacedString); #endif String contextMenuItemTagInspectElement(); +#endif // ENABLE(CONTEXT_MENUS) String searchMenuNoRecentSearchesText(); String searchMenuRecentSearchesText(); @@ -115,6 +117,7 @@ namespace WebCore { String AXHeadingText(); String AXDefinitionListTermText(); String AXDefinitionListDefinitionText(); + String AXARIAContentGroupText(const String& ariaType); String AXButtonActionVerb(); String AXRadioButtonActionVerb(); @@ -135,6 +138,9 @@ namespace WebCore { String mediaElementLoadingStateText(); String mediaElementLiveBroadcastStateText(); + String localizedMediaControlElementString(const String&); + String localizedMediaControlElementHelpText(const String&); + String localizedMediaTimeDescription(float); } #endif diff --git a/WebCore/platform/MIMETypeRegistry.cpp b/WebCore/platform/MIMETypeRegistry.cpp index 1819e1d..32dd3f6 100644 --- a/WebCore/platform/MIMETypeRegistry.cpp +++ b/WebCore/platform/MIMETypeRegistry.cpp @@ -94,7 +94,7 @@ static void initializeSupportedImageMIMETypes() #elif PLATFORM(QT) QList<QByteArray> formats = QImageReader::supportedImageFormats(); - for (size_t i = 0; i < formats.size(); ++i) { + for (size_t i = 0; i < static_cast<size_t>(formats.size()); ++i) { #if ENABLE(SVG) /* * Qt has support for SVG, but we want to use KSVG2 @@ -173,7 +173,7 @@ static void initializeSupportedImageMIMETypesForEncoding() #endif #elif PLATFORM(QT) QList<QByteArray> formats = QImageWriter::supportedImageFormats(); - for (size_t i = 0; i < formats.size(); ++i) { + for (int i = 0; i < formats.size(); ++i) { String mimeType = MIMETypeRegistry::getMIMETypeForExtension(formats.at(i).constData()); supportedImageMIMETypesForEncoding->add(mimeType); } diff --git a/WebCore/platform/Pasteboard.h b/WebCore/platform/Pasteboard.h index 883364a..188b962 100644 --- a/WebCore/platform/Pasteboard.h +++ b/WebCore/platform/Pasteboard.h @@ -86,6 +86,7 @@ public: static Pasteboard* generalPasteboard(); void writeSelection(Range*, bool canSmartCopyOrDelete, Frame*); + void writePlainText(const String&); void writeURL(const KURL&, const String&, Frame* = 0); void writeImage(Node*, const KURL&, const String& title); #if PLATFORM(MAC) @@ -95,13 +96,14 @@ public: bool canSmartReplace(); PassRefPtr<DocumentFragment> documentFragment(Frame*, PassRefPtr<Range>, bool allowPlainText, bool& chosePlainText); String plainText(Frame* = 0); -#if PLATFORM(QT) +#if PLATFORM(QT) || PLATFORM(CHROMIUM) bool isSelectionMode() const; void setSelectionMode(bool selectionMode); #endif #if PLATFORM(GTK) void setHelper(PasteboardHelper*); + PasteboardHelper* m_helper; #endif private: @@ -117,11 +119,7 @@ private: HWND m_owner; #endif -#if PLATFORM(GTK) - PasteboardHelper* m_helper; -#endif - -#if PLATFORM(QT) +#if PLATFORM(QT) || PLATFORM(CHROMIUM) bool m_selectionMode; #endif diff --git a/WebCore/platform/PlatformKeyboardEvent.h b/WebCore/platform/PlatformKeyboardEvent.h index 1499ac5..b5c2e95 100644 --- a/WebCore/platform/PlatformKeyboardEvent.h +++ b/WebCore/platform/PlatformKeyboardEvent.h @@ -59,6 +59,10 @@ QT_END_NAMESPACE class wxKeyEvent; #endif +#if PLATFORM(HAIKU) +class BMessage; +#endif + namespace WebCore { class PlatformKeyboardEvent { @@ -155,6 +159,10 @@ namespace WebCore { PlatformKeyboardEvent(wxKeyEvent&); #endif +#if PLATFORM(HAIKU) + PlatformKeyboardEvent(BMessage*); +#endif + #if PLATFORM(WIN) || PLATFORM(CHROMIUM) bool isSystemKey() const { return m_isSystemKey; } #endif diff --git a/WebCore/platform/PlatformMenuDescription.h b/WebCore/platform/PlatformMenuDescription.h index ab71710..c986207 100644 --- a/WebCore/platform/PlatformMenuDescription.h +++ b/WebCore/platform/PlatformMenuDescription.h @@ -40,6 +40,8 @@ typedef struct HMENU__* HMENU; typedef struct _GtkMenu GtkMenu; #elif PLATFORM(WX) class wxMenu; +#elif PLATFORM(HAIKU) +class BMenu; #endif namespace WebCore { @@ -58,6 +60,8 @@ namespace WebCore { typedef void* PlatformMenuDescription; #elif PLATFORM(WX) typedef wxMenu* PlatformMenuDescription; +#elif PLATFORM(HAIKU) + typedef BMenu* PlatformMenuDescription; #else typedef void* PlatformMenuDescription; #endif diff --git a/WebCore/platform/PlatformMouseEvent.h b/WebCore/platform/PlatformMouseEvent.h index 2543d40..99acc63 100644 --- a/WebCore/platform/PlatformMouseEvent.h +++ b/WebCore/platform/PlatformMouseEvent.h @@ -36,6 +36,7 @@ typedef struct _GdkEventMotion GdkEventMotion; #if PLATFORM(QT) QT_BEGIN_NAMESPACE class QInputEvent; +class QGraphicsSceneMouseEvent; QT_END_NAMESPACE #endif @@ -50,6 +51,10 @@ typedef long LPARAM; class wxMouseEvent; #endif +#if PLATFORM(HAIKU) +class BMessage; +#endif + namespace WebCore { // These button numbers match the ones used in the DOM API, 0 through 2, except for NoButton which isn't specified. @@ -116,6 +121,7 @@ namespace WebCore { #if PLATFORM(QT) PlatformMouseEvent(QInputEvent*, int clickCount); + PlatformMouseEvent(QGraphicsSceneMouseEvent*, int clickCount); #endif #if PLATFORM(WIN) @@ -128,6 +134,10 @@ namespace WebCore { PlatformMouseEvent(const wxMouseEvent&, const wxPoint& globalPoint, int clickCount); #endif +#if PLATFORM(HAIKU) + PlatformMouseEvent(const BMessage*); +#endif + protected: IntPoint m_position; IntPoint m_globalPosition; diff --git a/WebCore/platform/PlatformWheelEvent.h b/WebCore/platform/PlatformWheelEvent.h index ae8df4e..9a4a0cb 100644 --- a/WebCore/platform/PlatformWheelEvent.h +++ b/WebCore/platform/PlatformWheelEvent.h @@ -35,6 +35,7 @@ typedef struct _GdkEventScroll GdkEventScroll; #if PLATFORM(QT) QT_BEGIN_NAMESPACE class QWheelEvent; +class QGraphicsSceneWheelEvent; QT_END_NAMESPACE #endif @@ -49,6 +50,10 @@ class wxMouseEvent; class wxPoint; #endif +#if PLATFORM(HAIKU) +class BMessage; +#endif + namespace WebCore { class FloatPoint; @@ -88,6 +93,15 @@ namespace WebCore { void accept() { m_isAccepted = true; } void ignore() { m_isAccepted = false; } + void turnVerticalTicksIntoHorizontal() + { + m_deltaX = m_deltaY; + m_deltaY = 0; + + m_wheelTicksX = m_wheelTicksY; + m_wheelTicksY = 0; + } + #if PLATFORM(GTK) PlatformWheelEvent(GdkEventScroll*); #endif @@ -98,6 +112,8 @@ namespace WebCore { #if PLATFORM(QT) PlatformWheelEvent(QWheelEvent*); + PlatformWheelEvent(QGraphicsSceneWheelEvent*); + void applyDelta(int delta, Qt::Orientation); #endif #if PLATFORM(WIN) @@ -109,6 +125,10 @@ namespace WebCore { PlatformWheelEvent(const wxMouseEvent&, const wxPoint&); #endif +#if PLATFORM(HAIKU) + PlatformWheelEvent(BMessage*); +#endif + protected: IntPoint m_position; IntPoint m_globalPosition; diff --git a/WebCore/platform/PopupMenu.h b/WebCore/platform/PopupMenu.h index fc85d60..2315f02 100644 --- a/WebCore/platform/PopupMenu.h +++ b/WebCore/platform/PopupMenu.h @@ -59,6 +59,8 @@ class wxMenu; #include <wx/event.h> #elif PLATFORM(CHROMIUM) #include "PopupMenuPrivate.h" +#elif PLATFORM(HAIKU) +class BMenu; #endif namespace WebCore { @@ -92,6 +94,8 @@ public: #if PLATFORM(WIN) Scrollbar* scrollbar() const { return m_scrollbar.get(); } + static LPCTSTR popupClassName(); + bool up(unsigned lines = 1); bool down(unsigned lines = 1); @@ -153,6 +157,10 @@ private: void calculatePositionAndSize(const IntRect&, FrameView*); void invalidateItem(int index); + static LRESULT CALLBACK PopupMenuWndProc(HWND, UINT, WPARAM, LPARAM); + LRESULT wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + static void registerClass(); + RefPtr<Scrollbar> m_scrollbar; HWND m_popup; HDC m_DC; @@ -164,6 +172,7 @@ private: int m_wheelDelta; int m_focusedIndex; bool m_scrollbarCapturingMouse; + bool m_showPopup; #elif PLATFORM(GTK) IntPoint m_menuPosition; GtkMenu* m_popup; @@ -177,6 +186,8 @@ private: void OnMenuItemSelected(wxCommandEvent&); #elif PLATFORM(CHROMIUM) PopupMenuPrivate p; +#elif PLATFORM(HAIKU) + BMenu* m_menu; #endif }; diff --git a/WebCore/platform/PopupMenuClient.h b/WebCore/platform/PopupMenuClient.h index 2a9625b..2614fe2 100644 --- a/WebCore/platform/PopupMenuClient.h +++ b/WebCore/platform/PopupMenuClient.h @@ -49,7 +49,7 @@ public: virtual int clientPaddingRight() const = 0; virtual int listSize() const = 0; virtual int selectedIndex() const = 0; - virtual void hidePopup() = 0; + virtual void popupDidHide() = 0; virtual bool itemIsSeparator(unsigned listIndex) const = 0; virtual bool itemIsLabel(unsigned listIndex) const = 0; virtual bool itemIsSelected(unsigned listIndex) const = 0; diff --git a/WebCore/platform/ScrollView.cpp b/WebCore/platform/ScrollView.cpp index 54fa998..8c4b115 100644 --- a/WebCore/platform/ScrollView.cpp +++ b/WebCore/platform/ScrollView.cpp @@ -83,6 +83,7 @@ void ScrollView::setHasHorizontalScrollbar(bool hasBar) if (hasBar && !m_horizontalScrollbar) { m_horizontalScrollbar = createScrollbar(HorizontalScrollbar); addChild(m_horizontalScrollbar.get()); + m_horizontalScrollbar->styleChanged(); } else if (!hasBar && m_horizontalScrollbar) { removeChild(m_horizontalScrollbar.get()); m_horizontalScrollbar = 0; @@ -94,6 +95,7 @@ void ScrollView::setHasVerticalScrollbar(bool hasBar) if (hasBar && !m_verticalScrollbar) { m_verticalScrollbar = createScrollbar(VerticalScrollbar); addChild(m_verticalScrollbar.get()); + m_verticalScrollbar->styleChanged(); } else if (!hasBar && m_verticalScrollbar) { removeChild(m_verticalScrollbar.get()); m_verticalScrollbar = 0; @@ -105,7 +107,6 @@ PassRefPtr<Scrollbar> ScrollView::createScrollbar(ScrollbarOrientation orientati { return Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar); } -#endif void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode) { @@ -118,6 +119,7 @@ void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode v else updateScrollbars(scrollOffset()); } +#endif void ScrollView::scrollbarModes(ScrollbarMode& horizontalMode, ScrollbarMode& verticalMode) const { @@ -332,6 +334,15 @@ void ScrollView::updateScrollbars(const IntSize& desiredOffset) if (m_inUpdateScrollbars || prohibitsScrolling() || platformWidget()) return; + // If we came in here with the view already needing a layout, then go ahead and do that + // first. (This will be the common case, e.g., when the page changes due to window resizing for example). + // This layout will not re-enter updateScrollbars and does not count towards our max layout pass total. + if (!m_scrollbarsSuppressed) { + m_inUpdateScrollbars = true; + visibleContentsResized(); + m_inUpdateScrollbars = false; + } + bool hasHorizontalScrollbar = m_horizontalScrollbar; bool hasVerticalScrollbar = m_verticalScrollbar; @@ -352,13 +363,6 @@ void ScrollView::updateScrollbars(const IntSize& desiredOffset) if (hasVerticalScrollbar != newHasVerticalScrollbar) setHasVerticalScrollbar(newHasVerticalScrollbar); } else { - // If we came in here with the view already needing a layout, then go ahead and do that - // first. (This will be the common case, e.g., when the page changes due to window resizing for example). - // This layout will not re-enter updateScrollers and does not count towards our max layout pass total. - m_inUpdateScrollbars = true; - visibleContentsResized(); - m_inUpdateScrollbars = false; - bool sendContentResizedNotification = false; IntSize docSize = contentsSize(); @@ -465,8 +469,10 @@ void ScrollView::updateScrollbars(const IntSize& desiredOffset) m_verticalScrollbar->setSuppressInvalidation(false); } - if (hasHorizontalScrollbar != (m_horizontalScrollbar != 0) || hasVerticalScrollbar != (m_verticalScrollbar != 0)) + if (hasHorizontalScrollbar != (m_horizontalScrollbar != 0) || hasVerticalScrollbar != (m_verticalScrollbar != 0)) { frameRectsChanged(); + updateScrollCorner(); + } // 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. @@ -481,7 +487,7 @@ void ScrollView::updateScrollbars(const IntSize& desiredOffset) m_inUpdateScrollbars = false; } -const int panIconSizeLength = 20; +const int panIconSizeLength = 16; void ScrollView::scrollContents(const IntSize& scrollDelta) { @@ -626,23 +632,7 @@ void ScrollView::setScrollbarsSuppressed(bool suppressed, bool repaintOnUnsuppre m_verticalScrollbar->invalidate(); // Invalidate the scroll corner too on unsuppress. - IntRect hCorner; - if (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) { - hCorner = IntRect(m_horizontalScrollbar->width(), - height() - m_horizontalScrollbar->height(), - width() - m_horizontalScrollbar->width(), - m_horizontalScrollbar->height()); - invalidateRect(hCorner); - } - - if (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0) { - IntRect vCorner(width() - m_verticalScrollbar->width(), - m_verticalScrollbar->height(), - m_verticalScrollbar->width(), - height() - m_verticalScrollbar->height()); - if (vCorner != hCorner) - invalidateRect(vCorner); - } + invalidateRect(scrollCornerRect()); } } @@ -722,16 +712,48 @@ void ScrollView::frameRectsChanged() void ScrollView::repaintContentRectangle(const IntRect& rect, bool now) { - if (rect.isEmpty()) + IntRect visibleContent = visibleContentRect(); + visibleContent.intersect(rect); + if (visibleContent.isEmpty()) return; if (platformWidget()) { - platformRepaintContentRectangle(rect, now); + platformRepaintContentRectangle(visibleContent, now); return; } if (hostWindow()) - hostWindow()->repaint(contentsToWindow(rect), true, now); + hostWindow()->repaint(contentsToWindow(visibleContent), true, now); +} + +IntRect ScrollView::scrollCornerRect() const +{ + IntRect cornerRect; + + if (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) { + cornerRect.unite(IntRect(m_horizontalScrollbar->width(), + height() - m_horizontalScrollbar->height(), + width() - m_horizontalScrollbar->width(), + m_horizontalScrollbar->height())); + } + + if (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0) { + cornerRect.unite(IntRect(width() - m_verticalScrollbar->width(), + m_verticalScrollbar->height(), + m_verticalScrollbar->width(), + height() - m_verticalScrollbar->height())); + } + + return cornerRect; +} + +void ScrollView::updateScrollCorner() +{ +} + +void ScrollView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect) +{ + ScrollbarTheme::nativeTheme()->paintScrollCorner(this, context, cornerRect); } void ScrollView::paint(GraphicsContext* context, const IntRect& rect) @@ -773,25 +795,7 @@ void ScrollView::paint(GraphicsContext* context, const IntRect& rect) if (m_verticalScrollbar) m_verticalScrollbar->paint(context, scrollViewDirtyRect); - IntRect hCorner; - if (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) { - hCorner = IntRect(m_horizontalScrollbar->width(), - height() - m_horizontalScrollbar->height(), - width() - m_horizontalScrollbar->width(), - m_horizontalScrollbar->height()); - if (hCorner.intersects(scrollViewDirtyRect)) - ScrollbarTheme::nativeTheme()->paintScrollCorner(this, context, hCorner); - } - - if (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0) { - IntRect vCorner(width() - m_verticalScrollbar->width(), - m_verticalScrollbar->height(), - m_verticalScrollbar->width(), - height() - m_verticalScrollbar->height()); - if (vCorner != hCorner && vCorner.intersects(scrollViewDirtyRect)) - ScrollbarTheme::nativeTheme()->paintScrollCorner(this, context, vCorner); - } - + paintScrollCorner(context, scrollCornerRect()); context->restore(); } diff --git a/WebCore/platform/ScrollView.h b/WebCore/platform/ScrollView.h index 88e2564..ef3d03d 100644 --- a/WebCore/platform/ScrollView.h +++ b/WebCore/platform/ScrollView.h @@ -89,7 +89,7 @@ public: void scrollbarModes(ScrollbarMode& horizontalMode, ScrollbarMode& verticalMode) const; ScrollbarMode horizontalScrollbarMode() const { ScrollbarMode horizontal, vertical; scrollbarModes(horizontal, vertical); return horizontal; } ScrollbarMode verticalScrollbarMode() const { ScrollbarMode horizontal, vertical; scrollbarModes(horizontal, vertical); return vertical; } - virtual void setCanHaveScrollbars(bool flag); + void setCanHaveScrollbars(bool flag); bool canHaveScrollbars() const { return horizontalScrollbarMode() != ScrollbarAlwaysOff || verticalScrollbarMode() != ScrollbarAlwaysOff; } // Overridden by FrameView to create custom CSS scrollbars if applicable. @@ -239,6 +239,10 @@ protected: void setHasHorizontalScrollbar(bool); void setHasVerticalScrollbar(bool); + IntRect scrollCornerRect() const; + virtual void updateScrollCorner(); + virtual void paintScrollCorner(GraphicsContext*, const IntRect& cornerRect); + private: RefPtr<Scrollbar> m_horizontalScrollbar; RefPtr<Scrollbar> m_verticalScrollbar; diff --git a/WebCore/platform/Scrollbar.cpp b/WebCore/platform/Scrollbar.cpp index 4574f63..4eb2c4a 100644 --- a/WebCore/platform/Scrollbar.cpp +++ b/WebCore/platform/Scrollbar.cpp @@ -392,9 +392,9 @@ void Scrollbar::setFrameRect(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()) { - bool overlapsResizer = false; - ScrollView* view = parent(); + bool overlapsResizer = false; + ScrollView* view = parent(); + if (view && !rect.isEmpty() && !view->windowResizerRect().isEmpty()) { IntRect resizerRect = view->convertFromContainingWindow(view->windowResizerRect()); if (rect.intersects(resizerRect)) { if (orientation() == HorizontalScrollbar) { @@ -411,11 +411,11 @@ void Scrollbar::setFrameRect(const IntRect& rect) } } } - - if (overlapsResizer != m_overlapsResizer) { - m_overlapsResizer = overlapsResizer; + } + if (overlapsResizer != m_overlapsResizer) { + m_overlapsResizer = overlapsResizer; + if (view) view->adjustScrollbarsAvoidingResizerCount(m_overlapsResizer ? 1 : -1); - } } Widget::setFrameRect(adjustedRect); diff --git a/WebCore/platform/StaticConstructors.h b/WebCore/platform/StaticConstructors.h index 26b44de..5bc792c 100644 --- a/WebCore/platform/StaticConstructors.h +++ b/WebCore/platform/StaticConstructors.h @@ -56,6 +56,9 @@ #if COMPILER(MSVC7) #define DEFINE_GLOBAL(type, name) \ const type name; +#elif COMPILER(WINSCW) +#define DEFINE_GLOBAL(type, name, arg...) \ + const type name; #else #define DEFINE_GLOBAL(type, name, ...) \ const type name; @@ -67,6 +70,9 @@ #if COMPILER(MSVC7) #define DEFINE_GLOBAL(type, name) \ void * name[(sizeof(type) + sizeof(void *) - 1) / sizeof(void *)]; +#elif COMPILER(WINSCW) +#define DEFINE_GLOBAL(type, name, arg...) \ + void * name[(sizeof(type) + sizeof(void *) - 1) / sizeof(void *)]; #else #define DEFINE_GLOBAL(type, name, ...) \ void * name[(sizeof(type) + sizeof(void *) - 1) / sizeof(void *)]; diff --git a/WebCore/platform/ThemeTypes.h b/WebCore/platform/ThemeTypes.h index b763675..e132313 100644 --- a/WebCore/platform/ThemeTypes.h +++ b/WebCore/platform/ThemeTypes.h @@ -46,12 +46,11 @@ typedef unsigned ControlStates; // Must follow CSSValueKeywords.in order enum ControlPart { NoControlPart, CheckboxPart, RadioPart, PushButtonPart, SquareButtonPart, ButtonPart, - ButtonBevelPart, DefaultButtonPart, ListboxPart, ListItemPart, + ButtonBevelPart, DefaultButtonPart, ListButtonPart, ListboxPart, ListItemPart, MediaFullscreenButtonPart, MediaMuteButtonPart, MediaPlayButtonPart, MediaSeekBackButtonPart, MediaSeekForwardButtonPart, MediaRewindButtonPart, MediaReturnToRealtimeButtonPart, - MediaSliderPart, - MediaSliderThumbPart, MediaControlsBackgroundPart, - MediaCurrentTimePart, MediaTimeRemainingPart, + MediaSliderPart, MediaSliderThumbPart, MediaVolumeSliderContainerPart, MediaVolumeSliderPart, MediaVolumeSliderThumbPart, + MediaControlsBackgroundPart, MediaCurrentTimePart, MediaTimeRemainingPart, MenulistPart, MenulistButtonPart, MenulistTextPart, MenulistTextFieldPart, SliderHorizontalPart, SliderVerticalPart, SliderThumbHorizontalPart, SliderThumbVerticalPart, CaretPart, SearchFieldPart, SearchFieldDecorationPart, diff --git a/WebCore/platform/ThreadTimers.cpp b/WebCore/platform/ThreadTimers.cpp index 71a06b0..3ae8207 100644 --- a/WebCore/platform/ThreadTimers.cpp +++ b/WebCore/platform/ThreadTimers.cpp @@ -34,6 +34,11 @@ namespace WebCore { +// Fire timers for this length of time, and then quit to let the run loop process user input events. +// 100ms is about a perceptable delay in UI, so use a half of that as a threshold. +// This is to prevent UI freeze when there are too many timers or machine performance is low. +static const double maxDurationOfFiringTimers = 0.050; + // Timers are created, started and fired on the same thread, and each thread has its own ThreadTimers // copy to keep the heap and a set of currently firing timers. @@ -79,43 +84,6 @@ void ThreadTimers::updateSharedTimer() m_sharedTimer->setFireTime(m_timerHeap.first()->m_nextFireTime); } - -void ThreadTimers::collectFiringTimers(double fireTime, Vector<TimerBase*>& firingTimers) -{ - while (!m_timerHeap.isEmpty() && m_timerHeap.first()->m_nextFireTime <= fireTime) { - TimerBase* timer = m_timerHeap.first(); - firingTimers.append(timer); - m_timersReadyToFire.add(timer); - timer->m_nextFireTime = 0; - timer->heapDeleteMin(); - } -} - -void ThreadTimers::fireTimers(double fireTime, const Vector<TimerBase*>& firingTimers) -{ - size_t size = firingTimers.size(); - for (size_t i = 0; i != size; ++i) { - TimerBase* timer = firingTimers[i]; - - // If not in the set, this timer has been deleted or re-scheduled in another timer's fired function. - // So either we don't want to fire it at all or we will fire it next time the shared timer goes off. - // It might even have been deleted; that's OK because we won't do anything else with the pointer. - if (!m_timersReadyToFire.contains(timer)) - continue; - - // Setting the next fire time has a side effect of removing the timer from the firing timers set. - double interval = timer->repeatInterval(); - timer->setNextFireTime(interval ? fireTime + interval : 0); - - // Once the timer has been fired, it may be deleted, so do nothing else with it after this point. - timer->fired(); - - // Catch the case where the timer asked timers to fire in a nested event loop. - if (!m_firingTimers) - break; - } -} - void ThreadTimers::sharedTimerFired() { // Redirect to non-static method. @@ -130,17 +98,24 @@ void ThreadTimers::sharedTimerFiredInternal() m_firingTimers = true; double fireTime = currentTime(); - Vector<TimerBase*> firingTimers; + double timeToQuit = fireTime + maxDurationOfFiringTimers; - // m_timersReadyToFire will initially contain the same set as firingTimers, but - // as timers fire some mat become re-scheduled or deleted. They get removed from - // m_timersReadyToFire so we can avoid firing them. - ASSERT(m_timersReadyToFire.isEmpty()); + while (!m_timerHeap.isEmpty() && m_timerHeap.first()->m_nextFireTime <= fireTime) { + TimerBase* timer = m_timerHeap.first(); + timer->m_nextFireTime = 0; + timer->heapDeleteMin(); - collectFiringTimers(fireTime, firingTimers); - fireTimers(fireTime, firingTimers); + double interval = timer->repeatInterval(); + timer->setNextFireTime(interval ? fireTime + interval : 0); + + // Once the timer has been fired, it may be deleted, so do nothing else with it after this point. + timer->fired(); + + // Catch the case where the timer asked timers to fire in a nested event loop, or we are over time limit. + if (!m_firingTimers || timeToQuit < currentTime()) + break; + } - m_timersReadyToFire.clear(); m_firingTimers = false; updateSharedTimer(); @@ -150,7 +125,6 @@ void ThreadTimers::fireTimersInNestedEventLoop() { // Reset the reentrancy guard so the timers can fire again. m_firingTimers = false; - m_timersReadyToFire.clear(); updateSharedTimer(); } diff --git a/WebCore/platform/ThreadTimers.h b/WebCore/platform/ThreadTimers.h index ea0a366..01b4c71 100644 --- a/WebCore/platform/ThreadTimers.h +++ b/WebCore/platform/ThreadTimers.h @@ -45,7 +45,6 @@ namespace WebCore { void setSharedTimer(SharedTimer*); Vector<TimerBase*>& timerHeap() { return m_timerHeap; } - HashSet<const TimerBase*>& timersReadyToFire() { return m_timersReadyToFire; } void updateSharedTimer(); void fireTimersInNestedEventLoop(); @@ -53,13 +52,10 @@ namespace WebCore { private: static void sharedTimerFired(); - void fireTimers(double fireTime, const Vector<TimerBase*>&); - void collectFiringTimers(double fireTime, Vector<TimerBase*>&); void sharedTimerFiredInternal(); void fireTimersInNestedEventLoopInternal(); Vector<TimerBase*> m_timerHeap; - HashSet<const TimerBase*> m_timersReadyToFire; // Temporarily holds a pointer to a stack object. No ownership. SharedTimer* m_sharedTimer; // External object, can be a run loop on a worker thread. Normally set/reset by worker thread. bool m_firingTimers; // Reentrancy guard. }; diff --git a/WebCore/platform/Timer.cpp b/WebCore/platform/Timer.cpp index bd29fd8..539846c 100644 --- a/WebCore/platform/Timer.cpp +++ b/WebCore/platform/Timer.cpp @@ -53,11 +53,6 @@ static Vector<TimerBase*>& timerHeap() return threadGlobalData().threadTimers().timerHeap(); } -static HashSet<const TimerBase*>& timersReadyToFire() -{ - return threadGlobalData().threadTimers().timersReadyToFire(); -} - // Class to represent elements in the heap when calling the standard library heap algorithms. // Maintains the m_heapIndex value in the timers themselves, which allows us to do efficient // modification of the heap. @@ -205,7 +200,7 @@ bool TimerBase::isActive() const { ASSERT(m_thread == currentThread()); - return m_nextFireTime || timersReadyToFire().contains(this); + return m_nextFireTime; } double TimerBase::nextFireInterval() const @@ -296,9 +291,6 @@ void TimerBase::setNextFireTime(double newTime) ASSERT(m_thread == currentThread()); // Keep heap valid while changing the next-fire time. - - timersReadyToFire().remove(this); - double oldTime = m_nextFireTime; if (oldTime != newTime) { m_nextFireTime = newTime; diff --git a/WebCore/platform/TreeShared.h b/WebCore/platform/TreeShared.h index 1ac1b33..02728ff 100644 --- a/WebCore/platform/TreeShared.h +++ b/WebCore/platform/TreeShared.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -28,17 +28,8 @@ namespace WebCore { template<class T> class TreeShared : public Noncopyable { public: - TreeShared() - : m_refCount(0) - , m_parent(0) - { -#ifndef NDEBUG - m_deletionHasBegun = false; - m_inRemovedLastRefFunction = false; -#endif - } - TreeShared(T* parent) - : m_refCount(0) + TreeShared(int initialRefCount = 1) + : m_refCount(initialRefCount) , m_parent(0) { #ifndef NDEBUG diff --git a/WebCore/platform/Widget.h b/WebCore/platform/Widget.h index 4534d58..cbbc427 100644 --- a/WebCore/platform/Widget.h +++ b/WebCore/platform/Widget.h @@ -70,10 +70,22 @@ class wxWindow; typedef wxWindow* PlatformWidget; #endif +#if PLATFORM(HAIKU) +class BView; +typedef BView* PlatformWidget; +#endif + #if PLATFORM(CHROMIUM) #include "PlatformWidget.h" #endif +#if PLATFORM(QT) +class QWebPageClient; +typedef QWebPageClient* PlatformPageClient; +#else +typedef PlatformWidget PlatformPageClient; +#endif + #include "IntPoint.h" #include "IntRect.h" #include "IntSize.h" diff --git a/WebCore/platform/android/TemporaryLinkStubs.cpp b/WebCore/platform/android/TemporaryLinkStubs.cpp index 482565b..215c7f5 100644 --- a/WebCore/platform/android/TemporaryLinkStubs.cpp +++ b/WebCore/platform/android/TemporaryLinkStubs.cpp @@ -174,6 +174,11 @@ void Pasteboard::writeSelection(Range*, bool, Frame*) notImplemented(); } +void Pasteboard::writePlainText(const String&) +{ + notImplemented(); +} + void Pasteboard::writeURL(const KURL&, const String&, Frame*) { notImplemented(); diff --git a/WebCore/platform/chromium/ChromiumBridge.h b/WebCore/platform/chromium/ChromiumBridge.h index bca8c52..1afcc23 100644 --- a/WebCore/platform/chromium/ChromiumBridge.h +++ b/WebCore/platform/chromium/ChromiumBridge.h @@ -67,12 +67,16 @@ namespace WebCore { class ChromiumBridge { public: // Clipboard ---------------------------------------------------------- - static bool clipboardIsFormatAvailable(PasteboardPrivate::ClipboardFormat); + static bool clipboardIsFormatAvailable(PasteboardPrivate::ClipboardFormat, PasteboardPrivate::ClipboardBuffer); - static String clipboardReadPlainText(); - static void clipboardReadHTML(String*, KURL*); + static String clipboardReadPlainText(PasteboardPrivate::ClipboardBuffer); + static void clipboardReadHTML(PasteboardPrivate::ClipboardBuffer, String*, KURL*); + // Only the clipboardRead functions take a buffer argument because + // Chromium currently uses a different technique to write to alternate + // clipboard buffers. static void clipboardWriteSelection(const String&, const KURL&, const String&, bool); + static void clipboardWritePlainText(const String&); static void clipboardWriteURL(const KURL&, const String&); static void clipboardWriteImage(const NativeImageSkia*, const KURL&, const String&); @@ -92,6 +96,9 @@ namespace WebCore { static String directoryName(const String& path); static String pathByAppendingComponent(const String& path, const String& component); static bool makeAllDirectories(const String& path); + static String getAbsolutePath(const String&); + static bool isDirectory(const String&); + static KURL filePathToURL(const String&); // Font --------------------------------------------------------------- #if PLATFORM(WIN_OS) @@ -103,12 +110,16 @@ namespace WebCore { // Forms -------------------------------------------------------------- static void notifyFormStateChanged(const Document*); - + // HTML5 DB ----------------------------------------------------------- #if ENABLE(DATABASE) - static PlatformFileHandle databaseOpenFile(const String& fileName, int desiredFlags); - static bool databaseDeleteFile(const String& fileName); + // Returns a handle to the DB file and ooptionally a handle to its containing directory + static PlatformFileHandle databaseOpenFile(const String& fileName, int desiredFlags, PlatformFileHandle* dirHandle = 0); + // Returns a SQLite code (SQLITE_OK = 0, on success) + static int databaseDeleteFile(const String& fileName, bool syncDir = false); + // Returns the attributes of the DB file static long databaseGetFileAttributes(const String& fileName); + // Returns the size of the DB file static long long databaseGetFileSize(const String& fileName); #endif diff --git a/WebCore/platform/chromium/ChromiumDataObject.h b/WebCore/platform/chromium/ChromiumDataObject.h index 3e8675e..a227001 100644 --- a/WebCore/platform/chromium/ChromiumDataObject.h +++ b/WebCore/platform/chromium/ChromiumDataObject.h @@ -55,7 +55,38 @@ namespace WebCore { void clear(); bool hasData() const; + + KURL mainURL() const { return url; } + void setMainURL(const KURL& newURL) { url = newURL; } + String mainURLTitle() const { return urlTitle; } + void setMainURLTitle(const String& newURLTitle) { urlTitle = newURLTitle; } + + String textPlain() const { return plainText; } + void setTextPlain(const String& newText) { plainText = newText; } + + String textHTML() const { return textHtml; } + void setTextHTML(const String& newText) { textHtml = newText; } + + KURL htmlBaseURL() const { return htmlBaseUrl; } + void setHTMLBaseURL(const KURL& newURL) { htmlBaseUrl = newURL; } + + SharedBuffer* content() const { return fileContent.get(); } + PassRefPtr<SharedBuffer> releaseContent() { return fileContent.release(); } + void setContent(PassRefPtr<SharedBuffer> newContent) { fileContent = newContent; } + + String contentFileExtension() const { return fileExtension; } + void setContentFileExtension(const String& newFileExtension) { fileExtension = newFileExtension; } + + String contentFileName() const { return fileContentFilename; } + void setContentFileName(const String& newFilename) { fileContentFilename = newFilename; } + + const Vector<String>& fileNames() const { return filenames; } + void setFileNames(const Vector<String>& newFilenames) { filenames = newFilenames; } + void takeFileNames(Vector<String>& newFilenames) { filenames.swap(newFilenames); } + + // Interim state: All members will become private, do NOT access them directly! + // Rather use the above accessor methods (or devise new ones if necessary). KURL url; String urlTitle; diff --git a/WebCore/platform/chromium/ClipboardChromium.cpp b/WebCore/platform/chromium/ClipboardChromium.cpp index 4050294..d330d3b 100644 --- a/WebCore/platform/chromium/ClipboardChromium.cpp +++ b/WebCore/platform/chromium/ClipboardChromium.cpp @@ -40,6 +40,7 @@ #include "MIMETypeRegistry.h" #include "markup.h" #include "NamedNodeMap.h" +#include "Pasteboard.h" #include "PlatformString.h" #include "Range.h" #include "RenderImage.h" @@ -92,6 +93,7 @@ void ClipboardChromium::clearData(const String& type) m_dataObject->url = KURL(); m_dataObject->urlTitle = ""; } + if (dataType == ClipboardDataTypeText) m_dataObject->plainText = ""; } @@ -116,7 +118,11 @@ String ClipboardChromium::getData(const String& type, bool& success) const if (!isForDragging()) { // If this isn't for a drag, it's for a cut/paste event handler. // In this case, we need to check the clipboard. - text = ChromiumBridge::clipboardReadPlainText(); + PasteboardPrivate::ClipboardBuffer buffer = + Pasteboard::generalPasteboard()->isSelectionMode() ? + PasteboardPrivate::SelectionBuffer : + PasteboardPrivate::StandardBuffer; + text = ChromiumBridge::clipboardReadPlainText(buffer); success = !text.isEmpty(); } else if (!m_dataObject->plainText.isEmpty()) { success = true; @@ -142,7 +148,7 @@ bool ClipboardChromium::setData(const String& type, const String& data) ClipboardDataType winType = clipboardTypeFromMIMEType(type); if (winType == ClipboardDataTypeURL) { - m_dataObject->url = KURL(data); + m_dataObject->url = KURL(ParsedURLString, data); return m_dataObject->url.isValid(); } @@ -150,6 +156,7 @@ bool ClipboardChromium::setData(const String& type, const String& data) m_dataObject->plainText = data; return true; } + return false; } @@ -163,6 +170,9 @@ HashSet<String> ClipboardChromium::types() const if (!m_dataObject) return results; + if (!m_dataObject->filenames.isEmpty()) + results.add("Files"); + if (m_dataObject->url.isValid()) { results.add("URL"); results.add("text/uri-list"); @@ -178,8 +188,17 @@ HashSet<String> ClipboardChromium::types() const PassRefPtr<FileList> ClipboardChromium::files() const { - notImplemented(); - return 0; + if (policy() != ClipboardReadable) + return FileList::create(); + + if (!m_dataObject || m_dataObject->filenames.isEmpty()) + return FileList::create(); + + RefPtr<FileList> fileList = FileList::create(); + for (size_t i = 0; i < m_dataObject->filenames.size(); ++i) + fileList->append(File::create(m_dataObject->filenames.at(i))); + + return fileList.release(); } void ClipboardChromium::setDragImage(CachedImage* image, Node* node, const IntPoint& loc) diff --git a/WebCore/platform/chromium/DragDataChromium.cpp b/WebCore/platform/chromium/DragDataChromium.cpp index eaec025..133ba24 100644 --- a/WebCore/platform/chromium/DragDataChromium.cpp +++ b/WebCore/platform/chromium/DragDataChromium.cpp @@ -30,10 +30,12 @@ #include "config.h" #include "DragData.h" +#include "ChromiumBridge.h" #include "ChromiumDataObject.h" #include "Clipboard.h" #include "ClipboardChromium.h" #include "DocumentFragment.h" +#include "FileSystem.h" #include "KURL.h" #include "markup.h" #include "NotImplemented.h" @@ -56,18 +58,25 @@ PassRefPtr<Clipboard> DragData::createClipboard(ClipboardAccessPolicy policy) co bool DragData::containsURL() const { - return m_platformDragData->url.isValid(); + return !asURL().isEmpty(); } String DragData::asURL(String* title) const { - if (!m_platformDragData->url.isValid()) - return String(); + String url; + if (m_platformDragData->url.isValid()) + url = m_platformDragData->url.string(); + else if (m_platformDragData->filenames.size() == 1) { + String fileName = m_platformDragData->filenames[0]; + fileName = ChromiumBridge::getAbsolutePath(fileName); + if (fileExists(fileName) && !ChromiumBridge::isDirectory(fileName)) + url = ChromiumBridge::filePathToURL(fileName).string(); + } // |title| can be NULL if (title) *title = m_platformDragData->urlTitle; - return m_platformDragData->url.string(); + return url; } bool DragData::containsFiles() const @@ -112,7 +121,8 @@ bool DragData::containsCompatibleContent() const return containsPlainText() || containsURL() || containsHTML(m_platformDragData) - || containsColor(); + || containsColor() + || containsFiles(); } PassRefPtr<DocumentFragment> DragData::asFragment(Document* doc) const diff --git a/WebCore/platform/chromium/FileChooserChromium.cpp b/WebCore/platform/chromium/FileChooserChromium.cpp index 08d33a3..3d75b42 100644 --- a/WebCore/platform/chromium/FileChooserChromium.cpp +++ b/WebCore/platform/chromium/FileChooserChromium.cpp @@ -42,7 +42,7 @@ String FileChooser::basenameForWidth(const Font& font, int width) const if (m_filenames.isEmpty()) string = fileButtonNoFileSelectedLabel(); else if (m_filenames.size() == 1) - string = pathGetFileName(m_filenames[0]); + string = pathGetDisplayFileName(m_filenames[0]); else return StringTruncator::rightTruncate(multipleFileUploadText(m_filenames.size()), width, font, false); diff --git a/WebCore/platform/chromium/FileSystemChromiumLinux.cpp b/WebCore/platform/chromium/FileSystemChromiumLinux.cpp index e388dee..24f8da5 100644 --- a/WebCore/platform/chromium/FileSystemChromiumLinux.cpp +++ b/WebCore/platform/chromium/FileSystemChromiumLinux.cpp @@ -38,4 +38,9 @@ String pathGetFileName(const String& path) return path.substring(path.reverseFind('/') + 1); } +String pathGetDisplayFileName(const String& path) +{ + return pathGetFileName(path); +} + } // namespace WebCore diff --git a/WebCore/platform/chromium/FileSystemChromiumMac.mm b/WebCore/platform/chromium/FileSystemChromiumMac.mm index 7e880e1..29563de 100644 --- a/WebCore/platform/chromium/FileSystemChromiumMac.mm +++ b/WebCore/platform/chromium/FileSystemChromiumMac.mm @@ -38,6 +38,11 @@ namespace WebCore { String pathGetFileName(const String& path) { + return [path lastPathComponent]; +} + +String pathGetDisplayFileName(const String& path) +{ return [[NSFileManager defaultManager] displayNameAtPath:path]; } diff --git a/WebCore/platform/chromium/FileSystemChromiumWin.cpp b/WebCore/platform/chromium/FileSystemChromiumWin.cpp index 704c39a..0e605dc 100644 --- a/WebCore/platform/chromium/FileSystemChromiumWin.cpp +++ b/WebCore/platform/chromium/FileSystemChromiumWin.cpp @@ -41,4 +41,9 @@ String pathGetFileName(const String& path) return String(PathFindFileName(String(path).charactersWithNullTermination())); } +String pathGetDisplayFileName(const String& path) +{ + return pathGetFileName(path); +} + } // namespace WebCore diff --git a/WebCore/platform/chromium/KeyCodeConversionGtk.cpp b/WebCore/platform/chromium/KeyCodeConversionGtk.cpp index 4fc7f32..5950de1 100644 --- a/WebCore/platform/chromium/KeyCodeConversionGtk.cpp +++ b/WebCore/platform/chromium/KeyCodeConversionGtk.cpp @@ -357,6 +357,31 @@ int windowsKeyCodeForKeyEvent(unsigned keycode) // VKEY_NONAME (FC) Reserved for future use // VKEY_PA1 (FD) PA1 key // VKEY_OEM_CLEAR (FE) Clear key + case GDK_F1: + case GDK_F2: + case GDK_F3: + case GDK_F4: + case GDK_F5: + case GDK_F6: + case GDK_F7: + case GDK_F8: + case GDK_F9: + case GDK_F10: + case GDK_F11: + case GDK_F12: + case GDK_F13: + case GDK_F14: + case GDK_F15: + case GDK_F16: + case GDK_F17: + case GDK_F18: + case GDK_F19: + case GDK_F20: + case GDK_F21: + case GDK_F22: + case GDK_F23: + case GDK_F24: + return VKEY_F1 + (keycode - GDK_F1); default: return 0; } diff --git a/WebCore/platform/chromium/PasteboardChromium.cpp b/WebCore/platform/chromium/PasteboardChromium.cpp index c5dee82..7702730 100644 --- a/WebCore/platform/chromium/PasteboardChromium.cpp +++ b/WebCore/platform/chromium/PasteboardChromium.cpp @@ -59,6 +59,7 @@ Pasteboard* Pasteboard::generalPasteboard() } Pasteboard::Pasteboard() + : m_selectionMode(false) { } @@ -68,6 +69,16 @@ void Pasteboard::clear() // previous contents. } +bool Pasteboard::isSelectionMode() const +{ + return m_selectionMode; +} + +void Pasteboard::setSelectionMode(bool selectionMode) +{ + m_selectionMode = selectionMode; +} + void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame) { String html = createMarkup(selectedRange, 0, AnnotateForInterchange); @@ -85,6 +96,17 @@ void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, ChromiumBridge::clipboardWriteSelection(html, url, plainText, canSmartCopyOrDelete); } +void Pasteboard::writePlainText(const String& text) +{ +#if PLATFORM(WIN_OS) + String plainText(text); + replaceNewlinesWithWindowsStyleNewlines(plainText); + ChromiumBridge::clipboardWritePlainText(plainText); +#else + ChromiumBridge::clipboardWritePlainText(text); +#endif +} + void Pasteboard::writeURL(const KURL& url, const String& titleStr, Frame* frame) { ASSERT(!url.isEmpty()); @@ -134,23 +156,23 @@ void Pasteboard::writeImage(Node* node, const KURL&, const String& title) bool Pasteboard::canSmartReplace() { - return ChromiumBridge::clipboardIsFormatAvailable( - PasteboardPrivate::WebSmartPasteFormat); + return ChromiumBridge::clipboardIsFormatAvailable(PasteboardPrivate::WebSmartPasteFormat, m_selectionMode ? PasteboardPrivate::SelectionBuffer : PasteboardPrivate::StandardBuffer); } String Pasteboard::plainText(Frame* frame) { - return ChromiumBridge::clipboardReadPlainText(); + return ChromiumBridge::clipboardReadPlainText(m_selectionMode ? PasteboardPrivate::SelectionBuffer : PasteboardPrivate::StandardBuffer); } PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefPtr<Range> context, bool allowPlainText, bool& chosePlainText) { chosePlainText = false; + PasteboardPrivate::ClipboardBuffer buffer = m_selectionMode ? PasteboardPrivate::SelectionBuffer : PasteboardPrivate::StandardBuffer; - if (ChromiumBridge::clipboardIsFormatAvailable(PasteboardPrivate::HTMLFormat)) { + if (ChromiumBridge::clipboardIsFormatAvailable(PasteboardPrivate::HTMLFormat, buffer)) { String markup; KURL srcURL; - ChromiumBridge::clipboardReadHTML(&markup, &srcURL); + ChromiumBridge::clipboardReadHTML(buffer, &markup, &srcURL); RefPtr<DocumentFragment> fragment = createFragmentFromMarkup(frame->document(), markup, srcURL); @@ -159,7 +181,7 @@ PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefP } if (allowPlainText) { - String markup = ChromiumBridge::clipboardReadPlainText(); + String markup = ChromiumBridge::clipboardReadPlainText(buffer); if (!markup.isEmpty()) { chosePlainText = true; diff --git a/WebCore/platform/chromium/PasteboardPrivate.h b/WebCore/platform/chromium/PasteboardPrivate.h index 26d45a0..95cc697 100644 --- a/WebCore/platform/chromium/PasteboardPrivate.h +++ b/WebCore/platform/chromium/PasteboardPrivate.h @@ -41,6 +41,10 @@ namespace WebCore { BookmarkFormat, WebSmartPasteFormat, }; + enum ClipboardBuffer { + StandardBuffer, + SelectionBuffer, + }; }; } // namespace WebCore diff --git a/WebCore/platform/chromium/PopupMenuChromium.cpp b/WebCore/platform/chromium/PopupMenuChromium.cpp index 51ed6ce..d6f895d 100644 --- a/WebCore/platform/chromium/PopupMenuChromium.cpp +++ b/WebCore/platform/chromium/PopupMenuChromium.cpp @@ -50,6 +50,7 @@ #include "PopupMenu.h" #include "RenderTheme.h" #include "ScrollbarTheme.h" +#include "StringTruncator.h" #include "SystemTime.h" #include <wtf/CurrentTime.h> @@ -72,10 +73,13 @@ static const TimeStamp kTypeAheadTimeoutMs = 1000; // The settings used for the drop down menu. // This is the delegate used if none is provided. static const PopupContainerSettings dropDownSettings = { - true, // focusOnShow - true, // setTextOnIndexChange - true, // acceptOnAbandon - false // loopSelectionNavigation + true, // focusOnShow + true, // setTextOnIndexChange + true, // acceptOnAbandon + false, // loopSelectionNavigation + false, // restrictWidthOfListBox + // display item text in its first strong directional character's directionality. + PopupContainerSettings::FirstStrongDirectionalCharacterDirection, }; // This class uses WebCore code to paint and handle events for a drop-down list @@ -100,10 +104,7 @@ public: // PopupListBox methods - // Shows the popup - void showPopup(); - - // Hides the popup. Do not call this directly: use client->hidePopup(). + // Hides the popup. void hidePopup(); // Updates our internal list to match the client. @@ -373,8 +374,7 @@ void PopupContainer::showExternal(const IntRect& rect, FrameView* v, int index) void PopupContainer::hidePopup() { - if (client()) - client()->popupClosed(this); + listBox()->hidePopup(); } void PopupContainer::layout() @@ -601,6 +601,22 @@ bool PopupListBox::isInterestedInEventForKey(int keyCode) } } +static bool isCharacterTypeEvent(const PlatformKeyboardEvent& event) +{ + // Check whether the event is a character-typed event or not. + // In Windows, PlatformKeyboardEvent::Char (not RawKeyDown) type event + // is considered as character type event. In Mac OS, KeyDown (not + // KeyUp) is considered as character type event. +#if PLATFORM(WIN_OS) + if (event.type() == PlatformKeyboardEvent::Char) + return true; +#else + if (event.type() == PlatformKeyboardEvent::KeyDown) + return true; +#endif + return false; +} + bool PopupListBox::handleKeyEvent(const PlatformKeyboardEvent& event) { if (event.type() == PlatformKeyboardEvent::KeyUp) @@ -615,7 +631,7 @@ bool PopupListBox::handleKeyEvent(const PlatformKeyboardEvent& event) return true; case VKEY_RETURN: if (m_selectedIndex == -1) { - m_popupClient->hidePopup(); + hidePopup(); // Don't eat the enter if nothing is selected. return false; } @@ -641,7 +657,8 @@ bool PopupListBox::handleKeyEvent(const PlatformKeyboardEvent& event) break; default: if (!event.ctrlKey() && !event.altKey() && !event.metaKey() - && isPrintableChar(event.windowsVirtualKeyCode())) + && isPrintableChar(event.windowsVirtualKeyCode()) + && isCharacterTypeEvent(event)) typeAheadFind(event); break; } @@ -690,21 +707,6 @@ static String stripLeadingWhiteSpace(const String& string) return string.substring(i, length - i); } -static bool isCharacterTypeEvent(const PlatformKeyboardEvent& event) { - // Check whether the event is a character-typed event or not. - // In Windows, PlatformKeyboardEvent::Char (not RawKeyDown) type event - // is considered as character type event. In Mac OS, KeyDown (not - // KeyUp) is considered as character type event. -#if PLATFORM(WIN_OS) - if (event.type() == PlatformKeyboardEvent::Char) - return true; -#else - if (event.type() == PlatformKeyboardEvent::KeyDown) - return true; -#endif - return false; -} - // From HTMLSelectElement.cpp, with modifications void PopupListBox::typeAheadFind(const PlatformKeyboardEvent& event) { @@ -714,8 +716,7 @@ void PopupListBox::typeAheadFind(const PlatformKeyboardEvent& event) // Reset the time when user types in a character. The time gap between // last character and the current character is used to indicate whether // user typed in a string or just a character as the search prefix. - if (isCharacterTypeEvent(event)) - m_lastCharTime = now; + m_lastCharTime = now; UChar c = event.windowsVirtualKeyCode(); @@ -817,25 +818,44 @@ void PopupListBox::paintRow(GraphicsContext* gc, const IntRect& rect, int rowInd return; } + if (!style.isVisible()) + return; + gc->setFillColor(textColor); - // Bunch of shit to deal with RTL text... + Font itemFont = getRowFont(rowIndex); + // FIXME: http://crbug.com/19872 We should get the padding of individual option + // elements. This probably implies changes to PopupMenuClient. + bool rightAligned = m_popupClient->menuStyle().textDirection() == RTL; + int textX = 0; + int maxWidth = 0; + if (rightAligned) + maxWidth = rowRect.width() - max(0, m_popupClient->clientPaddingRight() - m_popupClient->clientInsetRight()); + else { + textX = max(0, m_popupClient->clientPaddingLeft() - m_popupClient->clientInsetLeft()); + maxWidth = rowRect.width() - textX; + } + // Prepare text to be drawn. String itemText = m_popupClient->itemText(rowIndex); + if (m_settings.restrictWidthOfListBox) // truncate string to fit in. + itemText = StringTruncator::rightTruncate(itemText, maxWidth, itemFont); unsigned length = itemText.length(); const UChar* str = itemText.characters(); - - TextRun textRun(str, length, false, 0, 0, itemText.defaultWritingDirection() == WTF::Unicode::RightToLeft); - - // FIXME: http://b/1210481 We should get the padding of individual option - // elements. This probably implies changes to PopupMenuClient. - - // Draw the item text - if (style.isVisible()) { - Font itemFont = getRowFont(rowIndex); - int textX = max(0, m_popupClient->clientPaddingLeft() - m_popupClient->clientInsetLeft()); - int textY = rowRect.y() + itemFont.ascent() + (rowRect.height() - itemFont.height()) / 2; - gc->drawBidiText(itemFont, textRun, IntPoint(textX, textY)); - } + // Prepare the directionality to draw text. + bool rtl = false; + if (m_settings.itemTextDirectionalityHint == PopupContainerSettings::DOMElementDirection) + rtl = style.textDirection() == RTL; + else if (m_settings.itemTextDirectionalityHint == + PopupContainerSettings::FirstStrongDirectionalCharacterDirection) + rtl = itemText.defaultWritingDirection() == WTF::Unicode::RightToLeft; + TextRun textRun(str, length, false, 0, 0, rtl); + // If the text is right-to-left, make it right-aligned by adjusting its + // beginning position. + if (rightAligned) + textX += maxWidth - itemFont.width(textRun); + // Draw the item text. + int textY = rowRect.y() + itemFont.ascent() + (rowRect.height() - itemFont.height()) / 2; + gc->drawBidiText(itemFont, textRun, IntPoint(textX, textY)); } Font PopupListBox::getRowFont(int rowIndex) @@ -859,7 +879,7 @@ void PopupListBox::abandon() m_selectedIndex = m_originalIndex; - m_popupClient->hidePopup(); + hidePopup(); if (m_acceptedIndexOnAbandon >= 0) { m_popupClient->valueChanged(m_acceptedIndexOnAbandon); @@ -892,7 +912,7 @@ void PopupListBox::acceptIndex(int index) if (index < 0) { if (m_popupClient) { // Enter pressed with no selection, just close the popup. - m_popupClient->hidePopup(); + hidePopup(); } return; } @@ -901,7 +921,7 @@ void PopupListBox::acceptIndex(int index) RefPtr<PopupListBox> keepAlive(this); // Hide ourselves first since valueChanged may have numerous side-effects. - m_popupClient->hidePopup(); + hidePopup(); // Tell the <select> PopupMenuClient what index was selected. m_popupClient->valueChanged(index); @@ -1047,6 +1067,17 @@ void PopupListBox::adjustSelectedIndex(int delta) scrollToRevealSelection(); } +void PopupListBox::hidePopup() +{ + if (parent()) { + PopupContainer* container = static_cast<PopupContainer*>(parent()); + if (container->client()) + container->client()->popupClosed(container); + } + + m_popupClient->popupDidHide(); +} + void PopupListBox::updateFromElement() { clear(); @@ -1090,10 +1121,11 @@ void PopupListBox::layout() baseWidth = max(baseWidth, width); } // FIXME: http://b/1210481 We should get the padding of individual option elements. - paddingWidth = max(paddingWidth, + paddingWidth = max(paddingWidth, m_popupClient->clientPaddingLeft() + m_popupClient->clientPaddingRight()); } + // Calculate scroll bar width. int windowHeight = 0; #if PLATFORM(DARWIN) @@ -1124,14 +1156,20 @@ void PopupListBox::layout() if (m_visibleRows < numItems()) scrollbarWidth = ScrollbarTheme::nativeTheme()->scrollbarThickness(); - int windowWidth = baseWidth + scrollbarWidth + paddingWidth; - int contentWidth = baseWidth; - - if (windowWidth < m_baseWidth) { + int windowWidth; + int contentWidth; + if (m_settings.restrictWidthOfListBox) { windowWidth = m_baseWidth; contentWidth = m_baseWidth - scrollbarWidth - paddingWidth; } else { - m_baseWidth = baseWidth; + windowWidth = baseWidth + scrollbarWidth + paddingWidth; + contentWidth = baseWidth; + + if (windowWidth < m_baseWidth) { + windowWidth = m_baseWidth; + contentWidth = m_baseWidth - scrollbarWidth - paddingWidth; + } else + m_baseWidth = baseWidth; } resize(windowWidth, windowHeight); diff --git a/WebCore/platform/chromium/PopupMenuChromium.h b/WebCore/platform/chromium/PopupMenuChromium.h index f394bc2..ee094b3 100644 --- a/WebCore/platform/chromium/PopupMenuChromium.h +++ b/WebCore/platform/chromium/PopupMenuChromium.h @@ -52,7 +52,11 @@ namespace WebCore { }; PopupItem(const String& label, Type type) - : label(label), type(type), yOffset(0) { } + : label(label) + , type(type) + , yOffset(0) + { + } String label; Type type; int yOffset; // y offset of this item, relative to the top of the popup. @@ -83,10 +87,30 @@ namespace WebCore { // regardless of this setting. bool acceptOnAbandon; - // Whether the we should move the selection to the first/last item when + // Whether we should move the selection to the first/last item when // the user presses down/up arrow keys and the last/first item is // selected. bool loopSelectionNavigation; + + // Whether we should restrict the width of the PopupListBox or not. + // Autocomplete popups are restricted, combo-boxes (select tags) aren't. + bool restrictWidthOfListBox; + + // A hint on the display directionality of the item text in popup menu. + // + // We could either display the items in the drop-down using its DOM element's + // directionality, or we could display the items in the drop-down using heuristics: + // such as in its first strong directionality character's direction. + // Please refer to the discussion (especially comment #7 and #10) in + // https://bugs.webkit.org/show_bug.cgi?id=27889 for details. + enum DirectionalityHint { + // Use the DOM element's directionality to display the item text in popup menu. + DOMElementDirection, + // Use the item text's first strong-directional character's directionality + // to display the item text in popup menu. + FirstStrongDirectionalCharacterDirection, + }; + DirectionalityHint itemTextDirectionalityHint; }; class PopupContainer : public FramelessScrollView { @@ -121,7 +145,7 @@ namespace WebCore { // popups on other platforms. void show(const IntRect&, FrameView*, int index); - // Hide the popup. Do not call this directly: use client->hidePopup(). + // Hide the popup. void hidePopup(); // Compute size of widget and children. diff --git a/WebCore/platform/chromium/ThemeChromiumMac.h b/WebCore/platform/chromium/ThemeChromiumMac.h new file mode 100644 index 0000000..5580d1d --- /dev/null +++ b/WebCore/platform/chromium/ThemeChromiumMac.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2009 Google Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ThemeChromiumMac_h +#define ThemeChromiumMac_h + +#include "Theme.h" + +// This file (and its associated .mm file) is a clone of ThemeMac.h. See +// the .mm file for details. + +namespace WebCore { + +class ThemeChromiumMac : public Theme { +public: + ThemeChromiumMac() { } + virtual ~ThemeChromiumMac() { } + + virtual int baselinePositionAdjustment(ControlPart) const; + + virtual FontDescription controlFont(ControlPart, const Font&, float zoomFactor) const; + + virtual LengthSize controlSize(ControlPart, const Font&, const LengthSize&, float zoomFactor) const; + virtual LengthSize minimumControlSize(ControlPart, const Font&, float zoomFactor) const; + + virtual LengthBox controlPadding(ControlPart, const Font&, const LengthBox& zoomedBox, float zoomFactor) const; + virtual LengthBox controlBorder(ControlPart, const Font&, const LengthBox& zoomedBox, float zoomFactor) const; + + virtual bool controlRequiresPreWhiteSpace(ControlPart part) const { return part == PushButtonPart; } + + virtual void paint(ControlPart, ControlStates, GraphicsContext*, const IntRect&, float zoomFactor, ScrollView*) const; + virtual void inflateControlPaintRect(ControlPart, ControlStates, IntRect&, float zoomFactor) const; +}; + +} // namespace WebCore + +#endif // ThemeChromiumMac_h diff --git a/WebCore/platform/chromium/ThemeChromiumMac.mm b/WebCore/platform/chromium/ThemeChromiumMac.mm new file mode 100644 index 0000000..3c97428 --- /dev/null +++ b/WebCore/platform/chromium/ThemeChromiumMac.mm @@ -0,0 +1,569 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2009 Google Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "ThemeChromiumMac.h" + +#import "BlockExceptions.h" +#import "GraphicsContext.h" +#import "LocalCurrentGraphicsContext.h" +#import "ScrollView.h" +#import "WebCoreSystemInterface.h" +#include <wtf/StdLibExtras.h> + +using namespace std; + +// This file (and its associated .h file) is a clone of ThemeMac.mm. +// Because the original file is designed to run in-process inside a Cocoa view, +// we must maintain a fork. Please maintain this file by performing parallel +// changes to it. +// +// The only changes from ThemeMac should be: +// - The classname change from ThemeMac to ThemeChromiumMac. +// - The import of FlippedView() and its use as the parent view for cell +// rendering. +// - In updateStates() the code to update the cells' inactive state. +// - In paintButton() the code to save/restore the window's default button cell. +// +// For all other differences, if it was introduced in this file, then the +// maintainer forgot to include it in the list; otherwise it is an update that +// should have been applied to this file but was not. + +// FIXME: Default buttons really should be more like push buttons and not like buttons. + +namespace WebCore { + +// Pick up utility function from RenderThemeChromiumMac. +extern NSView* FlippedView(); + +enum { + topMargin, + rightMargin, + bottomMargin, + leftMargin +}; + +Theme* platformTheme() +{ + DEFINE_STATIC_LOCAL(ThemeChromiumMac, themeMac, ()); + return &themeMac; +} + +// Helper functions used by a bunch of different control parts. + +static NSControlSize controlSizeForFont(const Font& font) +{ + int fontSize = font.pixelSize(); + if (fontSize >= 16) + return NSRegularControlSize; + if (fontSize >= 11) + return NSSmallControlSize; + return NSMiniControlSize; +} + +static LengthSize sizeFromFont(const Font& font, const LengthSize& zoomedSize, float zoomFactor, const IntSize* sizes) +{ + IntSize controlSize = sizes[controlSizeForFont(font)]; + if (zoomFactor != 1.0f) + controlSize = IntSize(controlSize.width() * zoomFactor, controlSize.height() * zoomFactor); + LengthSize result = zoomedSize; + if (zoomedSize.width().isIntrinsicOrAuto() && controlSize.width() > 0) + result.setWidth(Length(controlSize.width(), Fixed)); + if (zoomedSize.height().isIntrinsicOrAuto() && controlSize.height() > 0) + result.setHeight(Length(controlSize.height(), Fixed)); + return result; +} + +static void setControlSize(NSCell* cell, const IntSize* sizes, const IntSize& minZoomedSize, float zoomFactor) +{ + NSControlSize size; + if (minZoomedSize.width() >= static_cast<int>(sizes[NSRegularControlSize].width() * zoomFactor) && + minZoomedSize.height() >= static_cast<int>(sizes[NSRegularControlSize].height() * zoomFactor)) + size = NSRegularControlSize; + else if (minZoomedSize.width() >= static_cast<int>(sizes[NSSmallControlSize].width() * zoomFactor) && + minZoomedSize.height() >= static_cast<int>(sizes[NSSmallControlSize].height() * zoomFactor)) + size = NSSmallControlSize; + else + size = NSMiniControlSize; + if (size != [cell controlSize]) // Only update if we have to, since AppKit does work even if the size is the same. + [cell setControlSize:size]; +} + +static void updateStates(NSCell* cell, ControlStates states) +{ + // Hover state is not supported by Aqua. + + // Pressed state + bool oldPressed = [cell isHighlighted]; + bool pressed = states & PressedState; + if (pressed != oldPressed) + [cell setHighlighted:pressed]; + + // Enabled state + bool oldEnabled = [cell isEnabled]; + bool enabled = states & EnabledState; + if (enabled != oldEnabled) + [cell setEnabled:enabled]; + + // Focused state + bool oldFocused = [cell showsFirstResponder]; + bool focused = states & FocusState; + if (focused != oldFocused) + [cell setShowsFirstResponder:focused]; + + // Checked and Indeterminate + bool oldIndeterminate = [cell state] == NSMixedState; + bool indeterminate = (states & IndeterminateState); + bool checked = states & CheckedState; + bool oldChecked = [cell state] == NSOnState; + if (oldIndeterminate != indeterminate || checked != oldChecked) + [cell setState:indeterminate ? NSMixedState : (checked ? NSOnState : NSOffState)]; + + // Window Inactive state + NSControlTint oldTint = [cell controlTint]; + bool windowInactive = (states & WindowInactiveState); + NSControlTint tint = windowInactive ? NSClearControlTint : [NSColor currentControlTint]; + if (tint != oldTint) + [cell setControlTint:tint]; +} + +static IntRect inflateRect(const IntRect& zoomedRect, const IntSize& zoomedSize, const int* margins, float zoomFactor) +{ + // Only do the inflation if the available width/height are too small. Otherwise try to + // fit the glow/check space into the available box's width/height. + int widthDelta = zoomedRect.width() - (zoomedSize.width() + margins[leftMargin] * zoomFactor + margins[rightMargin] * zoomFactor); + int heightDelta = zoomedRect.height() - (zoomedSize.height() + margins[topMargin] * zoomFactor + margins[bottomMargin] * zoomFactor); + IntRect result(zoomedRect); + if (widthDelta < 0) { + result.setX(result.x() - margins[leftMargin] * zoomFactor); + result.setWidth(result.width() - widthDelta); + } + if (heightDelta < 0) { + result.setY(result.y() - margins[topMargin] * zoomFactor); + result.setHeight(result.height() - heightDelta); + } + return result; +} + +// Checkboxes + +static const IntSize* checkboxSizes() +{ + static const IntSize sizes[3] = { IntSize(14, 14), IntSize(12, 12), IntSize(10, 10) }; + return sizes; +} + +static const int* checkboxMargins(NSControlSize controlSize) +{ + static const int margins[3][4] = + { + { 3, 4, 4, 2 }, + { 4, 3, 3, 3 }, + { 4, 3, 3, 3 }, + }; + return margins[controlSize]; +} + +static LengthSize checkboxSize(const Font& font, const LengthSize& zoomedSize, float zoomFactor) +{ + // If the width and height are both specified, then we have nothing to do. + if (!zoomedSize.width().isIntrinsicOrAuto() && !zoomedSize.height().isIntrinsicOrAuto()) + return zoomedSize; + + // Use the font size to determine the intrinsic width of the control. + return sizeFromFont(font, zoomedSize, zoomFactor, checkboxSizes()); +} + +static NSButtonCell* checkbox(ControlStates states, const IntRect& zoomedRect, float zoomFactor) +{ + static NSButtonCell* checkboxCell; + if (!checkboxCell) { + checkboxCell = [[NSButtonCell alloc] init]; + [checkboxCell setButtonType:NSSwitchButton]; + [checkboxCell setTitle:nil]; + [checkboxCell setAllowsMixedState:YES]; + [checkboxCell setFocusRingType:NSFocusRingTypeExterior]; + } + + // Set the control size based off the rectangle we're painting into. + setControlSize(checkboxCell, checkboxSizes(), zoomedRect.size(), zoomFactor); + + // Update the various states we respond to. + updateStates(checkboxCell, states); + + return checkboxCell; +} + +// FIXME: Share more code with radio buttons. +static void paintCheckbox(ControlStates states, GraphicsContext* context, const IntRect& zoomedRect, float zoomFactor, ScrollView* scrollView) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + + // Determine the width and height needed for the control and prepare the cell for painting. + NSButtonCell* checkboxCell = checkbox(states, zoomedRect, zoomFactor); + + context->save(); + + NSControlSize controlSize = [checkboxCell controlSize]; + IntSize zoomedSize = checkboxSizes()[controlSize]; + zoomedSize.setWidth(zoomedSize.width() * zoomFactor); + zoomedSize.setHeight(zoomedSize.height() * zoomFactor); + IntRect inflatedRect = inflateRect(zoomedRect, zoomedSize, checkboxMargins(controlSize), zoomFactor); + + if (zoomFactor != 1.0f) { + inflatedRect.setWidth(inflatedRect.width() / zoomFactor); + inflatedRect.setHeight(inflatedRect.height() / zoomFactor); + context->translate(inflatedRect.x(), inflatedRect.y()); + context->scale(FloatSize(zoomFactor, zoomFactor)); + context->translate(-inflatedRect.x(), -inflatedRect.y()); + } + + [checkboxCell drawWithFrame:NSRect(inflatedRect) inView:FlippedView()]; + [checkboxCell setControlView:nil]; + + context->restore(); + + END_BLOCK_OBJC_EXCEPTIONS +} + +// Radio Buttons + +static const IntSize* radioSizes() +{ + static const IntSize sizes[3] = { IntSize(14, 15), IntSize(12, 13), IntSize(10, 10) }; + return sizes; +} + +static const int* radioMargins(NSControlSize controlSize) +{ + static const int margins[3][4] = + { + { 2, 2, 4, 2 }, + { 3, 2, 3, 2 }, + { 1, 0, 2, 0 }, + }; + return margins[controlSize]; +} + +static LengthSize radioSize(const Font& font, const LengthSize& zoomedSize, float zoomFactor) +{ + // If the width and height are both specified, then we have nothing to do. + if (!zoomedSize.width().isIntrinsicOrAuto() && !zoomedSize.height().isIntrinsicOrAuto()) + return zoomedSize; + + // Use the font size to determine the intrinsic width of the control. + return sizeFromFont(font, zoomedSize, zoomFactor, radioSizes()); +} + +static NSButtonCell* radio(ControlStates states, const IntRect& zoomedRect, float zoomFactor) +{ + static NSButtonCell* radioCell; + if (!radioCell) { + radioCell = [[NSButtonCell alloc] init]; + [radioCell setButtonType:NSRadioButton]; + [radioCell setTitle:nil]; + [radioCell setFocusRingType:NSFocusRingTypeExterior]; + } + + // Set the control size based off the rectangle we're painting into. + setControlSize(radioCell, radioSizes(), zoomedRect.size(), zoomFactor); + + // Update the various states we respond to. + updateStates(radioCell, states); + + return radioCell; +} + +static void paintRadio(ControlStates states, GraphicsContext* context, const IntRect& zoomedRect, float zoomFactor, ScrollView* scrollView) +{ + // Determine the width and height needed for the control and prepare the cell for painting. + NSButtonCell* radioCell = radio(states, zoomedRect, zoomFactor); + + context->save(); + + NSControlSize controlSize = [radioCell controlSize]; + IntSize zoomedSize = radioSizes()[controlSize]; + zoomedSize.setWidth(zoomedSize.width() * zoomFactor); + zoomedSize.setHeight(zoomedSize.height() * zoomFactor); + IntRect inflatedRect = inflateRect(zoomedRect, zoomedSize, radioMargins(controlSize), zoomFactor); + + if (zoomFactor != 1.0f) { + inflatedRect.setWidth(inflatedRect.width() / zoomFactor); + inflatedRect.setHeight(inflatedRect.height() / zoomFactor); + context->translate(inflatedRect.x(), inflatedRect.y()); + context->scale(FloatSize(zoomFactor, zoomFactor)); + context->translate(-inflatedRect.x(), -inflatedRect.y()); + } + + BEGIN_BLOCK_OBJC_EXCEPTIONS + [radioCell drawWithFrame:NSRect(inflatedRect) inView:FlippedView()]; + [radioCell setControlView:nil]; + END_BLOCK_OBJC_EXCEPTIONS + + context->restore(); +} + +// Buttons + +// Buttons really only constrain height. They respect width. +static const IntSize* buttonSizes() +{ + static const IntSize sizes[3] = { IntSize(0, 21), IntSize(0, 18), IntSize(0, 15) }; + return sizes; +} + +static const int* buttonMargins(NSControlSize controlSize) +{ + static const int margins[3][4] = + { + { 4, 6, 7, 6 }, + { 4, 5, 6, 5 }, + { 0, 1, 1, 1 }, + }; + return margins[controlSize]; +} + +static NSButtonCell* button(ControlPart part, ControlStates states, const IntRect& zoomedRect, float zoomFactor) +{ + static NSButtonCell *buttonCell; + static bool defaultButton; + if (!buttonCell) { + buttonCell = [[NSButtonCell alloc] init]; + [buttonCell setTitle:nil]; + [buttonCell setButtonType:NSMomentaryPushInButton]; + } + + // Set the control size based off the rectangle we're painting into. + if (part == SquareButtonPart || zoomedRect.height() > buttonSizes()[NSRegularControlSize].height() * zoomFactor) { + // Use the square button + if ([buttonCell bezelStyle] != NSShadowlessSquareBezelStyle) + [buttonCell setBezelStyle:NSShadowlessSquareBezelStyle]; + } else if ([buttonCell bezelStyle] != NSRoundedBezelStyle) + [buttonCell setBezelStyle:NSRoundedBezelStyle]; + + setControlSize(buttonCell, buttonSizes(), zoomedRect.size(), zoomFactor); + + if (defaultButton != (states & DefaultState)) { + defaultButton = !defaultButton; + [buttonCell setKeyEquivalent:(defaultButton ? @"\r" : @"")]; + } + + // Update the various states we respond to. + updateStates(buttonCell, states); + + return buttonCell; +} + +static void paintButton(ControlPart part, ControlStates states, GraphicsContext* context, const IntRect& zoomedRect, float zoomFactor, ScrollView* scrollView) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + + // Determine the width and height needed for the control and prepare the cell for painting. + NSButtonCell *buttonCell = button(part, states, zoomedRect, zoomFactor); + LocalCurrentGraphicsContext localContext(context); + + NSControlSize controlSize = [buttonCell controlSize]; + IntSize zoomedSize = buttonSizes()[controlSize]; + zoomedSize.setWidth(zoomedRect.width()); // Buttons don't ever constrain width, so the zoomed width can just be honored. + zoomedSize.setHeight(zoomedSize.height() * zoomFactor); + IntRect inflatedRect = zoomedRect; + if ([buttonCell bezelStyle] == NSRoundedBezelStyle) { + // Center the button within the available space. + if (inflatedRect.height() > zoomedSize.height()) { + inflatedRect.setY(inflatedRect.y() + (inflatedRect.height() - zoomedSize.height()) / 2); + inflatedRect.setHeight(zoomedSize.height()); + } + + // Now inflate it to account for the shadow. + inflatedRect = inflateRect(inflatedRect, zoomedSize, buttonMargins(controlSize), zoomFactor); + + if (zoomFactor != 1.0f) { + inflatedRect.setWidth(inflatedRect.width() / zoomFactor); + inflatedRect.setHeight(inflatedRect.height() / zoomFactor); + context->translate(inflatedRect.x(), inflatedRect.y()); + context->scale(FloatSize(zoomFactor, zoomFactor)); + context->translate(-inflatedRect.x(), -inflatedRect.y()); + } + } + + [buttonCell drawWithFrame:NSRect(inflatedRect) inView:FlippedView()]; + [buttonCell setControlView:nil]; + + END_BLOCK_OBJC_EXCEPTIONS +} + +// Theme overrides + +int ThemeChromiumMac::baselinePositionAdjustment(ControlPart part) const +{ + if (part == CheckboxPart || part == RadioPart) + return -2; + return Theme::baselinePositionAdjustment(part); +} + +FontDescription ThemeChromiumMac::controlFont(ControlPart part, const Font& font, float zoomFactor) const +{ + switch (part) { + case PushButtonPart: { + FontDescription fontDescription; + fontDescription.setIsAbsoluteSize(true); + fontDescription.setGenericFamily(FontDescription::SerifFamily); + + NSFont* nsFont = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:controlSizeForFont(font)]]; + fontDescription.firstFamily().setFamily([nsFont familyName]); + fontDescription.setComputedSize([nsFont pointSize] * zoomFactor); + fontDescription.setSpecifiedSize([nsFont pointSize] * zoomFactor); + return fontDescription; + } + default: + return Theme::controlFont(part, font, zoomFactor); + } +} + +LengthSize ThemeChromiumMac::controlSize(ControlPart part, const Font& font, const LengthSize& zoomedSize, float zoomFactor) const +{ + switch (part) { + case CheckboxPart: + return checkboxSize(font, zoomedSize, zoomFactor); + case RadioPart: + return radioSize(font, zoomedSize, zoomFactor); + case PushButtonPart: + // Height is reset to auto so that specified heights can be ignored. + return sizeFromFont(font, LengthSize(zoomedSize.width(), Length()), zoomFactor, buttonSizes()); + default: + return zoomedSize; + } +} + +LengthSize ThemeChromiumMac::minimumControlSize(ControlPart part, const Font& font, float zoomFactor) const +{ + switch (part) { + case SquareButtonPart: + case DefaultButtonPart: + case ButtonPart: + return LengthSize(Length(0, Fixed), Length(static_cast<int>(15 * zoomFactor), Fixed)); + default: + return Theme::minimumControlSize(part, font, zoomFactor); + } +} + +LengthBox ThemeChromiumMac::controlBorder(ControlPart part, const Font& font, const LengthBox& zoomedBox, float zoomFactor) const +{ + switch (part) { + case SquareButtonPart: + case DefaultButtonPart: + case ButtonPart: + return LengthBox(0, zoomedBox.right().value(), 0, zoomedBox.left().value()); + default: + return Theme::controlBorder(part, font, zoomedBox, zoomFactor); + } +} + +LengthBox ThemeChromiumMac::controlPadding(ControlPart part, const Font& font, const LengthBox& zoomedBox, float zoomFactor) const +{ + switch (part) { + case PushButtonPart: { + // Just use 8px. AppKit wants to use 11px for mini buttons, but that padding is just too large + // for real-world Web sites (creating a huge necessary minimum width for buttons whose space is + // by definition constrained, since we select mini only for small cramped environments. + // This also guarantees the HTML <button> will match our rendering by default, since we're using a consistent + // padding. + const int padding = 8 * zoomFactor; + return LengthBox(0, padding, 0, padding); + } + default: + return Theme::controlPadding(part, font, zoomedBox, zoomFactor); + } +} + +void ThemeChromiumMac::inflateControlPaintRect(ControlPart part, ControlStates states, IntRect& zoomedRect, float zoomFactor) const +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + switch (part) { + case CheckboxPart: { + // We inflate the rect as needed to account for padding included in the cell to accommodate the checkbox + // shadow" and the check. We don't consider this part of the bounds of the control in WebKit. + NSCell *cell = checkbox(states, zoomedRect, zoomFactor); + NSControlSize controlSize = [cell controlSize]; + IntSize zoomedSize = checkboxSizes()[controlSize]; + zoomedSize.setHeight(zoomedSize.height() * zoomFactor); + zoomedSize.setWidth(zoomedSize.width() * zoomFactor); + zoomedRect = inflateRect(zoomedRect, zoomedSize, checkboxMargins(controlSize), zoomFactor); + break; + } + case RadioPart: { + // We inflate the rect as needed to account for padding included in the cell to accommodate the radio button + // shadow". We don't consider this part of the bounds of the control in WebKit. + NSCell *cell = radio(states, zoomedRect, zoomFactor); + NSControlSize controlSize = [cell controlSize]; + IntSize zoomedSize = radioSizes()[controlSize]; + zoomedSize.setHeight(zoomedSize.height() * zoomFactor); + zoomedSize.setWidth(zoomedSize.width() * zoomFactor); + zoomedRect = inflateRect(zoomedRect, zoomedSize, radioMargins(controlSize), zoomFactor); + break; + } + case PushButtonPart: + case DefaultButtonPart: + case ButtonPart: { + NSButtonCell *cell = button(part, states, zoomedRect, zoomFactor); + NSControlSize controlSize = [cell controlSize]; + + // We inflate the rect as needed to account for the Aqua button's shadow. + if ([cell bezelStyle] == NSRoundedBezelStyle) { + IntSize zoomedSize = buttonSizes()[controlSize]; + zoomedSize.setHeight(zoomedSize.height() * zoomFactor); + zoomedSize.setWidth(zoomedRect.width()); // Buttons don't ever constrain width, so the zoomed width can just be honored. + zoomedRect = inflateRect(zoomedRect, zoomedSize, buttonMargins(controlSize), zoomFactor); + } + break; + } + default: + break; + } + END_BLOCK_OBJC_EXCEPTIONS +} + +void ThemeChromiumMac::paint(ControlPart part, ControlStates states, GraphicsContext* context, const IntRect& zoomedRect, float zoomFactor, ScrollView* scrollView) const +{ + switch (part) { + case CheckboxPart: + paintCheckbox(states, context, zoomedRect, zoomFactor, scrollView); + break; + case RadioPart: + paintRadio(states, context, zoomedRect, zoomFactor, scrollView); + break; + case PushButtonPart: + case DefaultButtonPart: + case ButtonPart: + case SquareButtonPart: + paintButton(part, states, context, zoomedRect, zoomFactor, scrollView); + break; + default: + break; + } +} + +} diff --git a/WebCore/platform/graphics/BitmapImage.h b/WebCore/platform/graphics/BitmapImage.h index 807c11b..13641d2 100644 --- a/WebCore/platform/graphics/BitmapImage.h +++ b/WebCore/platform/graphics/BitmapImage.h @@ -45,6 +45,10 @@ class NSImage; typedef struct HBITMAP__ *HBITMAP; #endif +#if PLATFORM(HAIKU) +class BBitmap; +#endif + namespace WebCore { struct FrameData; } @@ -137,6 +141,7 @@ public: #endif #if PLATFORM(WIN) + static PassRefPtr<BitmapImage> create(HBITMAP); virtual bool getHBITMAP(HBITMAP); virtual bool getHBITMAPOfSize(HBITMAP, LPSIZE); #endif @@ -165,10 +170,16 @@ protected: virtual void drawFrameMatchingSourceSize(GraphicsContext*, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator); #endif virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); -#if PLATFORM(WX) || PLATFORM(WINCE) + +#if PLATFORM(WX) || (PLATFORM(WINCE) && !PLATFORM(QT)) virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator, const FloatRect& destRect); -#endif +#endif + +#if PLATFORM(HAIKU) + virtual BBitmap* getBBitmap() const; +#endif + size_t currentFrame() const { return m_currentFrame; } size_t frameCount(); NativeImagePtr frameAtIndex(size_t); diff --git a/WebCore/platform/graphics/Color.h b/WebCore/platform/graphics/Color.h index 5baa56e..8e51b95 100644 --- a/WebCore/platform/graphics/Color.h +++ b/WebCore/platform/graphics/Color.h @@ -47,6 +47,10 @@ typedef struct _GdkColor GdkColor; class wxColour; #endif +#if PLATFORM(HAIKU) +struct rgb_color; +#endif + namespace WebCore { class String; @@ -121,6 +125,11 @@ public: Color(CGColorRef); #endif +#if PLATFORM(HAIKU) + Color(const rgb_color&); + operator rgb_color() const; +#endif + static bool parseHexColor(const String& name, RGBA32& rgb); static const RGBA32 black = 0xFF000000; diff --git a/WebCore/platform/graphics/FloatPoint.h b/WebCore/platform/graphics/FloatPoint.h index 0c97c49..06b280b 100644 --- a/WebCore/platform/graphics/FloatPoint.h +++ b/WebCore/platform/graphics/FloatPoint.h @@ -36,7 +36,7 @@ typedef struct CGPoint CGPoint; #endif -#if PLATFORM(MAC) +#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) #ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES typedef struct CGPoint NSPoint; #else @@ -51,6 +51,10 @@ class QPointF; QT_END_NAMESPACE #endif +#if PLATFORM(HAIKU) +class BPoint; +#endif + #if PLATFORM(SKIA) struct SkPoint; #endif @@ -80,7 +84,8 @@ public: operator CGPoint() const; #endif -#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES) +#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \ + || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) FloatPoint(const NSPoint&); operator NSPoint() const; #endif @@ -90,7 +95,16 @@ public: operator QPointF() const; #endif +<<<<<<< HEAD:WebCore/platform/graphics/FloatPoint.h #if (PLATFORM(SKIA) || PLATFORM(SGL)) +======= +#if PLATFORM(HAIKU) + FloatPoint(const BPoint&); + operator BPoint() const; +#endif + +#if PLATFORM(SKIA) +>>>>>>> webkit.org at 49305:WebCore/platform/graphics/FloatPoint.h operator SkPoint() const; FloatPoint(const SkPoint&); #endif diff --git a/WebCore/platform/graphics/FloatRect.h b/WebCore/platform/graphics/FloatRect.h index e906812..704241a 100644 --- a/WebCore/platform/graphics/FloatRect.h +++ b/WebCore/platform/graphics/FloatRect.h @@ -33,7 +33,7 @@ typedef struct CGRect CGRect; #endif -#if PLATFORM(MAC) +#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) #ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES typedef struct CGRect NSRect; #else @@ -51,7 +51,15 @@ QT_END_NAMESPACE class wxRect2DDouble; #endif +<<<<<<< HEAD:WebCore/platform/graphics/FloatRect.h #if (PLATFORM(SKIA) || PLATFORM(SGL)) +======= +#if PLATFORM(HAIKU) +class BRect; +#endif + +#if PLATFORM(SKIA) +>>>>>>> webkit.org at 49305:WebCore/platform/graphics/FloatRect.h struct SkRect; #endif @@ -123,7 +131,8 @@ public: operator CGRect() const; #endif -#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES) +#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \ + || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) FloatRect(const NSRect&); operator NSRect() const; #endif @@ -138,7 +147,16 @@ public: operator wxRect2DDouble() const; #endif +<<<<<<< HEAD:WebCore/platform/graphics/FloatRect.h #if (PLATFORM(SKIA) || PLATFORM(SGL)) +======= +#if PLATFORM(HAIKU) + FloatRect(const BRect&); + operator BRect() const; +#endif + +#if PLATFORM(SKIA) +>>>>>>> webkit.org at 49305:WebCore/platform/graphics/FloatRect.h FloatRect(const SkRect&); operator SkRect() const; #endif diff --git a/WebCore/platform/graphics/FloatSize.h b/WebCore/platform/graphics/FloatSize.h index 6e792b6..5a84fd1 100644 --- a/WebCore/platform/graphics/FloatSize.h +++ b/WebCore/platform/graphics/FloatSize.h @@ -34,7 +34,7 @@ typedef struct CGSize CGSize; #endif -#if PLATFORM(MAC) +#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) #ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES typedef struct CGSize NSSize; #else @@ -79,7 +79,8 @@ public: operator CGSize() const; #endif -#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES) +#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \ + || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) explicit FloatSize(const NSSize &); // don't do this implicitly since it's lossy operator NSSize() const; #endif diff --git a/WebCore/platform/graphics/FontCache.h b/WebCore/platform/graphics/FontCache.h index 3c0f2d9..b88305f 100644 --- a/WebCore/platform/graphics/FontCache.h +++ b/WebCore/platform/graphics/FontCache.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2006, 2008 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2007-2008 Torch Mobile, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -63,7 +64,15 @@ public: // Also implemented by the platform. void platformInit(); -#if PLATFORM(WIN) +#if PLATFORM(WINCE) && !PLATFORM(QT) +#if defined(IMLANG_FONT_LINK) && (IMLANG_FONT_LINK == 2) + IMLangFontLink2* getFontLinkInterface(); +#else + IMLangFontLink* getFontLinkInterface(); +#endif + static void comInitialize(); + static void comUninitialize(); +#elif PLATFORM(WIN) IMLangFontLink2* getFontLinkInterface(); #endif diff --git a/WebCore/platform/graphics/FontDescription.h b/WebCore/platform/graphics/FontDescription.h index c893b8a..fc63db9 100644 --- a/WebCore/platform/graphics/FontDescription.h +++ b/WebCore/platform/graphics/FontDescription.h @@ -27,7 +27,9 @@ #include "FontFamily.h" #include "FontRenderingMode.h" +#include "FontSmoothingMode.h" #include "FontTraitsMask.h" +#include "TextRenderingMode.h" namespace WebCore { @@ -61,6 +63,8 @@ public: , m_usePrinterFont(false) , m_renderingMode(NormalRenderingMode) , m_keywordSize(0) + , m_fontSmoothing(AutoSmoothing) + , m_textRendering(AutoTextRendering) { } @@ -80,8 +84,12 @@ public: FontWeight bolderWeight() const; GenericFamilyType genericFamily() const { return static_cast<GenericFamilyType>(m_genericFamily); } bool usePrinterFont() const { return m_usePrinterFont; } + // only use fixed default size when there is only one font family, and that family is "monospace" + bool useFixedDefaultSize() const { return genericFamily() == MonospaceFamily && !family().next() && family().family() == "-webkit-monospace"; } FontRenderingMode renderingMode() const { return static_cast<FontRenderingMode>(m_renderingMode); } unsigned keywordSize() const { return m_keywordSize; } + FontSmoothingMode fontSmoothing() const { return static_cast<FontSmoothingMode>(m_fontSmoothing); } + TextRenderingMode textRenderingMode() const { return static_cast<TextRenderingMode>(m_textRendering); } FontTraitsMask traitsMask() const; @@ -96,6 +104,8 @@ public: void setUsePrinterFont(bool p) { m_usePrinterFont = p; } void setRenderingMode(FontRenderingMode mode) { m_renderingMode = mode; } void setKeywordSize(unsigned s) { m_keywordSize = s; } + void setFontSmoothing(FontSmoothingMode smoothing) { m_fontSmoothing = smoothing; } + void setTextRenderingMode(TextRenderingMode rendering) { m_textRendering = rendering; } private: FontFamily m_familyList; // The list of font families to be used. @@ -117,6 +127,9 @@ private: unsigned m_keywordSize : 4; // We cache whether or not a font is currently represented by a CSS keyword (e.g., medium). If so, // then we can accurately translate across different generic families to adjust for different preference settings // (e.g., 13px monospace vs. 16px everything else). Sizes are 1-8 (like the HTML size values for <font>). + + unsigned m_fontSmoothing : 2; // FontSmoothingMode + unsigned m_textRendering : 2; // TextRenderingMode }; inline bool FontDescription::operator==(const FontDescription& other) const @@ -131,7 +144,9 @@ inline bool FontDescription::operator==(const FontDescription& other) const && m_genericFamily == other.m_genericFamily && m_usePrinterFont == other.m_usePrinterFont && m_renderingMode == other.m_renderingMode - && m_keywordSize == other.m_keywordSize; + && m_keywordSize == other.m_keywordSize + && m_fontSmoothing == other.m_fontSmoothing + && m_textRendering == other.m_textRendering; } } diff --git a/WebCore/platform/graphics/FontFastPath.cpp b/WebCore/platform/graphics/FontFastPath.cpp index b0e39db..5246593 100644 --- a/WebCore/platform/graphics/FontFastPath.cpp +++ b/WebCore/platform/graphics/FontFastPath.cpp @@ -251,6 +251,10 @@ bool Font::canUseGlyphCache(const TextRun& run) const return false; } + TextRenderingMode textMode = m_fontDescription.textRenderingMode(); + if (textMode == OptimizeLegibility || textMode == GeometricPrecision) + return false; + return true; } diff --git a/WebCore/platform/graphics/FontSmoothingMode.h b/WebCore/platform/graphics/FontSmoothingMode.h new file mode 100644 index 0000000..7c23394 --- /dev/null +++ b/WebCore/platform/graphics/FontSmoothingMode.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FontSmoothingMode_h +#define FontSmoothingMode_h + +namespace WebCore { + + enum FontSmoothingMode { AutoSmoothing, NoSmoothing, Antialiased, SubpixelAntialiased }; + +} // namespace WebCore + +#endif // FontSmoothingMode_h diff --git a/WebCore/platform/graphics/GlyphPageTreeNode.cpp b/WebCore/platform/graphics/GlyphPageTreeNode.cpp index 6419e0c..9f53f0b 100644 --- a/WebCore/platform/graphics/GlyphPageTreeNode.cpp +++ b/WebCore/platform/graphics/GlyphPageTreeNode.cpp @@ -202,8 +202,10 @@ void GlyphPageTreeNode::initializePage(const FontData* fontData, unsigned pageNu GlyphPage* pageToFill = m_page.get(); for (unsigned i = 0; i < numRanges; i++) { const FontDataRange& range = segmentedFontData->rangeAt(i); - int from = max(0, range.from() - static_cast<int>(start)); - int to = 1 + min(range.to() - static_cast<int>(start), static_cast<int>(GlyphPage::size) - 1); + // all this casting is to ensure all the parameters to min and max have the same type, + // to avoid ambiguous template parameter errors on Windows + int from = max(0, static_cast<int>(range.from()) - static_cast<int>(start)); + int to = 1 + min(static_cast<int>(range.to()) - static_cast<int>(start), static_cast<int>(GlyphPage::size) - 1); if (from < static_cast<int>(GlyphPage::size) && to > 0) { if (haveGlyphs && !scratchPage) { scratchPage = GlyphPage::create(this); diff --git a/WebCore/platform/graphics/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp index a4e8408..ccdce08 100644 --- a/WebCore/platform/graphics/GraphicsContext.cpp +++ b/WebCore/platform/graphics/GraphicsContext.cpp @@ -27,9 +27,9 @@ #include "GraphicsContext.h" #include "BidiResolver.h" +#include "Font.h" #include "Generator.h" #include "GraphicsContextPrivate.h" -#include "Font.h" using namespace std; @@ -89,7 +89,7 @@ void GraphicsContext::save() return; m_common->stack.append(m_common->state); - + savePlatformState(); } @@ -104,7 +104,7 @@ void GraphicsContext::restore() } m_common->state = m_common->stack.last(); m_common->stack.removeLast(); - + restorePlatformState(); } @@ -305,7 +305,7 @@ bool GraphicsContext::paintingDisabled() const } void GraphicsContext::drawImage(Image* image, const IntPoint& p, CompositeOperator op) -{ +{ drawImage(image, p, IntRect(0, 0, -1, -1), op); } @@ -329,7 +329,7 @@ void GraphicsContext::drawText(const Font& font, const TextRun& run, const IntPo { if (paintingDisabled()) return; - + font.drawText(this, run, point, from, to); } #endif @@ -383,7 +383,7 @@ void GraphicsContext::initFocusRing(int width, int offset) if (paintingDisabled()) return; clearFocusRing(); - + m_common->m_focusRingWidth = width; m_common->m_focusRingOffset = offset; } @@ -396,12 +396,12 @@ void GraphicsContext::clearFocusRing() IntRect GraphicsContext::focusRingBoundingRect() { IntRect result = IntRect(0, 0, 0, 0); - + const Vector<IntRect>& rects = focusRingRects(); unsigned rectCount = rects.size(); for (unsigned i = 0; i < rectCount; i++) result.unite(rects[i]); - + return result; } @@ -436,7 +436,7 @@ void GraphicsContext::drawImage(Image* image, const FloatRect& dest, const Float float tsh = src.height(); float tw = dest.width(); float th = dest.height(); - + if (tsw == -1) tsw = image->width(); if (tsh == -1) @@ -540,10 +540,39 @@ void GraphicsContext::setPlatformTextDrawingMode(int mode) } #endif -#if !PLATFORM(QT) && !PLATFORM(CAIRO) && !PLATFORM(SKIA) +#if !PLATFORM(QT) && !PLATFORM(CAIRO) && !PLATFORM(SKIA) && !PLATFORM(HAIKU) void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle&) { } #endif +void GraphicsContext::adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, const StrokeStyle& penStyle) +{ + // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic + // works out. For example, with a border width of 3, WebKit will pass us (y1+y2)/2, e.g., + // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave + // us a perfect position, but an odd width gave us a position that is off by exactly 0.5. + if (penStyle == DottedStroke || penStyle == DashedStroke) { + if (p1.x() == p2.x()) { + p1.setY(p1.y() + strokeWidth); + p2.setY(p2.y() - strokeWidth); + } else { + p1.setX(p1.x() + strokeWidth); + p2.setX(p2.x() - strokeWidth); + } + } + + if (static_cast<int>(strokeWidth) % 2) { //odd + if (p1.x() == p2.x()) { + // We're a vertical line. Adjust our x. + p1.setX(p1.x() + 0.5f); + p2.setX(p2.x() + 0.5f); + } else { + // We're a horizontal line. Adjust our y. + p1.setY(p1.y() + 0.5f); + p2.setY(p2.y() + 0.5f); + } + } +} + } diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h index 233c14c..b1d1ef9 100644 --- a/WebCore/platform/graphics/GraphicsContext.h +++ b/WebCore/platform/graphics/GraphicsContext.h @@ -55,8 +55,8 @@ struct SkPoint; class wxGCDC; class wxWindowDC; -// wxGraphicsContext allows us to support Path, etc. -// but on some platforms, e.g. Linux, it requires fairly +// wxGraphicsContext allows us to support Path, etc. +// but on some platforms, e.g. Linux, it requires fairly // new software. #if USE(WXGC) // On OS X, wxGCDC is just a typedef for wxDC, so use wxDC explicitly to make @@ -72,6 +72,10 @@ class wxWindowDC; #endif #elif PLATFORM(SKIA) typedef class PlatformContextSkia PlatformGraphicsContext; +#elif PLATFORM(HAIKU) +class BView; +typedef BView PlatformGraphicsContext; +struct pattern; #elif PLATFORM(WINCE) typedef struct HDC__ PlatformGraphicsContext; #else @@ -124,7 +128,7 @@ namespace WebCore { const int cTextFill = 1; const int cTextStroke = 2; const int cTextClip = 4; - + enum StrokeStyle { NoStroke, SolidStroke, @@ -132,12 +136,12 @@ namespace WebCore { DashedStroke }; -// FIXME: This is a place-holder until we decide to add -// real color space support to WebCore. At that time, ColorSpace will be a -// class and instances will be held off of Colors. There will be -// special singleton Gradient and Pattern color spaces to mark when -// a fill or stroke is using a gradient or pattern instead of a solid color. -// https://bugs.webkit.org/show_bug.cgi?id=20558 + // FIXME: This is a place-holder until we decide to add + // real color space support to WebCore. At that time, ColorSpace will be a + // class and instances will be held off of Colors. There will be + // special singleton Gradient and Pattern color spaces to mark when + // a fill or stroke is using a gradient or pattern instead of a solid color. + // https://bugs.webkit.org/show_bug.cgi?id=20558 enum ColorSpace { SolidColorSpace, PatternColorSpace, @@ -156,11 +160,11 @@ namespace WebCore { public: GraphicsContext(PlatformGraphicsContext*); ~GraphicsContext(); - + #if !PLATFORM(WINCE) || PLATFORM(QT) PlatformGraphicsContext* platformContext() const; #endif - + float strokeThickness() const; void setStrokeThickness(float); StrokeStyle strokeStyle() const; @@ -267,7 +271,7 @@ namespace WebCore { CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false); void drawTiledImage(Image*, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize, CompositeOperator = CompositeSourceOver); - void drawTiledImage(Image*, const IntRect& destRect, const IntRect& srcRect, + void drawTiledImage(Image*, const IntRect& destRect, const IntRect& srcRect, Image::TileRule hRule = Image::StretchTile, Image::TileRule vRule = Image::StretchTile, CompositeOperator = CompositeSourceOver); @@ -291,13 +295,13 @@ namespace WebCore { void drawHighlightForText(const Font&, const TextRun&, const IntPoint&, int h, const Color& backgroundColor, int from = 0, int to = -1); FloatRect roundToDevicePixels(const FloatRect&); - + void drawLineForText(const IntPoint&, int width, bool printing); void drawLineForMisspellingOrBadGrammar(const IntPoint&, int width, bool grammar); - + bool paintingDisabled() const; void setPaintingDisabled(bool); - + bool updatingControlTints() const; void setUpdatingControlTints(bool); @@ -336,7 +340,7 @@ namespace WebCore { void rotate(float angleInRadians); void translate(float x, float y); IntPoint origin(); - + void setURLForRect(const KURL&, const IntRect&); void concatCTM(const TransformationMatrix&); @@ -418,6 +422,10 @@ namespace WebCore { GdkEventExpose* gdkExposeEvent() const; #endif +#if PLATFORM(HAIKU) + pattern getHaikuStrokeStyle(); +#endif + private: void savePlatformState(); void restorePlatformState(); @@ -440,6 +448,8 @@ namespace WebCore { void setPlatformShadow(const IntSize&, int blur, const Color&); void clearPlatformShadow(); + static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, const StrokeStyle&); + int focusRingWidth() const; int focusRingOffset() const; const Vector<IntRect>& focusRingRects() const; diff --git a/WebCore/platform/graphics/GraphicsContext3D.h b/WebCore/platform/graphics/GraphicsContext3D.h new file mode 100644 index 0000000..5223e05 --- /dev/null +++ b/WebCore/platform/graphics/GraphicsContext3D.h @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2009 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 GraphicsContext3D_h +#define GraphicsContext3D_h + +#include "PlatformString.h" + +#include <wtf/Noncopyable.h> + +#if PLATFORM(MAC) +#include <OpenGL/OpenGL.h> + +typedef void* PlatformGraphicsContext3D; +const PlatformGraphicsContext3D NullPlatformGraphicsContext3D = 0; +typedef GLuint Platform3DObject; +const Platform3DObject NullPlatform3DObject = 0; +#else +typedef void* PlatformGraphicsContext3D; +const PlatformGraphicsContext3D NullPlatformGraphicsContext3D = 0; +typedef int Platform3DObject; +const Platform3DObject NullPlatform3DObject = 0; +#endif + +namespace WebCore { + class CanvasArray; + class CanvasBuffer; + class CanvasUnsignedByteArray; + class CanvasFloatArray; + class CanvasFramebuffer; + class CanvasIntArray; + class CanvasProgram; + class CanvasRenderbuffer; + class CanvasRenderingContext3D; + class CanvasShader; + class CanvasTexture; + class HTMLCanvasElement; + class HTMLImageElement; + class HTMLVideoElement; + class ImageData; + class WebKitCSSMatrix; + + // FIXME: ideally this would be used on all platforms. +#if PLATFORM(CHROMIUM) + class GraphicsContext3DInternal; +#endif + + class GraphicsContext3D : Noncopyable { + public: + enum ShaderType { FRAGMENT_SHADER, VERTEX_SHADER }; + + GraphicsContext3D(); + virtual ~GraphicsContext3D(); + +#if PLATFORM(MAC) + PlatformGraphicsContext3D platformGraphicsContext3D() const { return m_contextObj; } + Platform3DObject platformTexture() const { return m_texture; } +#elif PLATFORM(CHROMIUM) + PlatformGraphicsContext3D platformGraphicsContext3D() const; + Platform3DObject platformTexture() const; +#else + PlatformGraphicsContext3D platformGraphicsContext3D() const { return NullPlatformGraphicsContext3D; } + Platform3DObject platformTexture() const { return NullPlatform3DObject; } +#endif + void checkError() const; + + void makeContextCurrent(); + + // Helper to return the size in bytes of OpenGL data types + // like GL_FLOAT, GL_INT, etc. + int sizeInBytes(int type); + + void activeTexture(unsigned long texture); + void attachShader(CanvasProgram* program, CanvasShader* shader); + void bindAttribLocation(CanvasProgram*, unsigned long index, const String& name); + void bindBuffer(unsigned long target, CanvasBuffer*); + void bindFramebuffer(unsigned long target, CanvasFramebuffer*); + void bindRenderbuffer(unsigned long target, CanvasRenderbuffer*); + void bindTexture(unsigned long target, CanvasTexture* texture); + void blendColor(double red, double green, double blue, double alpha); + void blendEquation(unsigned long mode); + void blendEquationSeparate(unsigned long modeRGB, unsigned long modeAlpha); + void blendFunc(unsigned long sfactor, unsigned long dfactor); + void blendFuncSeparate(unsigned long srcRGB, unsigned long dstRGB, unsigned long srcAlpha, unsigned long dstAlpha); + + void bufferData(unsigned long target, int size, unsigned long usage); + void bufferData(unsigned long target, CanvasArray* data, unsigned long usage); + void bufferSubData(unsigned long target, long offset, CanvasArray* data); + + unsigned long checkFramebufferStatus(unsigned long target); + void clear(unsigned long mask); + void clearColor(double red, double green, double blue, double alpha); + void clearDepth(double depth); + void clearStencil(long s); + void colorMask(bool red, bool green, bool blue, bool alpha); + void compileShader(CanvasShader*); + + //void compressedTexImage2D(unsigned long target, long level, unsigned long internalformat, unsigned long width, unsigned long height, long border, unsigned long imageSize, const void* data); + //void compressedTexSubImage2D(unsigned long target, long level, long xoffset, long yoffset, unsigned long width, unsigned long height, unsigned long format, unsigned long imageSize, const void* data); + + void copyTexImage2D(unsigned long target, long level, unsigned long internalformat, long x, long y, unsigned long width, unsigned long height, long border); + void copyTexSubImage2D(unsigned long target, long level, long xoffset, long yoffset, long x, long y, unsigned long width, unsigned long height); + void cullFace(unsigned long mode); + void depthFunc(unsigned long func); + void depthMask(bool flag); + void depthRange(double zNear, double zFar); + void detachShader(CanvasProgram*, CanvasShader*); + void disable(unsigned long cap); + void disableVertexAttribArray(unsigned long index); + void drawArrays(unsigned long mode, long first, long count); + void drawElements(unsigned long mode, unsigned long count, unsigned long type, long offset); + + void enable(unsigned long cap); + void enableVertexAttribArray(unsigned long index); + void finish(); + void flush(); + void framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, CanvasRenderbuffer*); + void framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, CanvasTexture*, long level); + void frontFace(unsigned long mode); + void generateMipmap(unsigned long target); + + int getAttribLocation(CanvasProgram*, const String& name); + + bool getBoolean(unsigned long pname); + PassRefPtr<CanvasUnsignedByteArray> getBooleanv(unsigned long pname); + int getBufferParameteri(unsigned long target, unsigned long pname); + PassRefPtr<CanvasIntArray> getBufferParameteriv(unsigned long target, unsigned long pname); + + unsigned long getError(); + + float getFloat(unsigned long pname); + PassRefPtr<CanvasFloatArray> getFloatv(unsigned long pname); + int getFramebufferAttachmentParameteri(unsigned long target, unsigned long attachment, unsigned long pname); + PassRefPtr<CanvasIntArray> getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long pname); + int getInteger(unsigned long pname); + PassRefPtr<CanvasIntArray> getIntegerv(unsigned long pname); + int getProgrami(CanvasProgram*, unsigned long pname); + PassRefPtr<CanvasIntArray> getProgramiv(CanvasProgram*, unsigned long pname); + String getProgramInfoLog(CanvasProgram*); + int getRenderbufferParameteri(unsigned long target, unsigned long pname); + PassRefPtr<CanvasIntArray> getRenderbufferParameteriv(unsigned long target, unsigned long pname); + int getShaderi(CanvasShader*, unsigned long pname); + PassRefPtr<CanvasIntArray> getShaderiv(CanvasShader*, unsigned long pname); + + String getShaderInfoLog(CanvasShader*); + + // TBD + // void glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); + + String getShaderSource(CanvasShader*); + String getString(unsigned long name); + + float getTexParameterf(unsigned long target, unsigned long pname); + PassRefPtr<CanvasFloatArray> getTexParameterfv(unsigned long target, unsigned long pname); + int getTexParameteri(unsigned long target, unsigned long pname); + PassRefPtr<CanvasIntArray> getTexParameteriv(unsigned long target, unsigned long pname); + + float getUniformf(CanvasProgram* program, long location); + PassRefPtr<CanvasFloatArray> getUniformfv(CanvasProgram* program, long location); + int getUniformi(CanvasProgram* program, long location); + PassRefPtr<CanvasIntArray> getUniformiv(CanvasProgram* program, long location); + + long getUniformLocation(CanvasProgram*, const String& name); + + float getVertexAttribf(unsigned long index, unsigned long pname); + PassRefPtr<CanvasFloatArray> getVertexAttribfv(unsigned long index, unsigned long pname); + int getVertexAttribi(unsigned long index, unsigned long pname); + PassRefPtr<CanvasIntArray> getVertexAttribiv(unsigned long index, unsigned long pname); + + long getVertexAttribOffset(unsigned long index, unsigned long pname); + + void hint(unsigned long target, unsigned long mode); + bool isBuffer(CanvasBuffer*); + bool isEnabled(unsigned long cap); + bool isFramebuffer(CanvasFramebuffer*); + bool isProgram(CanvasProgram*); + bool isRenderbuffer(CanvasRenderbuffer*); + bool isShader(CanvasShader*); + bool isTexture(CanvasTexture*); + void lineWidth(double); + void linkProgram(CanvasProgram*); + void pixelStorei(unsigned long pname, long param); + void polygonOffset(double factor, double units); + + // TBD + //void readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type, void* pixels); + + void releaseShaderCompiler(); + void renderbufferStorage(unsigned long target, unsigned long internalformat, unsigned long width, unsigned long height); + void sampleCoverage(double value, bool invert); + void scissor(long x, long y, unsigned long width, unsigned long height); + void shaderSource(CanvasShader*, const String& string); + void stencilFunc(unsigned long func, long ref, unsigned long mask); + void stencilFuncSeparate(unsigned long face, unsigned long func, long ref, unsigned long mask); + void stencilMask(unsigned long mask); + void stencilMaskSeparate(unsigned long face, unsigned long mask); + void stencilOp(unsigned long fail, unsigned long zfail, unsigned long zpass); + void stencilOpSeparate(unsigned long face, unsigned long fail, unsigned long zfail, unsigned long zpass); + + // These next several functions return an error code (0 if no errors) rather than using an ExceptionCode. + // Currently they return -1 on any error. + int texImage2D(unsigned target, unsigned level, unsigned internalformat, + unsigned width, unsigned height, unsigned border, + unsigned format, unsigned type, CanvasArray* pixels); + int texImage2D(unsigned target, unsigned level, unsigned internalformat, + unsigned width, unsigned height, unsigned border, + unsigned format, unsigned type, ImageData* pixels); + int texImage2D(unsigned target, unsigned level, HTMLImageElement* image, + bool flipY, bool premultiplyAlpha); + int texImage2D(unsigned target, unsigned level, HTMLCanvasElement* canvas, + bool flipY, bool premultiplyAlpha); + int texImage2D(unsigned target, unsigned level, HTMLVideoElement* video, + bool flipY, bool premultiplyAlpha); + + void texParameterf(unsigned target, unsigned pname, float param); + void texParameteri(unsigned target, unsigned pname, int param); + + int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, + unsigned width, unsigned height, + unsigned format, unsigned type, CanvasArray* pixels); + int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, + unsigned width, unsigned height, + unsigned format, unsigned type, ImageData* pixels); + int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, + unsigned width, unsigned height, HTMLImageElement* image, + bool flipY, bool premultiplyAlpha); + int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, + unsigned width, unsigned height, HTMLCanvasElement* canvas, + bool flipY, bool premultiplyAlpha); + int texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, + unsigned width, unsigned height, HTMLVideoElement* video, + bool flipY, bool premultiplyAlpha); + + void uniform1f(long location, float x); + void uniform1fv(long location, float* v, int size); + void uniform1i(long location, int x); + void uniform1iv(long location, int* v, int size); + void uniform2f(long location, float x, float y); + void uniform2fv(long location, float* v, int size); + void uniform2i(long location, int x, int y); + void uniform2iv(long location, int* v, int size); + void uniform3f(long location, float x, float y, float z); + void uniform3fv(long location, float* v, int size); + void uniform3i(long location, int x, int y, int z); + void uniform3iv(long location, int* v, int size); + void uniform4f(long location, float x, float y, float z, float w); + void uniform4fv(long location, float* v, int size); + void uniform4i(long location, int x, int y, int z, int w); + void uniform4iv(long location, int* v, int size); + void uniformMatrix2fv(long location, bool transpose, float* value, int size); + void uniformMatrix3fv(long location, bool transpose, float* value, int size); + void uniformMatrix4fv(long location, bool transpose, float* value, int size); + + void useProgram(CanvasProgram*); + void validateProgram(CanvasProgram*); + + void vertexAttrib1f(unsigned long indx, float x); + void vertexAttrib1fv(unsigned long indx, float* values); + void vertexAttrib2f(unsigned long indx, float x, float y); + void vertexAttrib2fv(unsigned long indx, float* values); + void vertexAttrib3f(unsigned long indx, float x, float y, float z); + void vertexAttrib3fv(unsigned long indx, float* values); + void vertexAttrib4f(unsigned long indx, float x, float y, float z, float w); + void vertexAttrib4fv(unsigned long indx, float* values); + void vertexAttribPointer(unsigned long indx, int size, int type, bool normalized, + unsigned long stride, unsigned long offset); + + void viewport(long x, long y, unsigned long width, unsigned long height); + + void reshape(int width, int height); + + // Helpers for notification about paint events + void beginPaint(CanvasRenderingContext3D* context); + void endPaint(); + + // Support for buffer creation and deletion + unsigned createBuffer(); + unsigned createFramebuffer(); + unsigned createProgram(); + unsigned createRenderbuffer(); + unsigned createShader(ShaderType); + unsigned createTexture(); + + void deleteBuffer(unsigned); + void deleteFramebuffer(unsigned); + void deleteProgram(unsigned); + void deleteRenderbuffer(unsigned); + void deleteShader(unsigned); + void deleteTexture(unsigned); + + private: + int m_currentWidth, m_currentHeight; + +#if PLATFORM(MAC) + Vector<Vector<float> > m_vertexArray; + + CGLContextObj m_contextObj; + GLuint m_texture; + GLuint m_fbo; + GLuint m_depthBuffer; +#endif + + // FIXME: ideally this would be used on all platforms. +#if PLATFORM(CHROMIUM) + friend class GraphicsContext3DInternal; + OwnPtr<GraphicsContext3DInternal> m_internal; +#endif + }; + +} // namespace WebCore + +#endif // GraphicsContext3D_h + diff --git a/WebCore/platform/graphics/GraphicsLayer.cpp b/WebCore/platform/graphics/GraphicsLayer.cpp index 7d43832..b375bd3 100644 --- a/WebCore/platform/graphics/GraphicsLayer.cpp +++ b/WebCore/platform/graphics/GraphicsLayer.cpp @@ -69,10 +69,11 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client) , m_usingTiledLayer(false) , m_masksToBounds(false) , m_drawsContent(false) - , m_paintingPhase(GraphicsLayerPaintAllMask) + , m_paintingPhase(GraphicsLayerPaintAll) , m_geometryOrientation(CompositingCoordinatesTopDown) , m_contentsOrientation(CompositingCoordinatesTopDown) , m_parent(0) + , m_maskLayer(0) #ifndef NDEBUG , m_repaintCount(0) #endif diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h index 4d7668a..2924073 100644 --- a/WebCore/platform/graphics/GraphicsLayer.h +++ b/WebCore/platform/graphics/GraphicsLayer.h @@ -33,11 +33,15 @@ #include "FloatPoint.h" #include "FloatPoint3D.h" #include "FloatSize.h" +#if ENABLE(3D_CANVAS) +#include "GraphicsContext3D.h" +#endif #include "GraphicsLayerClient.h" #include "IntRect.h" #include "TransformationMatrix.h" #include "TransformOperations.h" #include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> #if PLATFORM(MAC) #ifdef __OBJC__ @@ -152,7 +156,7 @@ protected: class GraphicsLayer { public: - static GraphicsLayer* createGraphicsLayer(GraphicsLayerClient*); + static PassOwnPtr<GraphicsLayer> create(GraphicsLayerClient*); virtual ~GraphicsLayer(); @@ -180,6 +184,9 @@ public: void removeAllChildren(); virtual void removeFromParent(); + GraphicsLayer* maskLayer() const { return m_maskLayer; } + virtual void setMaskLayer(GraphicsLayer* layer) { m_maskLayer = layer; } + // Offset is origin of the renderer minus origin of the graphics layer (so either zero or negative). IntSize offsetFromRenderer() const { return m_offsetFromRenderer; } void setOffsetFromRenderer(const IntSize& offset) { m_offsetFromRenderer = offset; } @@ -229,8 +236,8 @@ public: virtual void setOpacity(float opacity) { m_opacity = opacity; } // Some GraphicsLayers paint only the foreground or the background content - GraphicsLayerPaintingPhase drawingPhase() const { return m_paintingPhase; } - void setDrawingPhase(GraphicsLayerPaintingPhase phase) { m_paintingPhase = phase; } + GraphicsLayerPaintingPhase paintingPhase() const { return m_paintingPhase; } + void setPaintingPhase(GraphicsLayerPaintingPhase phase) { m_paintingPhase = phase; } virtual void setNeedsDisplay() = 0; // mark the given rect (in layer coords) as needing dispay. Never goes deep. @@ -255,6 +262,10 @@ public: virtual void setContentsToVideo(PlatformLayer*) { } virtual void setContentsBackgroundColor(const Color&) { } +#if ENABLE(3D_CANVAS) + virtual void setContentsToGraphicsContext3D(const GraphicsContext3D*) { } + virtual void setGraphicsContext3DNeedsDisplay() { } +#endif // Callback from the underlying graphics system to draw layer contents. void paintGraphicsLayerContents(GraphicsContext&, const IntRect& clip); @@ -347,6 +358,8 @@ protected: Vector<GraphicsLayer*> m_children; GraphicsLayer* m_parent; + GraphicsLayer* m_maskLayer; // Reference to mask layer. We don't own this. + IntRect m_contentsRect; #ifndef NDEBUG diff --git a/WebCore/platform/graphics/GraphicsLayerClient.h b/WebCore/platform/graphics/GraphicsLayerClient.h index 8c0b7ed..5facc94 100644 --- a/WebCore/platform/graphics/GraphicsLayerClient.h +++ b/WebCore/platform/graphics/GraphicsLayerClient.h @@ -37,9 +37,10 @@ class IntRect; class FloatPoint; enum GraphicsLayerPaintingPhase { - GraphicsLayerPaintBackgroundMask = (1 << 0), - GraphicsLayerPaintForegroundMask = (1 << 1), - GraphicsLayerPaintAllMask = (GraphicsLayerPaintBackgroundMask | GraphicsLayerPaintForegroundMask) + GraphicsLayerPaintBackground = (1 << 0), + GraphicsLayerPaintForeground = (1 << 1), + GraphicsLayerPaintMask = (1 << 2), + GraphicsLayerPaintAll = (GraphicsLayerPaintBackground | GraphicsLayerPaintForeground | GraphicsLayerPaintMask) }; enum AnimatedPropertyID { diff --git a/WebCore/platform/graphics/ImageBuffer.h b/WebCore/platform/graphics/ImageBuffer.h index 2a96d3b..9432058 100644 --- a/WebCore/platform/graphics/ImageBuffer.h +++ b/WebCore/platform/graphics/ImageBuffer.h @@ -50,6 +50,11 @@ namespace WebCore { LinearRGB }; + enum Multiply { + Premultiplied, + Unmultiplied + }; + class ImageBuffer : public Noncopyable { public: // Will return a null pointer on allocation failure. @@ -71,8 +76,11 @@ namespace WebCore { void clearImage() { m_image.clear(); } - PassRefPtr<ImageData> getImageData(const IntRect& rect) const; - void putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint); + PassRefPtr<ImageData> getUnmultipliedImageData(const IntRect&) const; + PassRefPtr<ImageData> getPremultipliedImageData(const IntRect&) const; + + void putUnmultipliedImageData(ImageData*, const IntRect& sourceRect, const IntPoint& destPoint); + void putPremultipliedImageData(ImageData*, const IntRect& sourceRect, const IntPoint& destPoint); String toDataURL(const String& mimeType) const; #if !PLATFORM(CG) diff --git a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp b/WebCore/platform/graphics/ImageSource.cpp index df62618..bf7ae21 100644 --- a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp +++ b/WebCore/platform/graphics/ImageSource.cpp @@ -1,6 +1,8 @@ /* * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. * Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk> + * Copyright (C) 2008, Google Inc. All rights reserved. + * Copyright (C) 2007-2009 Torch Mobile, Inc * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,64 +29,20 @@ #include "config.h" #include "ImageSource.h" -#if PLATFORM(CAIRO) +#if PLATFORM(QT) +#include "ImageDecoderQt.h" +#else +#include "ImageDecoder.h" +#endif -#include "BMPImageDecoder.h" -#include "GIFImageDecoder.h" -#include "ICOImageDecoder.h" -#include "JPEGImageDecoder.h" -#include "PNGImageDecoder.h" -#include "XBMImageDecoder.h" -#include "SharedBuffer.h" -#include <cairo.h> +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) +#ifndef IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS +#define IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS (1024 * 1024) +#endif +#endif namespace WebCore { -ImageDecoder* createDecoder(const Vector<char>& data) -{ - // We need at least 4 bytes to figure out what kind of image we're dealing with. - int length = data.size(); - if (length < 4) - return 0; - - const unsigned char* uContents = (const unsigned char*)data.data(); - const char* contents = data.data(); - - // GIFs begin with GIF8(7 or 9). - if (strncmp(contents, "GIF8", 4) == 0) - return new GIFImageDecoder(); - - // Test for PNG. - if (uContents[0]==0x89 && - uContents[1]==0x50 && - uContents[2]==0x4E && - uContents[3]==0x47) - return new PNGImageDecoder(); - - // JPEG - if (uContents[0]==0xFF && - uContents[1]==0xD8 && - uContents[2]==0xFF) - return new JPEGImageDecoder(); - - // BMP - if (strncmp(contents, "BM", 2) == 0) - return new BMPImageDecoder(); - - // ICOs always begin with a 2-byte 0 followed by a 2-byte 1. - // CURs begin with 2-byte 0 followed by 2-byte 2. - if (!memcmp(contents, "\000\000\001\000", 4) || - !memcmp(contents, "\000\000\002\000", 4)) - return new ICOImageDecoder(); - - // XBMs require 8 bytes of info. - if (length >= 8 && strncmp(contents, "#define ", 8) == 0) - return new XBMImageDecoder(); - - // Give up. We don't know what the heck this is. - return 0; -} - ImageSource::ImageSource() : m_decoder(0) { @@ -120,53 +78,41 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived) // This method will examine the data and instantiate an instance of the appropriate decoder plugin. // If insufficient bytes are available to determine the image type, no decoder plugin will be // made. - if (!m_decoder) - m_decoder = createDecoder(data->buffer()); - - if (!m_decoder) - return; + if (!m_decoder) { + m_decoder = static_cast<NativeImageSourcePtr>(ImageDecoder::create(*data)); +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + if (m_decoder) + m_decoder->setMaxNumPixels(IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS); +#endif + } - m_decoder->setData(data, allDataReceived); + if (m_decoder) + m_decoder->setData(data, allDataReceived); } String ImageSource::filenameExtension() const { - if (!m_decoder) - return String(); - - return m_decoder->filenameExtension(); + return m_decoder ? m_decoder->filenameExtension() : String(); } bool ImageSource::isSizeAvailable() { - if (!m_decoder) - return false; - - return m_decoder->isSizeAvailable(); + return m_decoder && m_decoder->isSizeAvailable(); } IntSize ImageSource::size() const { - if (!m_decoder) - return IntSize(); - - return m_decoder->size(); + return m_decoder ? m_decoder->size() : IntSize(); } IntSize ImageSource::frameSizeAtIndex(size_t index) const { - if (!m_decoder) - return IntSize(); - - return m_decoder->frameSizeAtIndex(index); + return m_decoder ? m_decoder->frameSizeAtIndex(index) : IntSize(); } int ImageSource::repetitionCount() { - if (!m_decoder) - return cAnimationNone; - - return m_decoder->repetitionCount(); + return m_decoder ? m_decoder->repetitionCount() : cAnimationNone; } size_t ImageSource::frameCount() const @@ -176,9 +122,6 @@ size_t ImageSource::frameCount() const NativeImagePtr ImageSource::createFrameAtIndex(size_t index) { - if (!initialized()) - return 0; - if (!m_decoder) return 0; @@ -186,23 +129,16 @@ NativeImagePtr ImageSource::createFrameAtIndex(size_t index) if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) return 0; - // Cairo does not like zero height images. - // If we have a zero height image, just pretend we don't have enough data yet. - if (!size().height()) + // Zero-height images can cause problems for some ports. If we have an + // empty image dimension, just bail. + if (size().isEmpty()) return 0; + // Return the buffer contents as a native image. For some ports, the data + // is already in a native container, and this just increments its refcount. return buffer->asNewNativeImage(); } -bool ImageSource::frameIsCompleteAtIndex(size_t index) -{ - if (!m_decoder) - return false; - - RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); - return buffer && buffer->status() == RGBA32Buffer::FrameComplete; -} - float ImageSource::frameDurationAtIndex(size_t index) { if (!m_decoder) @@ -223,17 +159,23 @@ float ImageSource::frameDurationAtIndex(size_t index) bool ImageSource::frameHasAlphaAtIndex(size_t index) { - // When a frame has not finished decoding, always mark it as having alpha, - // so we don't get a black background for the undecoded sections. - // TODO: A better solution is probably to have the underlying buffer's - // hasAlpha() return true in these cases, since it is, in fact, technically - // true. - if (!frameIsCompleteAtIndex(index)) - return true; - - return m_decoder->frameBufferAtIndex(index)->hasAlpha(); + // When a frame has not finished decoding, always mark it as having alpha. + // Ports that check the result of this function to determine their + // compositing op need this in order to not draw the undecoded portion as + // black. + // TODO: Perhaps we should ensure that each individual decoder returns true + // in this case. + return !frameIsCompleteAtIndex(index) + || m_decoder->frameBufferAtIndex(index)->hasAlpha(); } +bool ImageSource::frameIsCompleteAtIndex(size_t index) +{ + if (!m_decoder) + return false; + + RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); + return buffer && buffer->status() == RGBA32Buffer::FrameComplete; } -#endif // PLATFORM(CAIRO) +} diff --git a/WebCore/platform/graphics/ImageSource.h b/WebCore/platform/graphics/ImageSource.h index 173d50b..eabeeab 100644 --- a/WebCore/platform/graphics/ImageSource.h +++ b/WebCore/platform/graphics/ImageSource.h @@ -51,6 +51,8 @@ class SkBitmapRef; class PrivateAndroidImageSourceRec; #elif PLATFORM(SKIA) class NativeImageSkia; +#elif PLATFORM(HAIKU) +class BBitmap; #elif PLATFORM(WINCE) #include "SharedBitmap.h" #endif @@ -61,22 +63,14 @@ class IntSize; class SharedBuffer; class String; -#if PLATFORM(WX) -class ImageDecoder; -typedef ImageDecoder* NativeImageSourcePtr; -typedef const Vector<char>* NativeBytePtr; -#if USE(WXGC) -typedef wxGraphicsBitmap* NativeImagePtr; -#else -typedef wxBitmap* NativeImagePtr; -#endif -#elif PLATFORM(CG) +#if PLATFORM(CG) typedef CGImageSourceRef NativeImageSourcePtr; typedef CGImageRef NativeImagePtr; #elif PLATFORM(QT) class ImageDecoderQt; typedef ImageDecoderQt* NativeImageSourcePtr; typedef QPixmap* NativeImagePtr; +<<<<<<< HEAD:WebCore/platform/graphics/ImageSource.h #elif PLATFORM(ANDROID) #if PLATFORM(SGL) class String; @@ -98,18 +92,27 @@ typedef ImageDecoder* NativeImageSourcePtr; typedef NativeImageSkia* NativeImagePtr; #endif #elif PLATFORM(CAIRO) +======= +#else +>>>>>>> webkit.org at 49305:WebCore/platform/graphics/ImageSource.h class ImageDecoder; typedef ImageDecoder* NativeImageSourcePtr; +#if PLATFORM(WX) +#if USE(WXGC) +typedef wxGraphicsBitmap* NativeImagePtr; +#else +typedef wxBitmap* NativeImagePtr; +#endif +#elif PLATFORM(CAIRO) typedef cairo_surface_t* NativeImagePtr; #elif PLATFORM(SKIA) -class ImageDecoder; -typedef ImageDecoder* NativeImageSourcePtr; typedef NativeImageSkia* NativeImagePtr; +#elif PLATFORM(HAIKU) +typedef BBitmap* NativeImagePtr; #elif PLATFORM(WINCE) -class ImageDecoder; -typedef ImageDecoder* NativeImageSourcePtr; typedef RefPtr<SharedBitmap> NativeImagePtr; #endif +#endif const int cAnimationLoopOnce = -1; const int cAnimationNone = -2; diff --git a/WebCore/platform/graphics/IntPoint.h b/WebCore/platform/graphics/IntPoint.h index e6d4816..afbfb46 100644 --- a/WebCore/platform/graphics/IntPoint.h +++ b/WebCore/platform/graphics/IntPoint.h @@ -55,6 +55,8 @@ class QPoint; QT_END_NAMESPACE #elif PLATFORM(GTK) typedef struct _GdkPoint GdkPoint; +#elif PLATFORM(HAIKU) +class BPoint; #endif #if PLATFORM(WX) @@ -121,6 +123,9 @@ public: #elif PLATFORM(GTK) IntPoint(const GdkPoint&); operator GdkPoint() const; +#elif PLATFORM(HAIKU) + explicit IntPoint(const BPoint&); + operator BPoint() const; #endif #if PLATFORM(WX) diff --git a/WebCore/platform/graphics/IntRect.h b/WebCore/platform/graphics/IntRect.h index 0b607f5..cd912ff 100644 --- a/WebCore/platform/graphics/IntRect.h +++ b/WebCore/platform/graphics/IntRect.h @@ -33,7 +33,7 @@ typedef struct CGRect CGRect; #endif -#if PLATFORM(MAC) +#if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) #ifdef NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES typedef struct CGRect NSRect; #else @@ -49,6 +49,8 @@ class QRect; QT_END_NAMESPACE #elif PLATFORM(GTK) typedef struct _GdkRectangle GdkRectangle; +#elif PLATFORM(HAIKU) +class BRect; #endif #if PLATFORM(WX) @@ -144,6 +146,9 @@ public: #elif PLATFORM(GTK) IntRect(const GdkRectangle&); operator GdkRectangle() const; +#elif PLATFORM(HAIKU) + explicit IntRect(const BRect&); + operator BRect() const; #endif #if PLATFORM(CG) @@ -156,7 +161,8 @@ public: operator SkIRect() const; #endif -#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES) +#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \ + || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) operator NSRect() const; #endif @@ -193,7 +199,8 @@ inline bool operator!=(const IntRect& a, const IntRect& b) IntRect enclosingIntRect(const CGRect&); #endif -#if PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES) +#if (PLATFORM(MAC) && !defined(NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES)) \ + || (PLATFORM(CHROMIUM) && PLATFORM(DARWIN)) IntRect enclosingIntRect(const NSRect&); #endif diff --git a/WebCore/platform/graphics/IntSize.h b/WebCore/platform/graphics/IntSize.h index dc7a85d..b242784 100644 --- a/WebCore/platform/graphics/IntSize.h +++ b/WebCore/platform/graphics/IntSize.h @@ -47,6 +47,12 @@ typedef struct tagSIZE SIZE; QT_BEGIN_NAMESPACE class QSize; QT_END_NAMESPACE +#elif PLATFORM(HAIKU) +class BSize; +#endif + +#if PLATFORM(WX) +class wxSize; #endif namespace WebCore { @@ -113,6 +119,15 @@ public: operator QSize() const; #endif +#if PLATFORM(HAIKU) + explicit IntSize(const BSize&); + operator BSize() const; +#endif + +#if PLATFORM(WX) + IntSize(const wxSize&); + operator wxSize() const; +#endif private: int m_width, m_height; diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp index 8792640..3898386 100644 --- a/WebCore/platform/graphics/MediaPlayer.cpp +++ b/WebCore/platform/graphics/MediaPlayer.cpp @@ -35,10 +35,11 @@ #include "FrameView.h" #include "Frame.h" #include "Document.h" +#include "TimeRanges.h" #if PLATFORM(MAC) #include "MediaPlayerPrivateQTKit.h" -#elif PLATFORM(WINCE) +#elif PLATFORM(WINCE) && !PLATFORM(QT) #include "MediaPlayerPrivateWince.h" #elif PLATFORM(WIN) #include "MediaPlayerPrivateQuickTimeWin.h" @@ -67,11 +68,12 @@ public: virtual void play() { } virtual void pause() { } - virtual bool supportsFullscreen() const { return false; } + virtual PlatformMedia platformMedia() const { return NoPlatformMedia; } virtual IntSize naturalSize() const { return IntSize(0, 0); } virtual bool hasVideo() const { return false; } + virtual bool hasAudio() const { return false; } virtual void setVisible(bool) { } @@ -93,7 +95,7 @@ public: virtual MediaPlayer::ReadyState readyState() const { return MediaPlayer::HaveNothing; } virtual float maxTimeSeekable() const { return 0; } - virtual float maxTimeBuffered() const { return 0; } + virtual PassRefPtr<TimeRanges> buffered() const { return TimeRanges::create(); } virtual int dataRate() const { return 0; } @@ -260,11 +262,19 @@ bool MediaPlayer::canLoadPoster() const { return m_private->canLoadPoster(); } +<<<<<<< HEAD:WebCore/platform/graphics/MediaPlayer.cpp +======= + +>>>>>>> webkit.org at 49305:WebCore/platform/graphics/MediaPlayer.cpp void MediaPlayer::setPoster(const String& url) { m_private->setPoster(url); +<<<<<<< HEAD:WebCore/platform/graphics/MediaPlayer.cpp } +======= +} +>>>>>>> webkit.org at 49305:WebCore/platform/graphics/MediaPlayer.cpp void MediaPlayer::cancelLoad() { @@ -275,7 +285,11 @@ void MediaPlayer::prepareToPlay() { m_private->prepareToPlay(); } +<<<<<<< HEAD:WebCore/platform/graphics/MediaPlayer.cpp +======= + +>>>>>>> webkit.org at 49305:WebCore/platform/graphics/MediaPlayer.cpp void MediaPlayer::play() { m_private->play(); @@ -331,11 +345,16 @@ IntSize MediaPlayer::naturalSize() return m_private->naturalSize(); } -bool MediaPlayer::hasVideo() +bool MediaPlayer::hasVideo() const { return m_private->hasVideo(); } +bool MediaPlayer::hasAudio() const +{ + return m_private->hasAudio(); +} + bool MediaPlayer::inMediaDocument() { Frame* frame = m_frameView ? m_frameView->frame() : 0; @@ -344,6 +363,11 @@ bool MediaPlayer::inMediaDocument() return document && document->isMediaDocument(); } +PlatformMedia MediaPlayer::platformMedia() const +{ + return m_private->platformMedia(); +} + MediaPlayer::NetworkState MediaPlayer::networkState() { return m_private->networkState(); @@ -397,9 +421,9 @@ void MediaPlayer::setEndTime(float time) m_private->setEndTime(time); } -float MediaPlayer::maxTimeBuffered() +PassRefPtr<TimeRanges> MediaPlayer::buffered() { - return m_private->maxTimeBuffered(); + return m_private->buffered(); } float MediaPlayer::maxTimeSeekable() diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h index d0220ed..4cc6476 100644 --- a/WebCore/platform/graphics/MediaPlayer.h +++ b/WebCore/platform/graphics/MediaPlayer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -38,8 +38,24 @@ #include <wtf/OwnPtr.h> #include <wtf/Noncopyable.h> +#ifdef __OBJC__ +@class QTMovie; +#else +class QTMovie; +#endif + namespace WebCore { +// Structure that will hold every native +// types supported by the current media player. +// We have to do that has multiple media players +// backend can live at runtime. +typedef struct PlatformMedia { + QTMovie* qtMovie; +} PlatformMedia; + +static const PlatformMedia NoPlatformMedia = { 0 }; + class ContentType; class FrameView; class GraphicsContext; @@ -48,6 +64,7 @@ class IntSize; class MediaPlayer; class MediaPlayerPrivateInterface; class String; +class TimeRanges; #if USE(ACCELERATED_COMPOSITING) class GraphicsLayer; @@ -109,8 +126,11 @@ public: bool supportsFullscreen() const; bool supportsSave() const; + PlatformMedia platformMedia() const; + IntSize naturalSize(); - bool hasVideo(); + bool hasVideo() const; + bool hasAudio() const; void setFrameView(FrameView* frameView) { m_frameView = frameView; } FrameView* frameView() { return m_frameView; } @@ -146,7 +166,7 @@ public: bool preservesPitch() const; void setPreservesPitch(bool); - float maxTimeBuffered(); + PassRefPtr<TimeRanges> buffered(); float maxTimeSeekable(); unsigned bytesLoaded(); diff --git a/WebCore/platform/graphics/MediaPlayerPrivate.h b/WebCore/platform/graphics/MediaPlayerPrivate.h index de7f75c..925e563 100644 --- a/WebCore/platform/graphics/MediaPlayerPrivate.h +++ b/WebCore/platform/graphics/MediaPlayerPrivate.h @@ -44,6 +44,11 @@ public: virtual void cancelLoad() = 0; virtual void prepareToPlay() { } +<<<<<<< HEAD:WebCore/platform/graphics/MediaPlayerPrivate.h +======= + virtual PlatformMedia platformMedia() const { return NoPlatformMedia; } + +>>>>>>> webkit.org at 49305:WebCore/platform/graphics/MediaPlayerPrivate.h virtual void play() = 0; virtual void pause() = 0; @@ -53,6 +58,7 @@ public: virtual IntSize naturalSize() const = 0; virtual bool hasVideo() const = 0; + virtual bool hasAudio() const = 0; virtual void setVisible(bool) = 0; @@ -77,7 +83,7 @@ public: virtual MediaPlayer::ReadyState readyState() const = 0; virtual float maxTimeSeekable() const = 0; - virtual float maxTimeBuffered() const = 0; + virtual PassRefPtr<TimeRanges> buffered() const = 0; virtual int dataRate() const = 0; diff --git a/WebCore/platform/graphics/Path.h b/WebCore/platform/graphics/Path.h index da324bc..6b617a0 100644 --- a/WebCore/platform/graphics/Path.h +++ b/WebCore/platform/graphics/Path.h @@ -52,6 +52,9 @@ typedef WebCore::CairoPath PlatformPath; #elif PLATFORM(SKIA) class SkPath; typedef SkPath PlatformPath; +#elif PLATFORM(HAIKU) +class BRegion; +typedef BRegion PlatformPath; #elif PLATFORM(WINCE) namespace WebCore { class PlatformPath; diff --git a/WebCore/platform/graphics/Pattern.h b/WebCore/platform/graphics/Pattern.h index 02ad3ec..2f1192c 100644 --- a/WebCore/platform/graphics/Pattern.h +++ b/WebCore/platform/graphics/Pattern.h @@ -53,6 +53,9 @@ typedef wxGraphicsBrush* PlatformPatternPtr; class wxBrush; typedef wxBrush* PlatformPatternPtr; #endif // USE(WXGC) +#elif PLATFORM(HAIKU) +#include <interface/GraphicsDefs.h> +typedef pattern* PlatformPatternPtr; #elif PLATFORM(WINCE) typedef void* PlatformPatternPtr; #endif diff --git a/WebCore/platform/graphics/SimpleFontData.cpp b/WebCore/platform/graphics/SimpleFontData.cpp index c879228..2ec8abb 100644 --- a/WebCore/platform/graphics/SimpleFontData.cpp +++ b/WebCore/platform/graphics/SimpleFontData.cpp @@ -48,7 +48,9 @@ using namespace std; namespace WebCore { SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool loading, SVGFontData* svgFontData) - : m_unitsPerEm(defaultUnitsPerEm) + : m_maxCharWidth(-1) + , m_avgCharWidth(-1) + , m_unitsPerEm(defaultUnitsPerEm) , m_platformData(f) , m_treatAsFixedPitch(false) #if ENABLE(SVG_FONTS) diff --git a/WebCore/platform/graphics/SimpleFontData.h b/WebCore/platform/graphics/SimpleFontData.h index cb472b0..387a5c7 100644 --- a/WebCore/platform/graphics/SimpleFontData.h +++ b/WebCore/platform/graphics/SimpleFontData.h @@ -2,6 +2,7 @@ * This file is part of the internal font implementation. * * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007-2008 Torch Mobile, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -27,13 +28,14 @@ #include "FontPlatformData.h" #include "GlyphPageTreeNode.h" #include "GlyphWidthMap.h" +#include "TextRenderingMode.h" #include <wtf/OwnPtr.h> #if USE(ATSUI) typedef struct OpaqueATSUStyle* ATSUStyle; #endif -#if PLATFORM(WIN) +#if PLATFORM(WIN) && !PLATFORM(WINCE) #include <usp10.h> #endif @@ -45,6 +47,10 @@ typedef struct OpaqueATSUStyle* ATSUStyle; #include <QFont> #endif +#if PLATFORM(HAIKU) +#include <Font.h> +#endif + namespace WebCore { class FontDescription; @@ -115,7 +121,7 @@ public: #if USE(CORE_TEXT) CTFontRef getCTFont() const; - CFDictionaryRef getCFStringAttributes() const; + CFDictionaryRef getCFStringAttributes(TextRenderingMode) const; #endif #if USE(ATSUI) @@ -134,17 +140,14 @@ public: #if PLATFORM(WIN) bool isSystemFont() const { return m_isSystemFont; } +#if !PLATFORM(WINCE) // disable unused members to save space SCRIPT_FONTPROPERTIES* scriptFontProperties() const; SCRIPT_CACHE* scriptCache() const { return &m_scriptCache; } - +#endif static void setShouldApplyMacAscentHack(bool); static bool shouldApplyMacAscentHack(); #endif -#if PLATFORM(CAIRO) - void setFont(cairo_t*) const; -#endif - #if PLATFORM(WX) wxFont* getWxFont() const { return m_platformData.font(); } #endif @@ -159,7 +162,7 @@ private: void commonInit(); -#if PLATFORM(WIN) +#if PLATFORM(WIN) && !PLATFORM(WINCE) void initGDIFont(); void platformCommonDestroy(); float widthForGDIGlyph(Glyph glyph) const; @@ -224,9 +227,11 @@ private: #if PLATFORM(WIN) bool m_isSystemFont; +#if !PLATFORM(WINCE) // disable unused members to save space mutable SCRIPT_CACHE m_scriptCache; mutable SCRIPT_FONTPROPERTIES* m_scriptFontProperties; #endif +#endif }; diff --git a/WebCore/platform/graphics/TextRenderingMode.h b/WebCore/platform/graphics/TextRenderingMode.h new file mode 100644 index 0000000..4f817a4 --- /dev/null +++ b/WebCore/platform/graphics/TextRenderingMode.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TextRenderingMode_h +#define TextRenderingMode_h + +namespace WebCore { + + enum TextRenderingMode { AutoTextRendering, OptimizeSpeed, OptimizeLegibility, GeometricPrecision }; + +} // namespace WebCore + +#endif // TextRenderingMode_h diff --git a/WebCore/platform/graphics/cairo/FontCairo.cpp b/WebCore/platform/graphics/cairo/FontCairo.cpp index 0f7ae79..1a951c2 100644 --- a/WebCore/platform/graphics/cairo/FontCairo.cpp +++ b/WebCore/platform/graphics/cairo/FontCairo.cpp @@ -46,7 +46,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons cairo_t* cr = context->platformContext(); cairo_save(cr); - font->setFont(cr); + cairo_set_scaled_font(cr, font->platformData().scaledFont()); GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from); diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp index 5765546..de8afb3 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp +++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -31,7 +31,6 @@ #if PLATFORM(CAIRO) -#include "TransformationMatrix.h" #include "CairoPath.h" #include "FloatRect.h" #include "Font.h" @@ -41,6 +40,7 @@ #include "Path.h" #include "Pattern.h" #include "SimpleFontData.h" +#include "TransformationMatrix.h" #include <cairo.h> #include <math.h> @@ -53,8 +53,8 @@ #elif PLATFORM(WIN) #include <cairo-win32.h> #endif -#include "GraphicsContextPrivate.h" #include "GraphicsContextPlatformPrivateCairo.h" +#include "GraphicsContextPrivate.h" #ifndef M_PI #define M_PI 3.14159265358979323846 @@ -142,38 +142,6 @@ void GraphicsContext::drawRect(const IntRect& rect) cairo_restore(cr); } -// FIXME: Now that this is refactored, it should be shared by all contexts. -static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle style) -{ - // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic - // works out. For example, with a border width of 3, KHTML will pass us (y1+y2)/2, e.g., - // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave - // us a perfect position, but an odd width gave us a position that is off by exactly 0.5. - if (style == DottedStroke || style == DashedStroke) { - if (p1.x() == p2.x()) { - p1.setY(p1.y() + strokeWidth); - p2.setY(p2.y() - strokeWidth); - } - else { - p1.setX(p1.x() + strokeWidth); - p2.setX(p2.x() - strokeWidth); - } - } - - if (static_cast<int>(strokeWidth) % 2) { - if (p1.x() == p2.x()) { - // We're a vertical line. Adjust our x. - p1.setX(p1.x() + 0.5); - p2.setX(p2.x() + 0.5); - } - else { - // We're a horizontal line. Adjust our y. - p1.setY(p1.y() + 0.5); - p2.setY(p2.y() + 0.5); - } - } -} - // This is only used to draw borders. void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) { @@ -239,20 +207,18 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) if (patWidth == 1) patternOffset = 1.0; else { - bool evenNumberOfSegments = numSegments%2 == 0; + bool evenNumberOfSegments = !(numSegments % 2); if (remainder) evenNumberOfSegments = !evenNumberOfSegments; if (evenNumberOfSegments) { if (remainder) { patternOffset += patWidth - remainder; - patternOffset += remainder/2; - } - else - patternOffset = patWidth/2; - } - else if (!evenNumberOfSegments) { + patternOffset += remainder / 2; + } else + patternOffset = patWidth / 2; + } else if (!evenNumberOfSegments) { if (remainder) - patternOffset = (patWidth - remainder)/2; + patternOffset = (patWidth - remainder) / 2; } } @@ -318,7 +284,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp if (w != h) cairo_scale(cr, 1., scaleFactor); - + cairo_arc_negative(cr, x + hRadius, (y + vRadius) * reverseScaleFactor, hRadius, -fa * M_PI/180, -falen * M_PI/180); if (w != h) @@ -326,16 +292,16 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp float width = strokeThickness(); int patWidth = 0; - + switch (strokeStyle()) { - case DottedStroke: - patWidth = static_cast<int>(width / 2); - break; - case DashedStroke: - patWidth = 3 * static_cast<int>(width / 2); - break; - default: - break; + case DottedStroke: + patWidth = static_cast<int>(width / 2); + break; + case DashedStroke: + patWidth = 3 * static_cast<int>(width / 2); + break; + default: + break; } setColor(cr, strokeColor()); @@ -349,7 +315,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp distance = static_cast<int>((M_PI * hRadius) / 2.0); else // We are elliptical and will have to estimate the distance distance = static_cast<int>((M_PI * sqrtf((hRadius * hRadius + vRadius * vRadius) / 2.0)) / 2.0); - + int remainder = distance % patWidth; int coverage = distance - remainder; int numSegments = coverage / patWidth; @@ -359,7 +325,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp if (patWidth == 1) patternOffset = 1.0; else { - bool evenNumberOfSegments = numSegments % 2 == 0; + bool evenNumberOfSegments = !(numSegments % 2); if (remainder) evenNumberOfSegments = !evenNumberOfSegments; if (evenNumberOfSegments) { @@ -828,15 +794,15 @@ void GraphicsContext::setLineCap(LineCap lineCap) cairo_line_cap_t cairoCap = CAIRO_LINE_CAP_BUTT; switch (lineCap) { - case ButtCap: - // no-op - break; - case RoundCap: - cairoCap = CAIRO_LINE_CAP_ROUND; - break; - case SquareCap: - cairoCap = CAIRO_LINE_CAP_SQUARE; - break; + case ButtCap: + // no-op + break; + case RoundCap: + cairoCap = CAIRO_LINE_CAP_ROUND; + break; + case SquareCap: + cairoCap = CAIRO_LINE_CAP_SQUARE; + break; } cairo_set_line_cap(m_data->cr, cairoCap); } @@ -853,15 +819,15 @@ void GraphicsContext::setLineJoin(LineJoin lineJoin) cairo_line_join_t cairoJoin = CAIRO_LINE_JOIN_MITER; switch (lineJoin) { - case MiterJoin: - // no-op - break; - case RoundJoin: - cairoJoin = CAIRO_LINE_JOIN_ROUND; - break; - case BevelJoin: - cairoJoin = CAIRO_LINE_JOIN_BEVEL; - break; + case MiterJoin: + // no-op + break; + case RoundJoin: + cairoJoin = CAIRO_LINE_JOIN_ROUND; + break; + case BevelJoin: + cairoJoin = CAIRO_LINE_JOIN_BEVEL; + break; } cairo_set_line_join(m_data->cr, cairoJoin); } @@ -887,37 +853,37 @@ float GraphicsContext::getAlpha() static inline cairo_operator_t toCairoOperator(CompositeOperator op) { switch (op) { - case CompositeClear: - return CAIRO_OPERATOR_CLEAR; - case CompositeCopy: - return CAIRO_OPERATOR_SOURCE; - case CompositeSourceOver: - return CAIRO_OPERATOR_OVER; - case CompositeSourceIn: - return CAIRO_OPERATOR_IN; - case CompositeSourceOut: - return CAIRO_OPERATOR_OUT; - case CompositeSourceAtop: - return CAIRO_OPERATOR_ATOP; - case CompositeDestinationOver: - return CAIRO_OPERATOR_DEST_OVER; - case CompositeDestinationIn: - return CAIRO_OPERATOR_DEST_IN; - case CompositeDestinationOut: - return CAIRO_OPERATOR_DEST_OUT; - case CompositeDestinationAtop: - return CAIRO_OPERATOR_DEST_ATOP; - case CompositeXOR: - return CAIRO_OPERATOR_XOR; - case CompositePlusDarker: - return CAIRO_OPERATOR_SATURATE; - case CompositeHighlight: - // There is no Cairo equivalent for CompositeHighlight. - return CAIRO_OPERATOR_OVER; - case CompositePlusLighter: - return CAIRO_OPERATOR_ADD; - default: - return CAIRO_OPERATOR_SOURCE; + case CompositeClear: + return CAIRO_OPERATOR_CLEAR; + case CompositeCopy: + return CAIRO_OPERATOR_SOURCE; + case CompositeSourceOver: + return CAIRO_OPERATOR_OVER; + case CompositeSourceIn: + return CAIRO_OPERATOR_IN; + case CompositeSourceOut: + return CAIRO_OPERATOR_OUT; + case CompositeSourceAtop: + return CAIRO_OPERATOR_ATOP; + case CompositeDestinationOver: + return CAIRO_OPERATOR_DEST_OVER; + case CompositeDestinationIn: + return CAIRO_OPERATOR_DEST_IN; + case CompositeDestinationOut: + return CAIRO_OPERATOR_DEST_OUT; + case CompositeDestinationAtop: + return CAIRO_OPERATOR_DEST_ATOP; + case CompositeXOR: + return CAIRO_OPERATOR_XOR; + case CompositePlusDarker: + return CAIRO_OPERATOR_SATURATE; + case CompositeHighlight: + // There is no Cairo equivalent for CompositeHighlight. + return CAIRO_OPERATOR_OVER; + case CompositePlusLighter: + return CAIRO_OPERATOR_ADD; + default: + return CAIRO_OPERATOR_SOURCE; } } diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp index c905ee8..0213944 100644 --- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp @@ -138,16 +138,17 @@ void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) } } -PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const +template <Multiply multiplied> +PassRefPtr<ImageData> getImageData(const IntRect& rect, const ImageBufferData& data, const IntSize& size) { - ASSERT(cairo_surface_get_type(m_data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE); + ASSERT(cairo_surface_get_type(data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE); PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height()); - unsigned char* dataSrc = cairo_image_surface_get_data(m_data.m_surface); + unsigned char* dataSrc = cairo_image_surface_get_data(data.m_surface); unsigned char* dataDst = result->data()->data()->data(); - if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > m_size.width() || (rect.y() + rect.height()) > m_size.height()) - memset(dataSrc, 0, result->data()->length()); + if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > size.width() || (rect.y() + rect.height()) > size.height()) + memset(dataDst, 0, result->data()->length()); int originx = rect.x(); int destx = 0; @@ -156,8 +157,8 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const originx = 0; } int endx = rect.x() + rect.width(); - if (endx > m_size.width()) - endx = m_size.width(); + if (endx > size.width()) + endx = size.width(); int numColumns = endx - originx; int originy = rect.y(); @@ -167,11 +168,11 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const originy = 0; } int endy = rect.y() + rect.height(); - if (endy > m_size.height()) - endy = m_size.height(); + if (endy > size.height()) + endy = size.height(); int numRows = endy - originy; - int stride = cairo_image_surface_get_stride(m_data.m_surface); + int stride = cairo_image_surface_get_stride(data.m_surface); unsigned destBytesPerRow = 4 * rect.width(); unsigned char* destRows = dataDst + desty * destBytesPerRow + destx * 4; @@ -180,7 +181,11 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const for (int x = 0; x < numColumns; x++) { int basex = x * 4; unsigned* pixel = row + x + originx; - Color pixelColor = colorFromPremultipliedARGB(*pixel); + Color pixelColor; + if (multiplied == Unmultiplied) + pixelColor = colorFromPremultipliedARGB(*pixel); + else + pixelColor = Color(*pixel); destRows[basex] = pixelColor.red(); destRows[basex + 1] = pixelColor.green(); destRows[basex + 2] = pixelColor.blue(); @@ -192,11 +197,22 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const return result; } -void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const { - ASSERT(cairo_surface_get_type(m_data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE); + return getImageData<Unmultiplied>(rect, m_data, m_size); +} - unsigned char* dataDst = cairo_image_surface_get_data(m_data.m_surface); +PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const +{ + return getImageData<Premultiplied>(rect, m_data, m_size); +} + +template <Multiply multiplied> +void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& data, const IntSize& size) +{ + ASSERT(cairo_surface_get_type(data.m_surface) == CAIRO_SURFACE_TYPE_IMAGE); + + unsigned char* dataDst = cairo_image_surface_get_data(data.m_surface); ASSERT(sourceRect.width() > 0); ASSERT(sourceRect.height() > 0); @@ -204,28 +220,28 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, con int originx = sourceRect.x(); int destx = destPoint.x() + sourceRect.x(); ASSERT(destx >= 0); - ASSERT(destx < m_size.width()); + ASSERT(destx < size.width()); ASSERT(originx >= 0); ASSERT(originx <= sourceRect.right()); int endx = destPoint.x() + sourceRect.right(); - ASSERT(endx <= m_size.width()); + ASSERT(endx <= size.width()); int numColumns = endx - destx; int originy = sourceRect.y(); int desty = destPoint.y() + sourceRect.y(); ASSERT(desty >= 0); - ASSERT(desty < m_size.height()); + ASSERT(desty < size.height()); ASSERT(originy >= 0); ASSERT(originy <= sourceRect.bottom()); int endy = destPoint.y() + sourceRect.bottom(); - ASSERT(endy <= m_size.height()); + ASSERT(endy <= size.height()); int numRows = endy - desty; unsigned srcBytesPerRow = 4 * source->width(); - int stride = cairo_image_surface_get_stride(m_data.m_surface); + int stride = cairo_image_surface_get_stride(data.m_surface); unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4; for (int y = 0; y < numRows; ++y) { @@ -237,12 +253,25 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, con srcRows[basex + 1], srcRows[basex + 2], srcRows[basex + 3]); - *pixel = premultipliedARGBFromColor(pixelColor); + if (multiplied == Unmultiplied) + *pixel = premultipliedARGBFromColor(pixelColor); + else + *pixel = pixelColor.rgb(); } srcRows += srcBytesPerRow; } } +void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<Unmultiplied>(source, sourceRect, destPoint, m_data, m_size); +} + +void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<Premultiplied>(source, sourceRect, destPoint, m_data, m_size); +} + static cairo_status_t writeFunction(void* closure, const unsigned char* data, unsigned int length) { Vector<char>* in = reinterpret_cast<Vector<char>*>(closure); diff --git a/WebCore/platform/graphics/cg/ColorCG.cpp b/WebCore/platform/graphics/cg/ColorCG.cpp index 0465c0b..40aacc5 100644 --- a/WebCore/platform/graphics/cg/ColorCG.cpp +++ b/WebCore/platform/graphics/cg/ColorCG.cpp @@ -29,6 +29,7 @@ #if PLATFORM(CG) #include <wtf/Assertions.h> +#include <wtf/RetainPtr.h> #include <ApplicationServices/ApplicationServices.h> namespace WebCore { @@ -75,13 +76,12 @@ CGColorRef createCGColor(const Color& c) CMProfileRef prof = NULL; CMGetSystemProfile(&prof); - CGColorSpaceRef rgbSpace = CGColorSpaceCreateWithPlatformColorSpace(prof); + RetainPtr<CGColorSpaceRef> rgbSpace(AdoptCF, CGColorSpaceCreateWithPlatformColorSpace(prof)); - if (rgbSpace != NULL) - { - float components[4] = {c.red() / 255.0f, c.green() / 255.0f, c.blue() / 255.0f, c.alpha() / 255.0f}; - color = CGColorCreate(rgbSpace, components); - CGColorSpaceRelease(rgbSpace); + if (rgbSpace) { + CGFloat components[4] = { static_cast<CGFloat>(c.red()) / 255, static_cast<CGFloat>(c.green()) / 255, + static_cast<CGFloat>(c.blue()) / 255, static_cast<CGFloat>(c.alpha()) / 255 }; + color = CGColorCreate(rgbSpace.get(), components); } CMCloseProfile(prof); diff --git a/WebCore/platform/graphics/cg/GradientCG.cpp b/WebCore/platform/graphics/cg/GradientCG.cpp index c189fd5..05a0aad 100644 --- a/WebCore/platform/graphics/cg/GradientCG.cpp +++ b/WebCore/platform/graphics/cg/GradientCG.cpp @@ -58,17 +58,14 @@ CGShadingRef Gradient::platformGradient() const CGFloat intervalRanges[2] = { 0, 1 }; const CGFloat colorComponentRanges[4 * 2] = { 0, 1, 0, 1, 0, 1, 0, 1 }; const CGFunctionCallbacks gradientCallbacks = { 0, gradientCallback, 0 }; - CGFunctionRef colorFunction = CGFunctionCreate(this, 1, intervalRanges, 4, colorComponentRanges, &gradientCallbacks); + RetainPtr<CGFunctionRef> colorFunction(AdoptCF, CGFunctionCreate(this, 1, intervalRanges, 4, colorComponentRanges, &gradientCallbacks)); - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + static CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); if (m_radial) - m_gradient = CGShadingCreateRadial(colorSpace, m_p0, m_r0, m_p1, m_r1, colorFunction, true, true); + m_gradient = CGShadingCreateRadial(colorSpace, m_p0, m_r0, m_p1, m_r1, colorFunction.get(), true, true); else - m_gradient = CGShadingCreateAxial(colorSpace, m_p0, m_p1, colorFunction, true, true); - - CGColorSpaceRelease(colorSpace); - CGFunctionRelease(colorFunction); + m_gradient = CGShadingCreateAxial(colorSpace, m_p0, m_p1, colorFunction.get(), true, true); return m_gradient; } diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp index ab8eb3c..1b843e4 100644 --- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp +++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp @@ -28,14 +28,15 @@ #include "config.h" #include "GraphicsContext.h" -#include "TransformationMatrix.h" #include "FloatConversion.h" -#include "GraphicsContextPrivate.h" #include "GraphicsContextPlatformPrivateCG.h" +#include "GraphicsContextPrivate.h" #include "ImageBuffer.h" #include "KURL.h" #include "Path.h" #include "Pattern.h" +#include "TransformationMatrix.h" + #include <CoreGraphics/CGBitmapContext.h> #include <CoreGraphics/CGPDFContext.h> #include <wtf/MathExtras.h> @@ -86,7 +87,7 @@ CGContextRef GraphicsContext::platformContext() const { ASSERT(!paintingDisabled()); ASSERT(m_data->m_cgContext); - return m_data->m_cgContext; + return m_data->m_cgContext.get(); } void GraphicsContext::savePlatformState() @@ -178,19 +179,19 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) int patWidth = 0; switch (strokeStyle()) { - case NoStroke: - case SolidStroke: - break; - case DottedStroke: - patWidth = (int)width; - break; - case DashedStroke: - patWidth = 3 * (int)width; - break; + case NoStroke: + case SolidStroke: + break; + case DottedStroke: + patWidth = (int)width; + break; + case DashedStroke: + patWidth = 3 * (int)width; + break; } CGContextRef context = platformContext(); - + if (shouldAntialias()) CGContextSetShouldAntialias(context, false); @@ -221,7 +222,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) if (patWidth == 1) patternOffset = 1.0f; else { - bool evenNumberOfSegments = numSegments % 2 == 0; + bool evenNumberOfSegments = !(numSegments % 2); if (remainder) evenNumberOfSegments = !evenNumberOfSegments; if (evenNumberOfSegments) { @@ -235,7 +236,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) patternOffset = (patWidth - remainder)/2; } } - + const CGFloat dottedLine[2] = { patWidth, patWidth }; CGContextSetLineDash(context, patternOffset, dottedLine, 2); } @@ -248,7 +249,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) if (patWidth) CGContextRestoreGState(context); - + if (shouldAntialias()) CGContextSetShouldAntialias(context, true); } @@ -263,7 +264,7 @@ void GraphicsContext::drawEllipse(const IntRect& rect) if (paintingDisabled()) return; - + CGContextRef context = platformContext(); CGContextBeginPath(context); float r = (float)rect.width() / 2; @@ -275,25 +276,25 @@ void GraphicsContext::drawEllipse(const IntRect& rect) void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan) -{ +{ if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f) return; - + CGContextRef context = platformContext(); CGContextSaveGState(context); CGContextBeginPath(context); CGContextSetShouldAntialias(context, false); - + int x = rect.x(); int y = rect.y(); float w = (float)rect.width(); float h = (float)rect.height(); float scaleFactor = h / w; float reverseScaleFactor = w / h; - + if (w != h) scale(FloatSize(1, scaleFactor)); - + float hRadius = w / 2; float vRadius = h / 2; float fa = startAngle; @@ -304,22 +305,21 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp if (w != h) scale(FloatSize(1, reverseScaleFactor)); - - + float width = strokeThickness(); int patWidth = 0; - + switch (strokeStyle()) { - case DottedStroke: - patWidth = (int)(width / 2); - break; - case DashedStroke: - patWidth = 3 * (int)(width / 2); - break; - default: - break; + case DottedStroke: + patWidth = (int)(width / 2); + break; + case DashedStroke: + patWidth = 3 * (int)(width / 2); + break; + default: + break; } - + if (patWidth) { // Example: 80 pixels with a width of 30 pixels. // Remainder is 20. The maximum pixels of line we could paint @@ -329,7 +329,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp distance = static_cast<int>((piFloat * hRadius) / 2.0f); else // We are elliptical and will have to estimate the distance distance = static_cast<int>((piFloat * sqrtf((hRadius * hRadius + vRadius * vRadius) / 2.0f)) / 2.0f); - + int remainder = distance % patWidth; int coverage = distance - remainder; int numSegments = coverage / patWidth; @@ -339,7 +339,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp if (patWidth == 1) patternOffset = 1.0f; else { - bool evenNumberOfSegments = numSegments % 2 == 0; + bool evenNumberOfSegments = !(numSegments % 2); if (remainder) evenNumberOfSegments = !evenNumberOfSegments; if (evenNumberOfSegments) { @@ -353,13 +353,13 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp patternOffset = (patWidth - remainder) / 2.0f; } } - + const CGFloat dottedLine[2] = { patWidth, patWidth }; CGContextSetLineDash(context, patternOffset, dottedLine, 2); } CGContextStrokePath(context); - + CGContextRestoreGState(context); } @@ -375,7 +375,7 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points if (antialiased != shouldAntialias()) CGContextSetShouldAntialias(context, antialiased); - + CGContextBeginPath(context); CGContextMoveToPoint(context, points[0].x(), points[0].y()); for (size_t i = 1; i < npoints; i++) @@ -383,7 +383,7 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points CGContextClosePath(context); drawPath(); - + if (antialiased != shouldAntialias()) CGContextSetShouldAntialias(context, shouldAntialias()); } @@ -391,35 +391,31 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points void GraphicsContext::applyStrokePattern() { CGContextRef cgContext = platformContext(); - - CGPatternRef platformPattern = m_common->state.strokePattern.get()->createPlatformPattern(getCTM()); + + RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_common->state.strokePattern.get()->createPlatformPattern(getCTM())); if (!platformPattern) return; - CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(0); - CGContextSetStrokeColorSpace(cgContext, patternSpace); - CGColorSpaceRelease(patternSpace); + RetainPtr<CGColorSpaceRef> patternSpace(AdoptCF, CGColorSpaceCreatePattern(0)); + CGContextSetStrokeColorSpace(cgContext, patternSpace.get()); const CGFloat patternAlpha = 1; - CGContextSetStrokePattern(cgContext, platformPattern, &patternAlpha); - CGPatternRelease(platformPattern); + CGContextSetStrokePattern(cgContext, platformPattern.get(), &patternAlpha); } void GraphicsContext::applyFillPattern() { CGContextRef cgContext = platformContext(); - CGPatternRef platformPattern = m_common->state.fillPattern.get()->createPlatformPattern(getCTM()); + RetainPtr<CGPatternRef> platformPattern(AdoptCF, m_common->state.fillPattern.get()->createPlatformPattern(getCTM())); if (!platformPattern) return; - CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(0); - CGContextSetFillColorSpace(cgContext, patternSpace); - CGColorSpaceRelease(patternSpace); + RetainPtr<CGColorSpaceRef> patternSpace(AdoptCF, CGColorSpaceCreatePattern(0)); + CGContextSetFillColorSpace(cgContext, patternSpace.get()); const CGFloat patternAlpha = 1; - CGContextSetFillPattern(cgContext, platformPattern, &patternAlpha); - CGPatternRelease(platformPattern); + CGContextSetFillPattern(cgContext, platformPattern.get(), &patternAlpha); } static inline bool calculateDrawingMode(const GraphicsContextState& state, CGPathDrawingMode& mode) @@ -463,7 +459,7 @@ void GraphicsContext::drawPath() strokePath(); return; } - + if (state.fillColorSpace == PatternColorSpace) applyFillPattern(); if (state.strokeColorSpace == PatternColorSpace) @@ -599,7 +595,7 @@ void GraphicsContext::clipOut(const IntRect& rect) { if (paintingDisabled()) return; - + CGRect rects[2] = { CGContextGetClipBoundingBox(platformContext()), rect }; CGContextBeginPath(platformContext()); CGContextAddRects(platformContext(), rects, 2); @@ -610,7 +606,7 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) { if (paintingDisabled()) return; - + CGContextBeginPath(platformContext()); CGContextAddRect(platformContext(), CGContextGetClipBoundingBox(platformContext())); CGContextAddEllipseInRect(platformContext(), rect); @@ -639,13 +635,13 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness clip(rect); CGContextRef context = platformContext(); - + // Add outer ellipse CGContextAddEllipseInRect(context, CGRectMake(rect.x(), rect.y(), rect.width(), rect.height())); // Add inner ellipse. CGContextAddEllipseInRect(context, CGRectMake(rect.x() + thickness, rect.y() + thickness, rect.width() - (thickness * 2), rect.height() - (thickness * 2))); - + CGContextEOClip(context); } @@ -653,7 +649,7 @@ void GraphicsContext::clipToImageBuffer(const FloatRect& rect, const ImageBuffer { if (paintingDisabled()) return; - + CGContextTranslateCTM(platformContext(), rect.x(), rect.y() + rect.height()); CGContextScaleCTM(platformContext(), 1, -1); CGContextClipToMask(platformContext(), FloatRect(FloatPoint(), rect.size()), imageBuffer->image()->getCGImageRef()); @@ -731,12 +727,11 @@ void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Col if (!color.isValid()) CGContextSetShadow(context, CGSizeMake(width, height), blurRadius); else { - CGColorRef colorCG = createCGColor(color); + RetainPtr<CGColorRef> colorCG(AdoptCF, createCGColor(color)); CGContextSetShadowWithColor(context, CGSizeMake(width, height), - blurRadius, - colorCG); - CGColorRelease(colorCG); + blurRadius, + colorCG.get()); } } @@ -799,15 +794,15 @@ void GraphicsContext::setLineCap(LineCap cap) if (paintingDisabled()) return; switch (cap) { - case ButtCap: - CGContextSetLineCap(platformContext(), kCGLineCapButt); - break; - case RoundCap: - CGContextSetLineCap(platformContext(), kCGLineCapRound); - break; - case SquareCap: - CGContextSetLineCap(platformContext(), kCGLineCapSquare); - break; + case ButtCap: + CGContextSetLineCap(platformContext(), kCGLineCapButt); + break; + case RoundCap: + CGContextSetLineCap(platformContext(), kCGLineCapRound); + break; + case SquareCap: + CGContextSetLineCap(platformContext(), kCGLineCapSquare); + break; } } @@ -821,15 +816,15 @@ void GraphicsContext::setLineJoin(LineJoin join) if (paintingDisabled()) return; switch (join) { - case MiterJoin: - CGContextSetLineJoin(platformContext(), kCGLineJoinMiter); - break; - case RoundJoin: - CGContextSetLineJoin(platformContext(), kCGLineJoinRound); - break; - case BevelJoin: - CGContextSetLineJoin(platformContext(), kCGLineJoinBevel); - break; + case MiterJoin: + CGContextSetLineJoin(platformContext(), kCGLineJoinMiter); + break; + case RoundJoin: + CGContextSetLineJoin(platformContext(), kCGLineJoinRound); + break; + case BevelJoin: + CGContextSetLineJoin(platformContext(), kCGLineJoinBevel); + break; } } @@ -858,7 +853,7 @@ void GraphicsContext::clipOut(const Path& path) { if (paintingDisabled()) return; - + CGContextBeginPath(platformContext()); CGContextAddRect(platformContext(), CGContextGetClipBoundingBox(platformContext())); CGContextAddPath(platformContext(), path.platformPath()); @@ -909,9 +904,9 @@ TransformationMatrix GraphicsContext::getCTM() const FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) { - // It is not enough just to round to pixels in device space. The rotation part of the + // It is not enough just to round to pixels in device space. The rotation part of the // affine transform matrix to device space can mess with this conversion if we have a - // rotating image like the hands of the world clock widget. We just need the scale, so + // rotating image like the hands of the world clock widget. We just need the scale, so // we get the affine transform matrix and extract the scale. if (m_data->m_userToDeviceTransformKnownToBeIdentity) @@ -934,11 +929,11 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) deviceOrigin.y = roundf(deviceOrigin.y); deviceLowerRight.x = roundf(deviceLowerRight.x); deviceLowerRight.y = roundf(deviceLowerRight.y); - + // Don't let the height or width round to 0 unless either was originally 0 - if (deviceOrigin.y == deviceLowerRight.y && rect.height() != 0) + if (deviceOrigin.y == deviceLowerRight.y && rect.height()) deviceLowerRight.y += 1; - if (deviceOrigin.x == deviceLowerRight.x && rect.width() != 0) + if (deviceOrigin.x == deviceLowerRight.x && rect.width()) deviceLowerRight.x += 1; FloatPoint roundedOrigin = FloatPoint(deviceOrigin.x / deviceScaleX, deviceOrigin.y / deviceScaleY); @@ -984,13 +979,13 @@ void GraphicsContext::drawLineForText(const IntPoint& point, int width, bool pri } } } - + if (fillColor() != strokeColor()) setCGFillColor(platformContext(), strokeColor()); CGContextFillRect(platformContext(), CGRectMake(x, y, lineLength, thickness)); if (fillColor() != strokeColor()) setCGFillColor(platformContext(), fillColor()); - + if (restoreAntialiasMode) CGContextSetShouldAntialias(platformContext(), true); } @@ -999,51 +994,50 @@ void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) { if (paintingDisabled()) return; - - CFURLRef urlRef = link.createCFURL(); - if (urlRef) { - CGContextRef context = platformContext(); - - // Get the bounding box to handle clipping. - CGRect box = CGContextGetClipBoundingBox(context); - - IntRect intBox((int)box.origin.x, (int)box.origin.y, (int)box.size.width, (int)box.size.height); - IntRect rect = destRect; - rect.intersect(intBox); - - CGPDFContextSetURLForRect(context, urlRef, - CGRectApplyAffineTransform(rect, CGContextGetCTM(context))); - - CFRelease(urlRef); - } + + RetainPtr<CFURLRef> urlRef(AdoptCF, link.createCFURL()); + if (!urlRef) + return; + + CGContextRef context = platformContext(); + + // Get the bounding box to handle clipping. + CGRect box = CGContextGetClipBoundingBox(context); + + IntRect intBox((int)box.origin.x, (int)box.origin.y, (int)box.size.width, (int)box.size.height); + IntRect rect = destRect; + rect.intersect(intBox); + + CGPDFContextSetURLForRect(context, urlRef.get(), + CGRectApplyAffineTransform(rect, CGContextGetCTM(context))); } void GraphicsContext::setImageInterpolationQuality(InterpolationQuality mode) { if (paintingDisabled()) return; - + CGInterpolationQuality quality = kCGInterpolationDefault; switch (mode) { - case InterpolationDefault: - quality = kCGInterpolationDefault; - break; - case InterpolationNone: - quality = kCGInterpolationNone; - break; - case InterpolationLow: - quality = kCGInterpolationLow; - break; - - // Fall through to InterpolationHigh if kCGInterpolationMedium is not available - case InterpolationMedium: + case InterpolationDefault: + quality = kCGInterpolationDefault; + break; + case InterpolationNone: + quality = kCGInterpolationNone; + break; + case InterpolationLow: + quality = kCGInterpolationLow; + break; + + // Fall through to InterpolationHigh if kCGInterpolationMedium is not available + case InterpolationMedium: #if HAVE(CG_INTERPOLATION_MEDIUM) - quality = kCGInterpolationMedium; - break; + quality = kCGInterpolationMedium; + break; #endif - case InterpolationHigh: - quality = kCGInterpolationHigh; - break; + case InterpolationHigh: + quality = kCGInterpolationHigh; + break; } CGContextSetInterpolationQuality(platformContext(), quality); } @@ -1055,18 +1049,18 @@ InterpolationQuality GraphicsContext::imageInterpolationQuality() const CGInterpolationQuality quality = CGContextGetInterpolationQuality(platformContext()); switch (quality) { - case kCGInterpolationDefault: - return InterpolationDefault; - case kCGInterpolationNone: - return InterpolationNone; - case kCGInterpolationLow: - return InterpolationLow; + case kCGInterpolationDefault: + return InterpolationDefault; + case kCGInterpolationNone: + return InterpolationNone; + case kCGInterpolationLow: + return InterpolationLow; #if HAVE(CG_INTERPOLATION_MEDIUM) - case kCGInterpolationMedium: - return InterpolationMedium; + case kCGInterpolationMedium: + return InterpolationMedium; #endif - case kCGInterpolationHigh: - return InterpolationHigh; + case kCGInterpolationHigh: + return InterpolationHigh; } return InterpolationDefault; } @@ -1079,32 +1073,32 @@ void GraphicsContext::setPlatformTextDrawingMode(int mode) // Wow, wish CG had used bits here. CGContextRef context = platformContext(); switch (mode) { - case cTextInvisible: // Invisible - CGContextSetTextDrawingMode(context, kCGTextInvisible); - break; - case cTextFill: // Fill - CGContextSetTextDrawingMode(context, kCGTextFill); - break; - case cTextStroke: // Stroke - CGContextSetTextDrawingMode(context, kCGTextStroke); - break; - case 3: // Fill | Stroke - CGContextSetTextDrawingMode(context, kCGTextFillStroke); - break; - case cTextClip: // Clip - CGContextSetTextDrawingMode(context, kCGTextClip); - break; - case 5: // Fill | Clip - CGContextSetTextDrawingMode(context, kCGTextFillClip); - break; - case 6: // Stroke | Clip - CGContextSetTextDrawingMode(context, kCGTextStrokeClip); - break; - case 7: // Fill | Stroke | Clip - CGContextSetTextDrawingMode(context, kCGTextFillStrokeClip); - break; - default: - break; + case cTextInvisible: // Invisible + CGContextSetTextDrawingMode(context, kCGTextInvisible); + break; + case cTextFill: // Fill + CGContextSetTextDrawingMode(context, kCGTextFill); + break; + case cTextStroke: // Stroke + CGContextSetTextDrawingMode(context, kCGTextStroke); + break; + case 3: // Fill | Stroke + CGContextSetTextDrawingMode(context, kCGTextFillStroke); + break; + case cTextClip: // Clip + CGContextSetTextDrawingMode(context, kCGTextClip); + break; + case 5: // Fill | Clip + CGContextSetTextDrawingMode(context, kCGTextFillClip); + break; + case 6: // Stroke | Clip + CGContextSetTextDrawingMode(context, kCGTextStrokeClip); + break; + case 7: // Fill | Stroke | Clip + CGContextSetTextDrawingMode(context, kCGTextFillStrokeClip); + break; + default: + break; } } @@ -1138,54 +1132,54 @@ void GraphicsContext::setPlatformShouldAntialias(bool enable) #ifndef BUILDING_ON_TIGER // Tiger's setCompositeOperation() is defined in GraphicsContextMac.mm. void GraphicsContext::setCompositeOperation(CompositeOperator mode) -{ +{ if (paintingDisabled()) return; - CGBlendMode target = kCGBlendModeNormal; + CGBlendMode target = kCGBlendModeNormal; switch (mode) { - case CompositeClear: - target = kCGBlendModeClear; - break; - case CompositeCopy: - target = kCGBlendModeCopy; - break; - case CompositeSourceOver: - //kCGBlendModeNormal - break; - case CompositeSourceIn: - target = kCGBlendModeSourceIn; - break; - case CompositeSourceOut: - target = kCGBlendModeSourceOut; - break; - case CompositeSourceAtop: - target = kCGBlendModeSourceAtop; - break; - case CompositeDestinationOver: - target = kCGBlendModeDestinationOver; - break; - case CompositeDestinationIn: - target = kCGBlendModeDestinationIn; - break; - case CompositeDestinationOut: - target = kCGBlendModeDestinationOut; - break; - case CompositeDestinationAtop: - target = kCGBlendModeDestinationAtop; - break; - case CompositeXOR: - target = kCGBlendModeXOR; - break; - case CompositePlusDarker: - target = kCGBlendModePlusDarker; - break; - case CompositeHighlight: - // currently unsupported - break; - case CompositePlusLighter: - target = kCGBlendModePlusLighter; - break; + case CompositeClear: + target = kCGBlendModeClear; + break; + case CompositeCopy: + target = kCGBlendModeCopy; + break; + case CompositeSourceOver: + //kCGBlendModeNormal + break; + case CompositeSourceIn: + target = kCGBlendModeSourceIn; + break; + case CompositeSourceOut: + target = kCGBlendModeSourceOut; + break; + case CompositeSourceAtop: + target = kCGBlendModeSourceAtop; + break; + case CompositeDestinationOver: + target = kCGBlendModeDestinationOver; + break; + case CompositeDestinationIn: + target = kCGBlendModeDestinationIn; + break; + case CompositeDestinationOut: + target = kCGBlendModeDestinationOut; + break; + case CompositeDestinationAtop: + target = kCGBlendModeDestinationAtop; + break; + case CompositeXOR: + target = kCGBlendModeXOR; + break; + case CompositePlusDarker: + target = kCGBlendModePlusDarker; + break; + case CompositeHighlight: + // currently unsupported + break; + case CompositePlusLighter: + target = kCGBlendModePlusLighter; + break; } CGContextSetBlendMode(platformContext(), target); } diff --git a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h index f63a8dd..38c5506 100644 --- a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h +++ b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h @@ -38,12 +38,10 @@ public: #endif , m_userToDeviceTransformKnownToBeIdentity(false) { - CGContextRetain(m_cgContext); } ~GraphicsContextPlatformPrivate() { - CGContextRelease(m_cgContext); } #if PLATFORM(MAC) || PLATFORM(CHROMIUM) @@ -80,7 +78,7 @@ public: bool m_shouldIncludeChildWindows; #endif - CGContextRef m_cgContext; + RetainPtr<CGContextRef> m_cgContext; bool m_userToDeviceTransformKnownToBeIdentity; }; diff --git a/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/WebCore/platform/graphics/cg/ImageBufferCG.cpp index 6db7e88..b1896f8 100644 --- a/WebCore/platform/graphics/cg/ImageBufferCG.cpp +++ b/WebCore/platform/graphics/cg/ImageBufferCG.cpp @@ -65,37 +65,37 @@ ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, b bytesPerRow *= 4; } - m_data.m_data = tryFastCalloc(size.height(), bytesPerRow); + if (!tryFastCalloc(size.height(), bytesPerRow).getValue(m_data.m_data)) + return; + ASSERT((reinterpret_cast<size_t>(m_data.m_data) & 2) == 0); - CGColorSpaceRef colorSpace; + RetainPtr<CGColorSpaceRef> colorSpace; switch(imageColorSpace) { case DeviceRGB: - colorSpace = CGColorSpaceCreateDeviceRGB(); + colorSpace.adoptCF(CGColorSpaceCreateDeviceRGB()); break; case GrayScale: - colorSpace = CGColorSpaceCreateDeviceGray(); + colorSpace.adoptCF(CGColorSpaceCreateDeviceGray()); break; #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) case LinearRGB: - colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear); + colorSpace.adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear)); break; #endif default: - colorSpace = CGColorSpaceCreateDeviceRGB(); + colorSpace.adoptCF(CGColorSpaceCreateDeviceRGB()); break; } - CGContextRef cgContext = CGBitmapContextCreate(m_data.m_data, size.width(), size.height(), 8, bytesPerRow, - colorSpace, (imageColorSpace == GrayScale) ? kCGImageAlphaNone : kCGImageAlphaPremultipliedLast); - CGColorSpaceRelease(colorSpace); + RetainPtr<CGContextRef> cgContext(AdoptCF, CGBitmapContextCreate(m_data.m_data, size.width(), size.height(), 8, bytesPerRow, + colorSpace.get(), (imageColorSpace == GrayScale) ? kCGImageAlphaNone : kCGImageAlphaPremultipliedLast)); if (!cgContext) return; - m_context.set(new GraphicsContext(cgContext)); + m_context.set(new GraphicsContext(cgContext.get())); m_context->scale(FloatSize(1, -1)); m_context->translate(0, -size.height()); - CGContextRelease(cgContext); success = true; } @@ -122,12 +122,13 @@ Image* ImageBuffer::image() const return m_image.get(); } -PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const +template <Multiply multiplied> +PassRefPtr<ImageData> getImageData(const IntRect& rect, const ImageBufferData& imageData, const IntSize& size) { PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height()); unsigned char* data = result->data()->data()->data(); - if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > m_size.width() || (rect.y() + rect.height()) > m_size.height()) + if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > size.width() || (rect.y() + rect.height()) > size.height()) memset(data, 0, result->data()->length()); int originx = rect.x(); @@ -137,8 +138,8 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const originx = 0; } int endx = rect.x() + rect.width(); - if (endx > m_size.width()) - endx = m_size.width(); + if (endx > size.width()) + endx = size.width(); int numColumns = endx - originx; int originy = rect.y(); @@ -148,20 +149,21 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const originy = 0; } int endy = rect.y() + rect.height(); - if (endy > m_size.height()) - endy = m_size.height(); + if (endy > size.height()) + endy = size.height(); int numRows = endy - originy; - unsigned srcBytesPerRow = 4 * m_size.width(); + unsigned srcBytesPerRow = 4 * size.width(); unsigned destBytesPerRow = 4 * rect.width(); // ::create ensures that all ImageBuffers have valid data, so we don't need to check it here. - unsigned char* srcRows = reinterpret_cast<unsigned char*>(m_data.m_data) + originy * srcBytesPerRow + originx * 4; + unsigned char* srcRows = reinterpret_cast<unsigned char*>(imageData.m_data) + originy * srcBytesPerRow + originx * 4; unsigned char* destRows = data + desty * destBytesPerRow + destx * 4; for (int y = 0; y < numRows; ++y) { for (int x = 0; x < numColumns; x++) { int basex = x * 4; - if (unsigned char alpha = srcRows[basex + 3]) { + unsigned char alpha = srcRows[basex + 3]; + if (multiplied == Unmultiplied && alpha) { destRows[basex] = (srcRows[basex] * 255) / alpha; destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha; destRows[basex + 2] = (srcRows[basex + 2] * 255) / alpha; @@ -175,7 +177,18 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const return result; } -void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const +{ + return getImageData<Unmultiplied>(rect, m_data, m_size); +} + +PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const +{ + return getImageData<Premultiplied>(rect, m_data, m_size); +} + +template <Multiply multiplied> +void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& imageData, const IntSize& size) { ASSERT(sourceRect.width() > 0); ASSERT(sourceRect.height() > 0); @@ -183,36 +196,36 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, con int originx = sourceRect.x(); int destx = destPoint.x() + sourceRect.x(); ASSERT(destx >= 0); - ASSERT(destx < m_size.width()); + ASSERT(destx < size.width()); ASSERT(originx >= 0); ASSERT(originx <= sourceRect.right()); int endx = destPoint.x() + sourceRect.right(); - ASSERT(endx <= m_size.width()); + ASSERT(endx <= size.width()); int numColumns = endx - destx; int originy = sourceRect.y(); int desty = destPoint.y() + sourceRect.y(); ASSERT(desty >= 0); - ASSERT(desty < m_size.height()); + ASSERT(desty < size.height()); ASSERT(originy >= 0); ASSERT(originy <= sourceRect.bottom()); int endy = destPoint.y() + sourceRect.bottom(); - ASSERT(endy <= m_size.height()); + ASSERT(endy <= size.height()); int numRows = endy - desty; unsigned srcBytesPerRow = 4 * source->width(); - unsigned destBytesPerRow = 4 * m_size.width(); + unsigned destBytesPerRow = 4 * size.width(); unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4; - unsigned char* destRows = reinterpret_cast<unsigned char*>(m_data.m_data) + desty * destBytesPerRow + destx * 4; + unsigned char* destRows = reinterpret_cast<unsigned char*>(imageData.m_data) + desty * destBytesPerRow + destx * 4; for (int y = 0; y < numRows; ++y) { for (int x = 0; x < numColumns; x++) { int basex = x * 4; unsigned char alpha = srcRows[basex + 3]; - if (alpha != 255) { + if (multiplied == Unmultiplied && alpha != 255) { destRows[basex] = (srcRows[basex] * alpha + 254) / 255; destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255; destRows[basex + 2] = (srcRows[basex + 2] * alpha + 254) / 255; @@ -225,6 +238,16 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, con } } +void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<Unmultiplied>(source, sourceRect, destPoint, m_data, m_size); +} + +void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<Premultiplied>(source, sourceRect, destPoint, m_data, m_size); +} + static RetainPtr<CFStringRef> utiFromMIMEType(const String& mimeType) { #if PLATFORM(MAC) diff --git a/WebCore/platform/graphics/cg/ImageCG.cpp b/WebCore/platform/graphics/cg/ImageCG.cpp index a5620e8..4da7018 100644 --- a/WebCore/platform/graphics/cg/ImageCG.cpp +++ b/WebCore/platform/graphics/cg/ImageCG.cpp @@ -101,30 +101,29 @@ BitmapImage::BitmapImage(CGImageRef cgImage, ImageObserver* observer) void BitmapImage::checkForSolidColor() { m_checkedForSolidColor = true; - if (frameCount() > 1) + if (frameCount() > 1) { m_isSolidColor = false; - else { - CGImageRef image = frameAtIndex(0); - - // Currently we only check for solid color in the important special case of a 1x1 image. - if (image && CGImageGetWidth(image) == 1 && CGImageGetHeight(image) == 1) { - unsigned char pixel[4]; // RGBA - CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); - CGContextRef bmap = CGBitmapContextCreate(pixel, 1, 1, 8, sizeof(pixel), space, - kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); - if (bmap) { - GraphicsContext(bmap).setCompositeOperation(CompositeCopy); - CGRect dst = { {0, 0}, {1, 1} }; - CGContextDrawImage(bmap, dst, image); - if (pixel[3] == 0) - m_solidColor = Color(0, 0, 0, 0); - else - m_solidColor = Color(pixel[0] * 255 / pixel[3], pixel[1] * 255 / pixel[3], pixel[2] * 255 / pixel[3], pixel[3]); - m_isSolidColor = true; - CFRelease(bmap); - } - CFRelease(space); - } + return; + } + + CGImageRef image = frameAtIndex(0); + + // Currently we only check for solid color in the important special case of a 1x1 image. + if (image && CGImageGetWidth(image) == 1 && CGImageGetHeight(image) == 1) { + unsigned char pixel[4]; // RGBA + static CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); + RetainPtr<CGContextRef> bmap(AdoptCF, CGBitmapContextCreate(pixel, 1, 1, 8, sizeof(pixel), space, + kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big)); + if (!bmap) + return; + GraphicsContext(bmap.get()).setCompositeOperation(CompositeCopy); + CGRect dst = { {0, 0}, {1, 1} }; + CGContextDrawImage(bmap.get(), dst, image); + if (pixel[3] == 0) + m_solidColor = Color(0, 0, 0, 0); + else + m_solidColor = Color(pixel[0] * 255 / pixel[3], pixel[1] * 255 / pixel[3], pixel[2] * 255 / pixel[3], pixel[3]); + m_isSolidColor = true; } } @@ -252,14 +251,14 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const CGImageRef tileImage = nativeImageForCurrentFrame(); float h = CGImageGetHeight(tileImage); - CGImageRef subImage; + RetainPtr<CGImageRef> subImage; if (tileRect.size() == size()) subImage = tileImage; else { // Copying a sub-image out of a partially-decoded image stops the decoding of the original image. It should never happen // because sub-images are only used for border-image, which only renders when the image is fully decoded. ASSERT(h == height()); - subImage = CGImageCreateWithImageInRect(tileImage, tileRect); + subImage.adoptCF(CGImageCreateWithImageInRect(tileImage, tileRect)); } #ifndef BUILDING_ON_TIGER @@ -275,7 +274,7 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const #else if (w == size().width() && h == size().height()) #endif - CGContextDrawTiledImage(context, FloatRect(adjustedX, adjustedY, scaledTileWidth, scaledTileHeight), subImage); + CGContextDrawTiledImage(context, FloatRect(adjustedX, adjustedY, scaledTileWidth, scaledTileHeight), subImage.get()); else { #endif @@ -288,39 +287,31 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const matrix = CGAffineTransformConcat(matrix, CGContextGetCTM(context)); // The top of a partially-decoded image is drawn at the bottom of the tile. Map it to the top. matrix = CGAffineTransformTranslate(matrix, 0, size().height() - h); - CGPatternRef pattern = CGPatternCreate(subImage, CGRectMake(0, 0, tileRect.width(), tileRect.height()), - matrix, tileRect.width(), tileRect.height(), - kCGPatternTilingConstantSpacing, true, &patternCallbacks); - if (pattern == NULL) { - if (subImage != tileImage) - CGImageRelease(subImage); + RetainPtr<CGPatternRef> pattern(AdoptCF, CGPatternCreate(subImage.get(), CGRectMake(0, 0, tileRect.width(), tileRect.height()), + matrix, tileRect.width(), tileRect.height(), + kCGPatternTilingConstantSpacing, true, &patternCallbacks)); + if (!pattern) { ctxt->restore(); return; } - CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL); + RetainPtr<CGColorSpaceRef> patternSpace(AdoptCF, CGColorSpaceCreatePattern(0)); CGFloat alpha = 1; - CGColorRef color = CGColorCreateWithPattern(patternSpace, pattern, &alpha); - CGContextSetFillColorSpace(context, patternSpace); - CGColorSpaceRelease(patternSpace); - CGPatternRelease(pattern); + RetainPtr<CGColorRef> color(AdoptCF, CGColorCreateWithPattern(patternSpace.get(), pattern.get(), &alpha)); + CGContextSetFillColorSpace(context, patternSpace.get()); // FIXME: Really want a public API for this. It is just CGContextSetBaseCTM(context, CGAffineTransformIdentiy). wkSetPatternBaseCTM(context, CGAffineTransformIdentity); CGContextSetPatternPhase(context, CGSizeZero); - CGContextSetFillColorWithColor(context, color); + CGContextSetFillColorWithColor(context, color.get()); CGContextFillRect(context, CGContextGetClipBoundingBox(context)); - - CGColorRelease(color); - + #ifndef BUILDING_ON_TIGER } #endif - if (subImage != tileImage) - CGImageRelease(subImage); ctxt->restore(); if (imageObserver()) diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp index b716060..66246fe 100644 --- a/WebCore/platform/graphics/cg/ImageSourceCG.cpp +++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp @@ -109,18 +109,16 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived) #if PLATFORM(MAC) // On Mac the NSData inside the SharedBuffer can be secretly appended to without the SharedBuffer's knowledge. We use SharedBuffer's ability // to wrap itself inside CFData to get around this, ensuring that ImageIO is really looking at the SharedBuffer. - CFDataRef cfData = data->createCFData(); + RetainPtr<CFDataRef> cfData(AdoptCF, data->createCFData()); #else // If no NSData is available, then we know SharedBuffer will always just be a vector. That means no secret changes can occur to it behind the // scenes. We use CFDataCreateWithBytesNoCopy in that case. Ensure that the SharedBuffer lives as long as the CFDataRef. data->ref(); CFAllocatorContext context = {0, data, 0, 0, 0, 0, 0, &sharedBufferDerefCallback, 0}; - CFAllocatorRef derefAllocator = CFAllocatorCreate(kCFAllocatorDefault, &context); - CFDataRef cfData = CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data->data()), data->size(), derefAllocator); - CFRelease(derefAllocator); + RetainPtr<CFAllocatorRef> derefAllocator(AdoptCF, CFAllocatorCreate(kCFAllocatorDefault, &context)); + RetainPtr<CFDataRef> cfData(AdoptCF, CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data->data()), data->size(), derefAllocator.get())); #endif - CGImageSourceUpdateData(m_decoder, cfData, allDataReceived); - CFRelease(cfData); + CGImageSourceUpdateData(m_decoder, cfData.get(), allDataReceived); } String ImageSource::filenameExtension() const @@ -138,12 +136,11 @@ bool ImageSource::isSizeAvailable() // Ragnaros yells: TOO SOON! You have awakened me TOO SOON, Executus! if (imageSourceStatus >= kCGImageStatusIncomplete) { - CFDictionaryRef image0Properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions()); + RetainPtr<CFDictionaryRef> image0Properties(AdoptCF, CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions())); if (image0Properties) { - CFNumberRef widthNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties, kCGImagePropertyPixelWidth); - CFNumberRef heightNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties, kCGImagePropertyPixelHeight); + CFNumberRef widthNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties.get(), kCGImagePropertyPixelWidth); + CFNumberRef heightNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties.get(), kCGImagePropertyPixelHeight); result = widthNumber && heightNumber; - CFRelease(image0Properties); } } @@ -153,17 +150,16 @@ bool ImageSource::isSizeAvailable() IntSize ImageSource::frameSizeAtIndex(size_t index) const { IntSize result; - CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions()); + RetainPtr<CFDictionaryRef> properties(AdoptCF, CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions())); if (properties) { int w = 0, h = 0; - CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth); + CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth); if (num) CFNumberGetValue(num, kCFNumberIntType, &w); - num = (CFNumberRef)CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight); + num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight); if (num) CFNumberGetValue(num, kCFNumberIntType, &h); result = IntSize(w, h); - CFRelease(properties); } return result; } @@ -180,17 +176,15 @@ int ImageSource::repetitionCount() return result; // A property with value 0 means loop forever. - CFDictionaryRef properties = CGImageSourceCopyProperties(m_decoder, imageSourceOptions()); + RetainPtr<CFDictionaryRef> properties(AdoptCF, CGImageSourceCopyProperties(m_decoder, imageSourceOptions())); if (properties) { - CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary); + CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary); if (gifProperties) { CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFLoopCount); if (num) CFNumberGetValue(num, kCFNumberIntType, &result); } else result = cAnimationNone; // Turns out we're not a GIF after all, so we don't animate. - - CFRelease(properties); } return result; @@ -206,20 +200,19 @@ CGImageRef ImageSource::createFrameAtIndex(size_t index) if (!initialized()) return 0; - CGImageRef image = CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions()); + RetainPtr<CGImageRef> image(AdoptCF, CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions())); CFStringRef imageUTI = CGImageSourceGetType(m_decoder); static const CFStringRef xbmUTI = CFSTR("public.xbitmap-image"); if (!imageUTI || !CFEqual(imageUTI, xbmUTI)) - return image; + return image.releaseRef(); // If it is an xbm image, mask out all the white areas to render them transparent. const CGFloat maskingColors[6] = {255, 255, 255, 255, 255, 255}; - CGImageRef maskedImage = CGImageCreateWithMaskingColors(image, maskingColors); + RetainPtr<CGImageRef> maskedImage(AdoptCF, CGImageCreateWithMaskingColors(image.get(), maskingColors)); if (!maskedImage) - return image; - - CGImageRelease(image); - return maskedImage; + return image.releaseRef(); + + return maskedImage.releaseRef(); } bool ImageSource::frameIsCompleteAtIndex(size_t index) @@ -233,15 +226,14 @@ float ImageSource::frameDurationAtIndex(size_t index) return 0; float duration = 0; - CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions()); + RetainPtr<CFDictionaryRef> properties(AdoptCF, CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions())); if (properties) { - CFDictionaryRef typeProperties = (CFDictionaryRef)CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary); + CFDictionaryRef typeProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary); if (typeProperties) { CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(typeProperties, kCGImagePropertyGIFDelayTime); if (num) CFNumberGetValue(num, kCFNumberFloatType, &duration); } - CFRelease(properties); } // Many annoying ads specify a 0 duration to make an image flash as quickly as possible. diff --git a/WebCore/platform/graphics/cg/PDFDocumentImage.cpp b/WebCore/platform/graphics/cg/PDFDocumentImage.cpp index 858b18e..2f5c15e 100644 --- a/WebCore/platform/graphics/cg/PDFDocumentImage.cpp +++ b/WebCore/platform/graphics/cg/PDFDocumentImage.cpp @@ -68,16 +68,14 @@ bool PDFDocumentImage::dataChanged(bool allDataReceived) #if PLATFORM(MAC) // On Mac the NSData inside the SharedBuffer can be secretly appended to without the SharedBuffer's knowledge. We use SharedBuffer's ability // to wrap itself inside CFData to get around this, ensuring that ImageIO is really looking at the SharedBuffer. - CFDataRef data = this->data()->createCFData(); + RetainPtr<CFDataRef> data(AdoptCF, this->data()->createCFData()); #else // If no NSData is available, then we know SharedBuffer will always just be a vector. That means no secret changes can occur to it behind the // scenes. We use CFDataCreateWithBytesNoCopy in that case. - CFDataRef data = CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(this->data()->data()), this->data()->size(), kCFAllocatorNull); + RetainPtr<CFDataRef> data(AdoptCF, CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(this->data()->data()), this->data()->size(), kCFAllocatorNull)); #endif - CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data); - CFRelease(data); - m_document = CGPDFDocumentCreateWithProvider(dataProvider); - CGDataProviderRelease(dataProvider); + RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(data.get())); + m_document = CGPDFDocumentCreateWithProvider(dataProvider.get()); setCurrentPage(0); } return m_document; // return true if size is available diff --git a/WebCore/platform/graphics/cg/PathCG.cpp b/WebCore/platform/graphics/cg/PathCG.cpp index 5812cea..3b05641 100644 --- a/WebCore/platform/graphics/cg/PathCG.cpp +++ b/WebCore/platform/graphics/cg/PathCG.cpp @@ -49,9 +49,8 @@ static size_t putBytesNowhere(void*, const void*, size_t count) static CGContextRef createScratchContext() { CGDataConsumerCallbacks callbacks = { putBytesNowhere, 0 }; - CGDataConsumerRef consumer = CGDataConsumerCreate(0, &callbacks); - CGContextRef context = CGPDFContextCreate(consumer, 0, 0); - CGDataConsumerRelease(consumer); + RetainPtr<CGDataConsumerRef> consumer(AdoptCF, CGDataConsumerCreate(0, &callbacks)); + CGContextRef context = CGPDFContextCreate(consumer.get(), 0, 0); CGFloat black[4] = { 0, 0, 0, 1 }; CGContextSetFillColor(context, black); @@ -129,9 +128,8 @@ bool Path::contains(const FloatPoint &point, WindRule rule) const return false; // CGPathContainsPoint returns false for non-closed paths, as a work-around, we copy and close the path first. Radar 4758998 asks for a better CG API to use - CGMutablePathRef path = copyCGPathClosingSubpaths(m_path); - bool ret = CGPathContainsPoint(path, 0, point, rule == RULE_EVENODD ? true : false); - CGPathRelease(path); + RetainPtr<CGMutablePathRef> path(AdoptCF, copyCGPathClosingSubpaths(m_path)); + bool ret = CGPathContainsPoint(path.get(), 0, point, rule == RULE_EVENODD ? true : false); return ret; } diff --git a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp index 9252ae0..e8fa860 100644 --- a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp @@ -261,7 +261,7 @@ static HFONT createFontIndirectAndGetWinName(const String& family, LOGFONT* winf // characters. Because it's family names rather than font faces we use // as keys, there might be edge cases where one face of a font family // has a different repertoire from another face of the same family. -typedef HashMap<const wchar_t*, UnicodeSet*> FontCmapCache; +typedef HashMap<const wchar_t*, icu::UnicodeSet*> FontCmapCache; static bool fontContainsCharacter(const FontPlatformData* fontData, const wchar_t* family, UChar32 character) @@ -277,7 +277,7 @@ static bool fontContainsCharacter(const FontPlatformData* fontData, if (!fontCmapCache) fontCmapCache = new FontCmapCache; - HashMap<const wchar_t*, UnicodeSet*>::iterator it = fontCmapCache->find(family); + HashMap<const wchar_t*, icu::UnicodeSet*>::iterator it = fontCmapCache->find(family); if (it != fontCmapCache->end()) return it->second->contains(character); @@ -308,7 +308,7 @@ static bool fontContainsCharacter(const FontPlatformData* fontData, // 1) port back ICU 4.0's faster look-up code for UnicodeSet // 2) port Mozilla's CompressedCharMap or gfxSparseBitset unsigned i = 0; - UnicodeSet* cmap = new UnicodeSet; + icu::UnicodeSet* cmap = new icu::UnicodeSet; while (i < glyphset->cRanges) { WCHAR start = glyphset->ranges[i].wcLow; cmap->add(start, start + glyphset->ranges[i].cGlyphs - 1); diff --git a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp index 3d67992..229188e 100644 --- a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp @@ -459,14 +459,16 @@ void Font::drawComplexText(GraphicsContext* graphicsContext, TransparencyAwareUniscribePainter painter(graphicsContext, this, run, from, to, point); HDC hdc = painter.hdc(); - if (!hdc) + if (windowsCanHandleTextDrawing(graphicsContext) && !hdc) return; // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency. // Enforce non-transparent color. color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color)); - SetTextColor(hdc, skia::SkColorToCOLORREF(color)); - SetBkMode(hdc, TRANSPARENT); + if (hdc) { + SetTextColor(hdc, skia::SkColorToCOLORREF(color)); + SetBkMode(hdc, TRANSPARENT); + } // If there is a non-blur shadow and both the fill color and shadow color // are opaque, handle without skia. diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp index d4e45fb..dca0efb 100644 --- a/WebCore/platform/graphics/chromium/FontLinux.cpp +++ b/WebCore/platform/graphics/chromium/FontLinux.cpp @@ -45,6 +45,11 @@ #include "SkTypeface.h" #include "SkUtils.h" +#include <unicode/normlzr.h> +#include <unicode/uchar.h> +#include <wtf/OwnArrayPtr.h> +#include <wtf/OwnPtr.h> + namespace WebCore { bool Font::canReturnFallbackFontsForComplexText() @@ -136,27 +141,29 @@ class TextRunWalker { public: TextRunWalker(const TextRun& run, unsigned startingX, const Font* font) : m_font(font) - , m_run(run) , m_startingX(startingX) , m_offsetX(m_startingX) - , m_iterateBackwards(run.rtl()) + , m_run(getTextRun(run)) + , m_iterateBackwards(m_run.rtl()) { + // Do not use |run| inside this constructor. Use |m_run| instead. + memset(&m_item, 0, sizeof(m_item)); // We cannot know, ahead of time, how many glyphs a given script run // will produce. We take a guess that script runs will not produce more // than twice as many glyphs as there are code points and fallback if // we find that we are wrong. - m_maxGlyphs = run.length() * 2; + m_maxGlyphs = m_run.length() * 2; createGlyphArrays(); - m_item.log_clusters = new unsigned short[run.length()]; + m_item.log_clusters = new unsigned short[m_run.length()]; m_item.face = 0; m_item.font = allocHarfbuzzFont(); - m_item.string = run.characters(); - m_item.stringLength = run.length(); - m_item.item.bidiLevel = run.rtl(); + m_item.string = m_run.characters(); + m_item.stringLength = m_run.length(); + m_item.item.bidiLevel = m_run.rtl(); reset(); } @@ -283,6 +290,43 @@ public: } private: + const TextRun& getTextRun(const TextRun& originalRun) + { + // Convert the |originalRun| to NFC normalized form if combining diacritical marks + // (U+0300..) are used in the run. This conversion is necessary since most OpenType + // fonts (e.g., Arial) don't have substitution rules for the diacritical marks in + // their GSUB tables. + // + // Note that we don't use the icu::Normalizer::isNormalized(UNORM_NFC) API here since + // the API returns FALSE (= not normalized) for complex runs that don't require NFC + // normalization (e.g., Arabic text). Unless the run contains the diacritical marks, + // Harfbuzz will do the same thing for us using the GSUB table. + for (unsigned i = 0; i < originalRun.length(); ++i) { + UBlockCode block = ::ublock_getCode(originalRun[i]); + if (block == UBLOCK_COMBINING_DIACRITICAL_MARKS) { + return getNormalizedTextRun(originalRun); + } + } + return originalRun; + } + + const TextRun& getNormalizedTextRun(const TextRun& originalRun) + { + icu::UnicodeString normalizedString; + UErrorCode error = U_ZERO_ERROR; + icu::Normalizer::normalize(icu::UnicodeString(originalRun.characters(), originalRun.length()), UNORM_NFC, 0 /* no options */, normalizedString, error); + if (U_FAILURE(error)) + return originalRun; + + m_normalizedBuffer.set(new UChar[normalizedString.length() + 1]); + normalizedString.extract(m_normalizedBuffer.get(), normalizedString.length() + 1, error); + ASSERT(U_SUCCESS(error)); + + m_normalizedRun.set(new TextRun(originalRun)); + m_normalizedRun->setText(m_normalizedBuffer.get(), normalizedString.length()); + return *m_normalizedRun; + } + void setupFontForScriptRun() { const FontData* fontData = m_font->fontDataAt(0); @@ -379,7 +423,6 @@ private: } const Font* const m_font; - const TextRun& m_run; HB_ShaperItem m_item; uint16_t* m_glyphs16; // A vector of 16-bit glyph ids. SkScalar* m_xPositions; // A vector of x positions for each glyph. @@ -389,6 +432,10 @@ private: unsigned m_pixelWidth; // Width (in px) of the current script run. unsigned m_numCodePoints; // Code points in current script run. unsigned m_maxGlyphs; // Current size of all the Harfbuzz arrays. + + OwnPtr<TextRun> m_normalizedRun; + OwnArrayPtr<UChar> m_normalizedBuffer; // A buffer for normalized run. + const TextRun& m_run; bool m_iterateBackwards; }; diff --git a/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp index 9596a4c..4e2a226 100644 --- a/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp +++ b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp @@ -100,11 +100,11 @@ void initializeScriptFontMap(ScriptToFontMap& scriptFontMap) // Initialize the locale-dependent mapping. // Since Chrome synchronizes the ICU default locale with its UI locale, // this ICU locale tells the current UI locale of Chrome. - Locale locale = Locale::getDefault(); + icu::Locale locale = icu::Locale::getDefault(); const UChar* localeFamily = 0; - if (locale == Locale::getJapanese()) + if (locale == icu::Locale::getJapanese()) localeFamily = scriptFontMap[USCRIPT_HIRAGANA]; - else if (locale == Locale::getKorean()) + else if (locale == icu::Locale::getKorean()) localeFamily = scriptFontMap[USCRIPT_HANGUL]; else { // Use Simplified Chinese font for all other locales including diff --git a/WebCore/platform/graphics/chromium/UniscribeHelper.cpp b/WebCore/platform/graphics/chromium/UniscribeHelper.cpp index 39b0847..10fcdf6 100644 --- a/WebCore/platform/graphics/chromium/UniscribeHelper.cpp +++ b/WebCore/platform/graphics/chromium/UniscribeHelper.cpp @@ -375,11 +375,13 @@ void UniscribeHelper::draw(GraphicsContext* graphicsContext, // Pass 0 in when there is no justification. const int* justify = shaping.m_justify.size() == 0 ? 0 : &shaping.m_justify[fromGlyph]; - if (firstRun) { - oldFont = SelectObject(dc, shaping.m_hfont); - firstRun = false; - } else - SelectObject(dc, shaping.m_hfont); + if (useWindowsDrawing) { + if (firstRun) { + oldFont = SelectObject(dc, shaping.m_hfont); + firstRun = false; + } else + SelectObject(dc, shaping.m_hfont); + } // Fonts with different ascents can be used to render different // runs. 'Across-runs' y-coordinate correction needs to be @@ -401,7 +403,7 @@ void UniscribeHelper::draw(GraphicsContext* graphicsContext, } else { SkPoint origin; origin.fX = curX + + innerOffset; - origin.fY = y + m_ascent - shaping.m_ascentOffset; + origin.fY = y + m_ascent; textOutOk = paintSkiaText(graphicsContext, shaping.m_hfont, glyphCount, diff --git a/WebCore/platform/graphics/filters/FEBlend.cpp b/WebCore/platform/graphics/filters/FEBlend.cpp index 86b702f..2364cc4 100644 --- a/WebCore/platform/graphics/filters/FEBlend.cpp +++ b/WebCore/platform/graphics/filters/FEBlend.cpp @@ -2,6 +2,7 @@ Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> 2004, 2005 Rob Buis <buis@kde.org> 2005 Eric Seidel <eric@webkit.org> + 2009 Dirk Schulze <krit@webkit.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -24,7 +25,13 @@ #if ENABLE(FILTERS) #include "FEBlend.h" +#include "CanvasPixelArray.h" #include "Filter.h" +#include "FloatPoint.h" +#include "GraphicsContext.h" +#include "ImageData.h" + +typedef unsigned char (*BlendType)(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB); namespace WebCore { @@ -61,8 +68,77 @@ void FEBlend::setBlendMode(BlendModeType mode) m_mode = mode; } -void FEBlend::apply(Filter*) +static unsigned char unknown(unsigned char, unsigned char, unsigned char, unsigned char) +{ + return 0; +} + +static unsigned char normal(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char) +{ + return (((255 - alphaA) * colorB + colorA * 255) / 255); +} + +static unsigned char multiply(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB) +{ + return (((255 - alphaA) * colorB + (255 - alphaB + colorB) * colorA) / 255); +} + +static unsigned char screen(unsigned char colorA, unsigned char colorB, unsigned char, unsigned char) +{ + return (((colorB + colorA) * 255 - colorA * colorB) / 255); +} + +static unsigned char darken(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB) +{ + return ((std::min((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255)) / 255); +} + +static unsigned char lighten(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB) { + return ((std::max((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255)) / 255); +} + +void FEBlend::apply(Filter* filter) +{ + m_in->apply(filter); + m_in2->apply(filter); + if (!m_in->resultImage() || !m_in2->resultImage()) + return; + + if (m_mode == FEBLEND_MODE_UNKNOWN) + return; + + if (!getEffectContext()) + return; + + IntRect effectADrawingRect = calculateDrawingIntRect(m_in->subRegion()); + RefPtr<CanvasPixelArray> srcPixelArrayA(m_in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data()); + + IntRect effectBDrawingRect = calculateDrawingIntRect(m_in2->subRegion()); + RefPtr<CanvasPixelArray> srcPixelArrayB(m_in2->resultImage()->getPremultipliedImageData(effectBDrawingRect)->data()); + + IntRect imageRect(IntPoint(), resultImage()->size()); + RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height()); + + // Keep synchronized with BlendModeType + static const BlendType callEffect[] = {unknown, normal, multiply, screen, darken, lighten}; + + ASSERT(srcPixelArrayA->length() == srcPixelArrayB->length()); + for (unsigned pixelOffset = 0; pixelOffset < srcPixelArrayA->length(); pixelOffset += 4) { + unsigned char alphaA = srcPixelArrayA->get(pixelOffset + 3); + unsigned char alphaB = srcPixelArrayB->get(pixelOffset + 3); + for (unsigned channel = 0; channel < 3; ++channel) { + unsigned char colorA = srcPixelArrayA->get(pixelOffset + channel); + unsigned char colorB = srcPixelArrayB->get(pixelOffset + channel); + + unsigned char result = (*callEffect[m_mode])(colorA, colorB, alphaA, alphaB); + imageData->data()->set(pixelOffset + channel, result); + } + unsigned char alphaR = 255 - ((255 - alphaA) * (255 - alphaB)) / 255; + imageData->data()->set(pixelOffset + 3, alphaR); + } + + resultImage()->putPremultipliedImageData(imageData.get(), imageRect, IntPoint()); } void FEBlend::dump() diff --git a/WebCore/platform/graphics/filters/FEBlend.h b/WebCore/platform/graphics/filters/FEBlend.h index b09cd72..31c625f 100644 --- a/WebCore/platform/graphics/filters/FEBlend.h +++ b/WebCore/platform/graphics/filters/FEBlend.h @@ -41,7 +41,7 @@ namespace WebCore { class FEBlend : public FilterEffect { public: static PassRefPtr<FEBlend> create(FilterEffect*, FilterEffect*, BlendModeType); - + FilterEffect* in2() const; void setIn2(FilterEffect*); diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.cpp b/WebCore/platform/graphics/filters/FEColorMatrix.cpp index fb0a194..1e2e552 100644 --- a/WebCore/platform/graphics/filters/FEColorMatrix.cpp +++ b/WebCore/platform/graphics/filters/FEColorMatrix.cpp @@ -166,7 +166,7 @@ void FEColorMatrix::apply(Filter* filter) filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion())); IntRect imageRect(IntPoint(), resultImage()->size()); - PassRefPtr<ImageData> imageData(resultImage()->getImageData(imageRect)); + PassRefPtr<ImageData> imageData(resultImage()->getUnmultipliedImageData(imageRect)); PassRefPtr<CanvasPixelArray> srcPixelArray(imageData->data()); switch (m_type) { @@ -186,7 +186,7 @@ void FEColorMatrix::apply(Filter* filter) break; } - resultImage()->putImageData(imageData.get(), imageRect, IntPoint()); + resultImage()->putUnmultipliedImageData(imageData.get(), imageRect, IntPoint()); } void FEColorMatrix::dump() diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp index 54ac123..43e5edd 100644 --- a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp +++ b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp @@ -2,6 +2,7 @@ Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> 2004, 2005 Rob Buis <buis@kde.org> 2005 Eric Seidel <eric@webkit.org> + 2009 Dirk Schulze <krit@webkit.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -24,10 +25,16 @@ #if ENABLE(FILTERS) #include "FEComponentTransfer.h" +#include "CanvasPixelArray.h" #include "Filter.h" +#include "GraphicsContext.h" +#include "ImageData.h" +#include <math.h> namespace WebCore { +typedef void (*TransferType)(unsigned char*, const ComponentTransferFunction&); + FEComponentTransfer::FEComponentTransfer(FilterEffect* in, const ComponentTransferFunction& redFunc, const ComponentTransferFunction& greenFunc, const ComponentTransferFunction& blueFunc, const ComponentTransferFunction& alphaFunc) : FilterEffect() @@ -85,8 +92,91 @@ void FEComponentTransfer::setAlphaFunction(const ComponentTransferFunction& func m_alphaFunc = func; } -void FEComponentTransfer::apply(Filter*) +void identity(unsigned char*, const ComponentTransferFunction&) +{ +} + +void table(unsigned char* values, const ComponentTransferFunction& transferFunction) +{ + const Vector<float>& tableValues = transferFunction.tableValues; + unsigned n = tableValues.size(); + if (n < 1) + return; + for (unsigned i = 0; i < 256; ++i) { + double c = i / 255.0; + unsigned k = static_cast<unsigned>(c * (n - 1)); + double v1 = tableValues[k]; + double v2 = tableValues[std::min((k + 1), (n - 1))]; + double val = 255.0 * (v1 + (c * (n - 1) - k) * (v2 - v1)); + val = std::max(0.0, std::min(255.0, val)); + values[i] = static_cast<unsigned char>(val); + } +} + +void discrete(unsigned char* values, const ComponentTransferFunction& transferFunction) +{ + const Vector<float>& tableValues = transferFunction.tableValues; + unsigned n = tableValues.size(); + if (n < 1) + return; + for (unsigned i = 0; i < 256; ++i) { + unsigned k = static_cast<unsigned>((i * n) / 255.0); + k = std::min(k, n - 1); + double val = 255 * tableValues[k]; + val = std::max(0.0, std::min(255.0, val)); + values[i] = static_cast<unsigned char>(val); + } +} + +void linear(unsigned char* values, const ComponentTransferFunction& transferFunction) +{ + for (unsigned i = 0; i < 256; ++i) { + double val = transferFunction.slope * i + 255 * transferFunction.intercept; + val = std::max(0.0, std::min(255.0, val)); + values[i] = static_cast<unsigned char>(val); + } +} + +void gamma(unsigned char* values, const ComponentTransferFunction& transferFunction) +{ + for (unsigned i = 0; i < 256; ++i) { + double val = 255.0 * (transferFunction.amplitude * pow((i / 255.0), transferFunction.exponent) + transferFunction.offset); + val = std::max(0.0, std::min(255.0, val)); + values[i] = static_cast<unsigned char>(val); + } +} + +void FEComponentTransfer::apply(Filter* filter) { + m_in->apply(filter); + if (!m_in->resultImage()) + return; + + if (!getEffectContext()) + return; + + unsigned char rValues[256], gValues[256], bValues[256], aValues[256]; + for (unsigned i = 0; i < 256; ++i) + rValues[i] = gValues[i] = bValues[i] = aValues[i] = i; + unsigned char* tables[] = { rValues, gValues, bValues, aValues }; + ComponentTransferFunction transferFunction[] = {m_redFunc, m_greenFunc, m_blueFunc, m_alphaFunc}; + TransferType callEffect[] = {identity, identity, table, discrete, linear, gamma}; + + for (unsigned channel = 0; channel < 4; channel++) + (*callEffect[transferFunction[channel].type])(tables[channel], transferFunction[channel]); + + IntRect drawingRect = calculateDrawingIntRect(m_in->subRegion()); + RefPtr<ImageData> imageData(m_in->resultImage()->getUnmultipliedImageData(drawingRect)); + CanvasPixelArray* srcPixelArray(imageData->data()); + + for (unsigned pixelOffset = 0; pixelOffset < srcPixelArray->length(); pixelOffset += 4) { + for (unsigned channel = 0; channel < 4; ++channel) { + unsigned char c = srcPixelArray->get(pixelOffset + channel); + imageData->data()->set(pixelOffset + channel, tables[channel][c]); + } + } + + resultImage()->putUnmultipliedImageData(imageData.get(), IntRect(IntPoint(), resultImage()->size()), IntPoint()); } void FEComponentTransfer::dump() diff --git a/WebCore/platform/graphics/filters/FEComposite.cpp b/WebCore/platform/graphics/filters/FEComposite.cpp index 0706358..1b41165 100644 --- a/WebCore/platform/graphics/filters/FEComposite.cpp +++ b/WebCore/platform/graphics/filters/FEComposite.cpp @@ -2,6 +2,7 @@ Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org> 2004, 2005 Rob Buis <buis@kde.org> 2005 Eric Seidel <eric@webkit.org> + 2009 Dirk Schulze <krit@webkit.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -24,7 +25,10 @@ #if ENABLE(FILTERS) #include "FEComposite.h" +#include "CanvasPixelArray.h" #include "Filter.h" +#include "GraphicsContext.h" +#include "ImageData.h" namespace WebCore { @@ -97,8 +101,74 @@ void FEComposite::setK4(float k4) m_k4 = k4; } -void FEComposite::apply(Filter*) +inline void arithmetic(const RefPtr<CanvasPixelArray>& srcPixelArrayA, CanvasPixelArray*& srcPixelArrayB, + float k1, float k2, float k3, float k4) { + float scaledK1 = k1 / 255.f; + float scaledK4 = k4 * 255.f; + for (unsigned pixelOffset = 0; pixelOffset < srcPixelArrayA->length(); pixelOffset += 4) { + for (unsigned channel = 0; channel < 4; ++channel) { + unsigned char i1 = srcPixelArrayA->get(pixelOffset + channel); + unsigned char i2 = srcPixelArrayB->get(pixelOffset + channel); + + unsigned char result = scaledK1 * i1 * i2 + k2 * i1 + k3 * i2 + scaledK4; + if (channel == 3 && i1 == 0 && i2 == 0) + result = 0; + srcPixelArrayB->set(pixelOffset + channel, result); + } + } +} + +void FEComposite::apply(Filter* filter) +{ + m_in->apply(filter); + m_in2->apply(filter); + if (!m_in->resultImage() || !m_in2->resultImage()) + return; + + GraphicsContext* filterContext = getEffectContext(); + if (!filterContext) + return; + + FloatRect srcRect = FloatRect(0.f, 0.f, -1.f, -1.f); + switch (m_type) { + case FECOMPOSITE_OPERATOR_OVER: + filterContext->drawImage(m_in2->resultImage()->image(), calculateDrawingRect(m_in2->subRegion())); + filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion())); + break; + case FECOMPOSITE_OPERATOR_IN: + filterContext->save(); + filterContext->clipToImageBuffer(calculateDrawingRect(m_in2->subRegion()), m_in2->resultImage()); + filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion())); + filterContext->restore(); + break; + case FECOMPOSITE_OPERATOR_OUT: + filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion())); + filterContext->drawImage(m_in2->resultImage()->image(), calculateDrawingRect(m_in2->subRegion()), srcRect, CompositeDestinationOut); + break; + case FECOMPOSITE_OPERATOR_ATOP: + filterContext->drawImage(m_in2->resultImage()->image(), calculateDrawingRect(m_in2->subRegion())); + filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion()), srcRect, CompositeSourceAtop); + break; + case FECOMPOSITE_OPERATOR_XOR: + filterContext->drawImage(m_in2->resultImage()->image(), calculateDrawingRect(m_in2->subRegion())); + filterContext->drawImage(m_in->resultImage()->image(), calculateDrawingRect(m_in->subRegion()), srcRect, CompositeXOR); + break; + case FECOMPOSITE_OPERATOR_ARITHMETIC: { + IntRect effectADrawingRect = calculateDrawingIntRect(m_in->subRegion()); + RefPtr<CanvasPixelArray> srcPixelArrayA(m_in->resultImage()->getPremultipliedImageData(effectADrawingRect)->data()); + + IntRect effectBDrawingRect = calculateDrawingIntRect(m_in2->subRegion()); + RefPtr<ImageData> imageData(m_in2->resultImage()->getPremultipliedImageData(effectBDrawingRect)); + CanvasPixelArray* srcPixelArrayB(imageData->data()); + + arithmetic(srcPixelArrayA, srcPixelArrayB, m_k1, m_k2, m_k3, m_k4); + resultImage()->putPremultipliedImageData(imageData.get(), IntRect(IntPoint(), resultImage()->size()), IntPoint()); + } + break; + default: + break; + } } void FEComposite::dump() diff --git a/WebCore/platform/graphics/filters/FilterEffect.cpp b/WebCore/platform/graphics/filters/FilterEffect.cpp index 41e8a39..5818e50 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.cpp +++ b/WebCore/platform/graphics/filters/FilterEffect.cpp @@ -59,6 +59,13 @@ FloatRect FilterEffect::calculateEffectRect(Filter* filter) return subRegion(); } +IntRect FilterEffect::calculateDrawingIntRect(const FloatRect& effectRect) +{ + IntPoint location = roundedIntPoint(FloatPoint(subRegion().x() - effectRect.x(), + subRegion().y() - effectRect.y())); + return IntRect(location, resultImage()->size()); +} + FloatRect FilterEffect::calculateDrawingRect(const FloatRect& srcRect) { FloatPoint startPoint = FloatPoint(srcRect.x() - subRegion().x(), srcRect.y() - subRegion().y()); diff --git a/WebCore/platform/graphics/filters/FilterEffect.h b/WebCore/platform/graphics/filters/FilterEffect.h index 8dc6233..e2b8a0e 100644 --- a/WebCore/platform/graphics/filters/FilterEffect.h +++ b/WebCore/platform/graphics/filters/FilterEffect.h @@ -77,6 +77,7 @@ namespace WebCore { GraphicsContext* getEffectContext(); FloatRect calculateDrawingRect(const FloatRect&); + IntRect calculateDrawingIntRect(const FloatRect&); virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return filter->filterRegion(); } virtual FloatRect calculateEffectRect(Filter*); diff --git a/WebCore/platform/graphics/filters/SourceAlpha.cpp b/WebCore/platform/graphics/filters/SourceAlpha.cpp index 646a57b..57436be 100644 --- a/WebCore/platform/graphics/filters/SourceAlpha.cpp +++ b/WebCore/platform/graphics/filters/SourceAlpha.cpp @@ -22,6 +22,7 @@ #if ENABLE(FILTERS) #include "SourceAlpha.h" +#include "Color.h" #include "GraphicsContext.h" #include "PlatformString.h" #include "Filter.h" @@ -41,8 +42,28 @@ const AtomicString& SourceAlpha::effectName() return s_effectName; } -void SourceAlpha::apply(Filter*) +FloatRect SourceAlpha::calculateEffectRect(Filter* filter) { + FloatRect clippedSourceRect = filter->sourceImageRect(); + if (filter->sourceImageRect().x() < filter->filterRegion().x()) + clippedSourceRect.setX(filter->filterRegion().x()); + if (filter->sourceImageRect().y() < filter->filterRegion().y()) + clippedSourceRect.setY(filter->filterRegion().y()); + setSubRegion(clippedSourceRect); + return filter->filterRegion(); +} + +void SourceAlpha::apply(Filter* filter) +{ + GraphicsContext* filterContext = getEffectContext(); + if (!filterContext) + return; + + FloatRect imageRect(FloatPoint(), filter->sourceImage()->image()->size()); + filterContext->save(); + filterContext->clipToImageBuffer(imageRect, filter->sourceImage()); + filterContext->fillRect(imageRect, Color::black); + filterContext->restore(); } void SourceAlpha::dump() diff --git a/WebCore/platform/graphics/filters/SourceAlpha.h b/WebCore/platform/graphics/filters/SourceAlpha.h index 5341562..172d05a 100644 --- a/WebCore/platform/graphics/filters/SourceAlpha.h +++ b/WebCore/platform/graphics/filters/SourceAlpha.h @@ -35,7 +35,7 @@ namespace WebCore { static const AtomicString& effectName(); virtual bool isSourceInput() { return true; } - virtual FloatRect calculateEffectRect(Filter* filter) { return filter->sourceImageRect(); } + virtual FloatRect calculateEffectRect(Filter*); void apply(Filter*); void dump(); diff --git a/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp b/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp new file mode 100644 index 0000000..a6c2dfb --- /dev/null +++ b/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2009 Igalia S.L + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "DataSourceGStreamer.h" + +#include <gio/gio.h> +#include <glib.h> +#include <gst/gst.h> +#include <gst/pbutils/missing-plugins.h> + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +GST_DEBUG_CATEGORY_STATIC(webkit_data_src_debug); +#define GST_CAT_DEFAULT webkit_data_src_debug + +static void webkit_data_src_uri_handler_init(gpointer g_iface, + gpointer iface_data); + +static void webkit_data_src_finalize(WebkitDataSrc* src); +static GstStateChangeReturn webkit_data_src_change_state(GstElement* element, + GstStateChange transition); + +static const GInterfaceInfo urihandler_info = { + webkit_data_src_uri_handler_init, + 0, 0 +}; + + +static void _do_init(GType datasrc_type) +{ + GST_DEBUG_CATEGORY_INIT(webkit_data_src_debug, "webkit_data_src", 0, "datasrc element"); + g_type_add_interface_static(datasrc_type, GST_TYPE_URI_HANDLER, + &urihandler_info); +} + +GST_BOILERPLATE_FULL(WebkitDataSrc, webkit_data_src, GstBin, GST_TYPE_BIN, _do_init); + +static void webkit_data_src_base_init(gpointer klass) +{ + GstElementClass* element_class = GST_ELEMENT_CLASS(klass); + + gst_element_class_add_pad_template(element_class, + gst_static_pad_template_get(&src_template)); + gst_element_class_set_details_simple(element_class, (gchar*) "WebKit data source element", + (gchar*) "Source", + (gchar*) "Handles data: uris", + (gchar*) "Philippe Normand <pnormand@igalia.com>"); + +} + +static void webkit_data_src_class_init(WebkitDataSrcClass* klass) +{ + GObjectClass* oklass = G_OBJECT_CLASS(klass); + GstElementClass* eklass = GST_ELEMENT_CLASS(klass); + + oklass->finalize = (GObjectFinalizeFunc) webkit_data_src_finalize; + eklass->change_state = webkit_data_src_change_state; +} + + +static gboolean webkit_data_src_reset(WebkitDataSrc* src) +{ + GstPad* targetpad; + + if (src->kid) { + gst_element_set_state(src->kid, GST_STATE_NULL); + gst_bin_remove(GST_BIN(src), src->kid); + } + + src->kid = gst_element_factory_make("giostreamsrc", "streamsrc"); + if (!src->kid) { + GST_ERROR_OBJECT(src, "Failed to create giostreamsrc"); + return FALSE; + } + + gst_bin_add(GST_BIN(src), src->kid); + + targetpad = gst_element_get_static_pad(src->kid, "src"); + gst_ghost_pad_set_target(GST_GHOST_PAD(src->pad), targetpad); + gst_object_unref(targetpad); + + return TRUE; +} + +static void webkit_data_src_init(WebkitDataSrc* src, + WebkitDataSrcClass* g_class) +{ + GstPadTemplate* pad_template = gst_static_pad_template_get(&src_template); + src->pad = gst_ghost_pad_new_no_target_from_template("src", + pad_template); + + gst_element_add_pad(GST_ELEMENT(src), src->pad); + + webkit_data_src_reset(src); +} + +static void webkit_data_src_finalize(WebkitDataSrc* src) +{ + g_free(src->uri); + + if (src->kid) { + GST_DEBUG_OBJECT(src, "Removing giostreamsrc element"); + gst_element_set_state(src->kid, GST_STATE_NULL); + gst_bin_remove(GST_BIN(src), src->kid); + src->kid = 0; + } + + GST_CALL_PARENT(G_OBJECT_CLASS, finalize, ((GObject* )(src))); +} + +static GstStateChangeReturn webkit_data_src_change_state(GstElement* element, GstStateChange transition) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + WebkitDataSrc* src = WEBKIT_DATA_SRC(element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + if (!src->kid) { + gst_element_post_message(element, + gst_missing_element_message_new(element, "giostreamsrc")); + GST_ELEMENT_ERROR(src, CORE, MISSING_PLUGIN, (0), ("no giostreamsrc")); + return GST_STATE_CHANGE_FAILURE; + } + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition); + if (G_UNLIKELY(ret == GST_STATE_CHANGE_FAILURE)) + return ret; + + // Downwards state change code should be here, after chaining up + // to the parent class. + + return ret; +} + +/*** GSTURIHANDLER INTERFACE *************************************************/ + +static GstURIType webkit_data_src_uri_get_type(void) +{ + return GST_URI_SRC; +} + +static gchar** webkit_data_src_uri_get_protocols(void) +{ + static gchar* protocols[] = {(gchar*) "data", 0 }; + + return protocols; +} + +static const gchar* webkit_data_src_uri_get_uri(GstURIHandler* handler) +{ + WebkitDataSrc* src = WEBKIT_DATA_SRC(handler); + + return src->uri; +} + +static gboolean webkit_data_src_uri_set_uri(GstURIHandler* handler, const gchar* uri) +{ + WebkitDataSrc* src = WEBKIT_DATA_SRC(handler); + + // URI as defined in RFC2397: + // "data:" [ mediatype ] [ ";base64" ] "," data + // we parse URIs like this one: + // data:audio/3gpp;base64,AA... + + gchar** scheme_and_remains = g_strsplit(uri, ":", 2); + gchar** mime_type_and_options = g_strsplit(scheme_and_remains[1], ";", 0); + gint options_size = g_strv_length(mime_type_and_options); + gchar* data = 0; + gchar* mime_type = 0; + gint ret = FALSE; + + // we require uris with a specified mime-type and base64-encoded + // data. It doesn't make much sense anyway to play plain/text data + // with very few allowed characters (as per the RFC). + + if (GST_STATE(src) >= GST_STATE_PAUSED) { + GST_ERROR_OBJECT(src, "Element already configured. Reset it and retry"); + } else if (!options_size) + GST_ERROR_OBJECT(src, "A mime-type is needed in %s", uri); + else { + mime_type = mime_type_and_options[0]; + data = mime_type_and_options[options_size-1]; + + guchar* decoded_data = 0; + gsize decoded_size; + + if (!g_str_has_prefix(data, "base64")) + GST_ERROR_OBJECT(src, "Data has to be base64-encoded in %s", uri); + else { + decoded_data = g_base64_decode(data+7, &decoded_size); + GInputStream* stream = g_memory_input_stream_new_from_data(decoded_data, + decoded_size, + g_free); + g_object_set(src->kid, "stream", stream, 0); + g_object_unref(stream); + + if (src->uri) { + g_free(src->uri); + src->uri = 0; + } + + src->uri = g_strdup(uri); + ret = TRUE; + } + } + + g_strfreev(scheme_and_remains); + g_strfreev(mime_type_and_options); + return ret; +} + +static void webkit_data_src_uri_handler_init(gpointer g_iface, gpointer iface_data) +{ + GstURIHandlerInterface* iface = (GstURIHandlerInterface *) g_iface; + + iface->get_type = webkit_data_src_uri_get_type; + iface->get_protocols = webkit_data_src_uri_get_protocols; + iface->get_uri = webkit_data_src_uri_get_uri; + iface->set_uri = webkit_data_src_uri_set_uri; +} diff --git a/WebCore/platform/graphics/gtk/DataSourceGStreamer.h b/WebCore/platform/graphics/gtk/DataSourceGStreamer.h new file mode 100644 index 0000000..3e88f63 --- /dev/null +++ b/WebCore/platform/graphics/gtk/DataSourceGStreamer.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009 Igalia S.L + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef DATA_SOURCE_GSTREAMER_H +#define DATA_SOURCE_GSTREAMER_H + +#include <glib-object.h> +#include <gst/base/gstbasesrc.h> + +G_BEGIN_DECLS + +#define WEBKIT_TYPE_DATA_SRC (webkit_data_src_get_type ()) +#define WEBKIT_DATA_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), WEBKIT_TYPE_DATA_SRC, WebkitDataSrc)) +#define WEBKIT_DATA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), WEBKIT_TYPE_DATA_SRC, WebkitDataSrcClass)) +#define WEBKIT_IS_DATA_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), WEBKIT_TYPE_DATA_SRC)) +#define WEBKIT_IS_DATA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), WEBKIT_TYPE_DATA_SRC)) + +typedef struct _WebkitDataSrc WebkitDataSrc; +typedef struct _WebkitDataSrcClass WebkitDataSrcClass; + + +struct _WebkitDataSrc { + GstBin parent; + + /* explicit pointers to stuff used */ + GstElement* kid; + GstPad* pad; + gchar* uri; +}; + +struct _WebkitDataSrcClass { + GstBinClass parent_class; +}; + +GType webkit_data_src_get_type(void); + +G_END_DECLS + +#endif diff --git a/WebCore/platform/graphics/gtk/FontPlatformData.h b/WebCore/platform/graphics/gtk/FontPlatformData.h index 2a65f1e..d30b480 100644 --- a/WebCore/platform/graphics/gtk/FontPlatformData.h +++ b/WebCore/platform/graphics/gtk/FontPlatformData.h @@ -87,7 +87,7 @@ public: bool syntheticBold() const { return m_syntheticBold; } bool syntheticOblique() const { return m_syntheticOblique; } - void setFont(cairo_t*) const; + cairo_scaled_font_t* scaledFont() const { return m_scaledFont; } unsigned hash() const { diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp index f2c5f0c..0b1280e 100644 --- a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp +++ b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp @@ -224,10 +224,8 @@ FontPlatformData::~FontPlatformData() m_fallbacks = 0; } - if (m_scaledFont) { + if (m_scaledFont) cairo_scaled_font_destroy(m_scaledFont); - m_scaledFont = 0; - } } bool FontPlatformData::isFixedPitch() @@ -242,13 +240,6 @@ bool FontPlatformData::isFixedPitch() return false; } -void FontPlatformData::setFont(cairo_t* cr) const -{ - ASSERT(m_scaledFont); - - cairo_set_scaled_font(cr, m_scaledFont); -} - bool FontPlatformData::operator==(const FontPlatformData& other) const { if (m_pattern == other.m_pattern) diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp index 9ea6811..8a1a5f1 100644 --- a/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp +++ b/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp @@ -214,13 +214,6 @@ bool FontPlatformData::isFixedPitch() return pango_font_family_is_monospace(family); } -void FontPlatformData::setFont(cairo_t* cr) const -{ - ASSERT(m_scaledFont); - - cairo_set_scaled_font(cr, m_scaledFont); -} - FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other) { // Check for self-assignment. diff --git a/WebCore/platform/graphics/gtk/ImageGtk.cpp b/WebCore/platform/graphics/gtk/ImageGtk.cpp index 0e92d6c..38da70d 100644 --- a/WebCore/platform/graphics/gtk/ImageGtk.cpp +++ b/WebCore/platform/graphics/gtk/ImageGtk.cpp @@ -88,26 +88,67 @@ PassRefPtr<Image> Image::loadPlatformResource(const char* name) return img.release(); } +static inline unsigned char* getCairoSurfacePixel(unsigned char* data, uint x, uint y, uint rowStride) +{ + return data + (y * rowStride) + x * 4; +} + +static inline guchar* getGdkPixbufPixel(guchar* data, uint x, uint y, uint rowStride) +{ + return data + (y * rowStride) + x * 4; +} + GdkPixbuf* BitmapImage::getGdkPixbuf() { int width = cairo_image_surface_get_width(frameAtIndex(currentFrame())); int height = cairo_image_surface_get_height(frameAtIndex(currentFrame())); - - int bestDepth = gdk_visual_get_best_depth(); - GdkColormap* cmap = gdk_colormap_new(gdk_visual_get_best_with_depth(bestDepth), true); - - GdkPixmap* pixmap = gdk_pixmap_new(0, width, height, bestDepth); - gdk_drawable_set_colormap(GDK_DRAWABLE(pixmap), cmap); - cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(pixmap)); - cairo_set_source_surface(cr, frameAtIndex(currentFrame()), 0, 0); - cairo_paint(cr); - cairo_destroy(cr); - - GdkPixbuf* pixbuf = gdk_pixbuf_get_from_drawable(0, GDK_DRAWABLE(pixmap), 0, 0, 0, 0, 0, width, height); - g_object_unref(pixmap); - g_object_unref(cmap); - - return pixbuf; + unsigned char* surfaceData = cairo_image_surface_get_data(frameAtIndex(currentFrame())); + int surfaceRowStride = cairo_image_surface_get_stride(frameAtIndex(currentFrame())); + + GdkPixbuf* dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height); + if (!dest) + return 0; + + guchar* pixbufData = gdk_pixbuf_get_pixels(dest); + int pixbufRowStride = gdk_pixbuf_get_rowstride(dest); + + /* From: http://cairographics.org/manual/cairo-image-surface.html#cairo-format-t + * "CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with alpha in + * the upper 8 bits, then red, then green, then blue. The 32-bit + * quantities are stored native-endian. Pre-multiplied alpha is used. + * (That is, 50% transparent red is 0x80800000, not 0x80ff0000.)" + * + * See http://developer.gimp.org/api/2.0/gdk-pixbuf/gdk-pixbuf-gdk-pixbuf.html#GdkPixbuf + * for information on the structure of GdkPixbufs stored with GDK_COLORSPACE_RGB. + * + * RGB color channels in CAIRO_FORMAT_ARGB32 are stored based on the + * endianness of the machine and are also multiplied by the alpha channel. + * To properly transfer the data from the Cairo surface we must divide each + * of the RGB channels by the alpha channel and then reorder all channels + * if this machine is little-endian. + */ + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + unsigned char* source = getCairoSurfacePixel(surfaceData, x, y, surfaceRowStride); + guchar* dest = getGdkPixbufPixel(pixbufData, x, y, pixbufRowStride); + +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + guchar alpha = source[3]; + dest[0] = alpha ? ((source[2] * 255) / alpha) : 0; + dest[1] = alpha ? ((source[1] * 255) / alpha) : 0; + dest[2] = alpha ? ((source[0] * 255) / alpha) : 0; + dest[3] = alpha; +#else + guchar alpha = source[0]; + dest[0] = alpha ? ((source[1] * 255) / alpha) : 0; + dest[1] = alpha ? ((source[2] * 255) / alpha) : 0; + dest[2] = alpha ? ((source[3] * 255) / alpha) : 0; + dest[3] = alpha; +#endif + } + } + + return dest; } } diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp index 4e4bda9..65c64b4 100644 --- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp +++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp @@ -2,6 +2,7 @@ * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. * Copyright (C) 2007 Collabora Ltd. All rights reserved. * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2009 Gustavo Noronha Silva <gns@gnome.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,6 +25,7 @@ #if ENABLE(VIDEO) #include "MediaPlayerPrivateGStreamer.h" +#include "DataSourceGStreamer.h" #include "CString.h" #include "GraphicsContext.h" @@ -35,6 +37,7 @@ #include "ScrollView.h" #include "VideoSinkGStreamer.h" #include "Widget.h" +#include "TimeRanges.h" #include <gst/base/gstbasesrc.h> #include <gst/gst.h> @@ -56,13 +59,19 @@ gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpoin GOwnPtr<gchar> debug; gst_message_parse_error(message, &err.outPtr(), &debug.outPtr()); - if (err->code == 3) { - LOG_VERBOSE(Media, "File not found"); - MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); - if (mp) - mp->loadingFailed(); - } else - LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message); + LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message); + + MediaPlayer::NetworkState error = MediaPlayer::Empty; + if (err->domain == GST_CORE_ERROR || err->domain == GST_LIBRARY_ERROR) + error = MediaPlayer::DecodeError; + else if (err->domain == GST_RESOURCE_ERROR) + error = MediaPlayer::FormatError; + else if (err->domain == GST_STREAM_ERROR) + error = MediaPlayer::NetworkError; + + MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); + if (mp) + mp->loadingFailed(error); } return true; } @@ -112,6 +121,19 @@ void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) registrar(create, getSupportedTypes, supportsType); } +static bool gstInitialized = false; + +static void do_gst_init() { + // FIXME: We should pass the arguments from the command line + if (!gstInitialized) { + gst_init(0, 0); + gstInitialized = true; + gst_element_register(0, "webkitmediasrc", GST_RANK_PRIMARY, + WEBKIT_TYPE_DATA_SRC); + + } +} + MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) : m_player(player) , m_playBin(0) @@ -119,7 +141,6 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) , m_source(0) , m_rate(1.0f) , m_endTime(numeric_limits<float>::infinity()) - , m_isEndReached(false) , m_volume(0.5f) , m_networkState(MediaPlayer::Empty) , m_readyState(MediaPlayer::HaveNothing) @@ -127,19 +148,22 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) , m_isStreaming(false) , m_size(IntSize()) , m_visible(true) + , m_paused(true) + , m_seeking(false) + , m_errorOccured(false) { - - static bool gstInitialized = false; - // FIXME: We should pass the arguments from the command line - if (!gstInitialized) { - gst_init(0, 0); - gstInitialized = true; - } + do_gst_init(); // FIXME: The size shouldn't be fixed here, this is just a quick hack. m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 640, 480); } +static gboolean idleUnref(gpointer data) +{ + g_object_unref(reinterpret_cast<GObject*>(data)); + return FALSE; +} + MediaPlayerPrivate::~MediaPlayerPrivate() { if (m_surface) @@ -149,6 +173,18 @@ MediaPlayerPrivate::~MediaPlayerPrivate() gst_element_set_state(m_playBin, GST_STATE_NULL); gst_object_unref(GST_OBJECT(m_playBin)); } + + // FIXME: We should find a better way to handle the lifetime of this object; this is + // needed because the object is sometimes being destroyed inbetween a call to + // webkit_video_sink_render, and the idle it schedules. Adding a ref in + // webkit_video_sink_render that would be balanced by the idle is not an option, + // because in some cases the destruction of the sink may happen in time for the idle + // to be removed from the queue, so it may not run. It would also cause lots of ref + // counting churn (render/idle are called many times). This is an ugly race. + if (m_videoSink) { + g_idle_add(idleUnref, m_videoSink); + m_videoSink = 0; + } } void MediaPlayerPrivate::load(const String& url) @@ -170,20 +206,13 @@ void MediaPlayerPrivate::load(const String& url) void MediaPlayerPrivate::play() { LOG_VERBOSE(Media, "Play"); - // When end reached, rewind for Test video-seek-past-end-playing - if (m_isEndReached) - seek(0); - m_isEndReached = false; - gst_element_set_state(m_playBin, GST_STATE_PLAYING); - m_startedPlaying = true; } void MediaPlayerPrivate::pause() { LOG_VERBOSE(Media, "Pause"); gst_element_set_state(m_playBin, GST_STATE_PAUSED); - m_startedPlaying = false; } float MediaPlayerPrivate::duration() const @@ -191,17 +220,24 @@ float MediaPlayerPrivate::duration() const if (!m_playBin) return 0.0; + if (m_errorOccured) + return 0.0; + GstFormat timeFormat = GST_FORMAT_TIME; gint64 timeLength = 0; - // FIXME: We try to get the duration, but we do not trust the +#if !GST_CHECK_VERSION(0, 10, 23) + // We try to get the duration, but we do not trust the // return value of the query function only; the problem we are // trying to work-around here is that pipelines in stream mode may // not be able to figure out the duration, but still return true! - // See https://bugs.webkit.org/show_bug.cgi?id=24639. + // See https://bugs.webkit.org/show_bug.cgi?id=24639 which has been + // fixed in gst-plugins-base 0.10.23 if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength) || timeLength <= 0) { +#else + if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength)) { +#endif LOG_VERBOSE(Media, "Time duration query failed."); - m_isStreaming = true; return numeric_limits<float>::infinity(); } @@ -215,22 +251,24 @@ float MediaPlayerPrivate::currentTime() const { if (!m_playBin) return 0; - // Necessary as sometimes, gstreamer return 0:00 at the EOS - if (m_isEndReached) - return m_endTime; - float ret; + if (m_errorOccured) + return 0; + + float ret = 0.0; GstQuery* query = gst_query_new_position(GST_FORMAT_TIME); - if (gst_element_query(m_playBin, query)) { - gint64 position; - gst_query_parse_position(query, 0, &position); - ret = (float) (position / 1000000000.0); - LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position)); - } else { + if (!gst_element_query(m_playBin, query)) { LOG_VERBOSE(Media, "Position query failed..."); - ret = 0.0; + gst_query_unref(query); + return ret; } + + gint64 position; + gst_query_parse_position(query, 0, &position); + ret = (float) (position / 1000000000.0); + LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position)); + gst_query_unref(query); return ret; @@ -246,35 +284,23 @@ void MediaPlayerPrivate::seek(float time) if (m_isStreaming) return; + if (m_errorOccured) + return; + LOG_VERBOSE(Media, "Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(sec)); - // FIXME: What happens when the seeked position is not available? if (!gst_element_seek( m_playBin, m_rate, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET, sec, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) LOG_VERBOSE(Media, "Seek to %f failed", time); + else + m_seeking = true; } void MediaPlayerPrivate::setEndTime(float time) { - if (!m_playBin) - return; - if (m_isStreaming) - return; - if (m_endTime != time) { - m_endTime = time; - GstClockTime start = (GstClockTime)(currentTime() * GST_SECOND); - GstClockTime end = (GstClockTime)(time * GST_SECOND); - LOG_VERBOSE(Media, "setEndTime: %" GST_TIME_FORMAT, GST_TIME_ARGS(end)); - // FIXME: What happens when the seeked position is not available? - if (!gst_element_seek(m_playBin, m_rate, - GST_FORMAT_TIME, - (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), - GST_SEEK_TYPE_SET, start, - GST_SEEK_TYPE_SET, end)) - LOG_VERBOSE(Media, "Seek to %f failed", time); - } + notImplemented(); } void MediaPlayerPrivate::startEndPointTimerIfNeeded() @@ -294,12 +320,12 @@ void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*) bool MediaPlayerPrivate::paused() const { - return !m_startedPlaying; + return m_paused; } bool MediaPlayerPrivate::seeking() const { - return false; + return m_seeking; } // Returns the size of the video @@ -308,13 +334,28 @@ IntSize MediaPlayerPrivate::naturalSize() const if (!hasVideo()) return IntSize(); - int x = 0, y = 0; + // TODO: handle possible clean aperture data. See + // https://bugzilla.gnome.org/show_bug.cgi?id=596571 + // TODO: handle possible transformation matrix. See + // https://bugzilla.gnome.org/show_bug.cgi?id=596326 + int width = 0, height = 0; if (GstPad* pad = gst_element_get_static_pad(m_videoSink, "sink")) { - gst_video_get_size(GST_PAD(pad), &x, &y); + gst_video_get_size(GST_PAD(pad), &width, &height); + GstCaps* caps = GST_PAD_CAPS(pad); + gfloat pixelAspectRatio; + gint pixelAspectRatioNumerator, pixelAspectRatioDenominator; + + if (!gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator, + &pixelAspectRatioDenominator)) + pixelAspectRatioNumerator = pixelAspectRatioDenominator = 1; + + pixelAspectRatio = (gfloat) pixelAspectRatioNumerator / (gfloat) pixelAspectRatioDenominator; + width *= pixelAspectRatio; + height /= pixelAspectRatio; gst_object_unref(GST_OBJECT(pad)); } - return IntSize(x, y); + return IntSize(width, height); } bool MediaPlayerPrivate::hasVideo() const @@ -325,24 +366,31 @@ bool MediaPlayerPrivate::hasVideo() const return currentVideo > -1; } +bool MediaPlayerPrivate::hasAudio() const +{ + gint currentAudio = -1; + if (m_playBin) + g_object_get(G_OBJECT(m_playBin), "current-audio", ¤tAudio, NULL); + return currentAudio > -1; +} + void MediaPlayerPrivate::setVolume(float volume) { m_volume = volume; LOG_VERBOSE(Media, "Volume to %f", volume); - setMuted(false); + + if (!m_playBin) + return; + + g_object_set(G_OBJECT(m_playBin), "volume", m_volume, NULL); } -void MediaPlayerPrivate::setMuted(bool b) +void MediaPlayerPrivate::setMuted(bool mute) { if (!m_playBin) return; - if (b) { - g_object_get(G_OBJECT(m_playBin), "volume", &m_volume, NULL); - g_object_set(G_OBJECT(m_playBin), "volume", (double)0.0, NULL); - } else - g_object_set(G_OBJECT(m_playBin), "volume", m_volume, NULL); - + g_object_set(G_OBJECT(m_playBin), "mute", mute, NULL); } void MediaPlayerPrivate::setRate(float rate) @@ -351,17 +399,13 @@ void MediaPlayerPrivate::setRate(float rate) gst_element_set_state(m_playBin, GST_STATE_PAUSED); return; } + if (m_isStreaming) return; m_rate = rate; LOG_VERBOSE(Media, "Set Rate to %f", rate); - if (!gst_element_seek(m_playBin, rate, - GST_FORMAT_TIME, - (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), - GST_SEEK_TYPE_SET, (GstClockTime) (currentTime() * GST_SECOND), - GST_SEEK_TYPE_SET, (GstClockTime) (m_endTime * GST_SECOND))) - LOG_VERBOSE(Media, "Set Rate to %f failed", rate); + seek(currentTime()); } int MediaPlayerPrivate::dataRate() const @@ -380,16 +424,20 @@ MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const return m_readyState; } -float MediaPlayerPrivate::maxTimeBuffered() const +PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const { - notImplemented(); - LOG_VERBOSE(Media, "maxTimeBuffered"); - // rtsp streams are not buffered - return m_isStreaming ? 0 : maxTimeLoaded(); + RefPtr<TimeRanges> timeRanges = TimeRanges::create(); + float loaded = maxTimeLoaded(); + if (!m_errorOccured && !m_isStreaming && loaded > 0) + timeRanges->add(0, loaded); + return timeRanges.release(); } float MediaPlayerPrivate::maxTimeSeekable() const { + if (m_errorOccured) + return 0.0; + // TODO LOG_VERBOSE(Media, "maxTimeSeekable"); if (m_isStreaming) @@ -400,6 +448,9 @@ float MediaPlayerPrivate::maxTimeSeekable() const float MediaPlayerPrivate::maxTimeLoaded() const { + if (m_errorOccured) + return 0.0; + // TODO LOG_VERBOSE(Media, "maxTimeLoaded"); notImplemented(); @@ -416,29 +467,30 @@ unsigned MediaPlayerPrivate::bytesLoaded() const float maxTime = maxTimeLoaded(); if (!dur) return 0;*/ + return 1;//totalBytes() * maxTime / dur; } bool MediaPlayerPrivate::totalBytesKnown() const { - notImplemented(); LOG_VERBOSE(Media, "totalBytesKnown"); return totalBytes() > 0; } unsigned MediaPlayerPrivate::totalBytes() const { - notImplemented(); LOG_VERBOSE(Media, "totalBytes"); - if (!m_playBin) + if (!m_source) return 0; - if (!m_source) + if (m_errorOccured) return 0; - // Do something with m_source to get the total bytes of the media + GstFormat fmt = GST_FORMAT_BYTES; + gint64 length = 0; + gst_element_query_duration(m_source, &fmt, &length); - return 100; + return length; } void MediaPlayerPrivate::cancelLoad() @@ -452,17 +504,21 @@ void MediaPlayerPrivate::updateStates() // the state of GStreamer, therefore, when in PAUSED state, // we are sure we can display the first frame and go to play + if (!m_playBin) + return; + + if (m_errorOccured) + return; + MediaPlayer::NetworkState oldNetworkState = m_networkState; MediaPlayer::ReadyState oldReadyState = m_readyState; GstState state; GstState pending; - if (!m_playBin) - return; - GstStateChangeReturn ret = gst_element_get_state(m_playBin, &state, &pending, 250 * GST_NSECOND); + bool shouldUpdateAfterSeek = false; switch (ret) { case GST_STATE_CHANGE_SUCCESS: LOG_VERBOSE(Media, "State: %s, pending: %s", @@ -474,6 +530,16 @@ void MediaPlayerPrivate::updateStates() } else if (state == GST_STATE_PAUSED) m_readyState = MediaPlayer::HaveEnoughData; + if (state == GST_STATE_PLAYING) + m_paused = false; + else + m_paused = true; + + if (m_seeking) { + shouldUpdateAfterSeek = true; + m_seeking = false; + } + m_networkState = MediaPlayer::Loaded; g_object_get(m_playBin, "source", &m_source, NULL); @@ -486,11 +552,17 @@ void MediaPlayerPrivate::updateStates() gst_element_state_get_name(pending)); // Change in progress return; - break; + case GST_STATE_CHANGE_FAILURE: + LOG_VERBOSE(Media, "Failure: State: %s, pending: %s", + gst_element_state_get_name(state), + gst_element_state_get_name(pending)); + // Change failed + return; case GST_STATE_CHANGE_NO_PREROLL: LOG_VERBOSE(Media, "No preroll: State: %s, pending: %s", gst_element_state_get_name(state), gst_element_state_get_name(pending)); + if (state == GST_STATE_READY) { m_readyState = MediaPlayer::HaveFutureData; } else if (state == GST_STATE_PAUSED) @@ -506,6 +578,9 @@ void MediaPlayerPrivate::updateStates() if (seeking()) m_readyState = MediaPlayer::HaveNothing; + if (shouldUpdateAfterSeek) + timeChanged(); + if (m_networkState != oldNetworkState) { LOG_VERBOSE(Media, "Network State Changed from %u to %u", oldNetworkState, m_networkState); @@ -546,15 +621,14 @@ void MediaPlayerPrivate::volumeChanged() void MediaPlayerPrivate::didEnd() { - m_isEndReached = true; - pause(); timeChanged(); } -void MediaPlayerPrivate::loadingFailed() +void MediaPlayerPrivate::loadingFailed(MediaPlayer::NetworkState error) { - if (m_networkState != MediaPlayer::NetworkError) { - m_networkState = MediaPlayer::NetworkError; + m_errorOccured = true; + if (m_networkState != error) { + m_networkState = error; m_player->networkStateChanged(); } if (m_readyState != MediaPlayer::HaveNothing) { @@ -565,7 +639,18 @@ void MediaPlayerPrivate::loadingFailed() void MediaPlayerPrivate::setSize(const IntSize& size) { + // Destroy and re-create the cairo surface only if the size + // changed. + if (size != m_size) { + if (m_surface) + cairo_surface_destroy(m_surface); + m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, size.width(), + size.height()); + g_object_set(m_videoSink, "surface", m_surface, 0); + } + m_size = size; + } void MediaPlayerPrivate::setVisible(bool visible) @@ -586,11 +671,12 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect) if (!m_visible) return; - //TODO: m_size vs rect? cairo_t* cr = context->platformContext(); cairo_save(cr); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + + // paint the rectangle on the context and draw the surface inside. cairo_translate(cr, rect.x(), rect.y()); cairo_rectangle(cr, 0, 0, rect.width(), rect.height()); cairo_set_source_surface(cr, m_surface, 0, 0); @@ -598,24 +684,124 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect) cairo_restore(cr); } +static HashSet<String> mimeTypeCache() +{ + + do_gst_init(); + + static HashSet<String> cache; + static bool typeListInitialized = false; + + if (!typeListInitialized) { + // These subtypes are already beeing supported by WebKit itself + HashSet<String> ignoredApplicationSubtypes; + ignoredApplicationSubtypes.add(String("javascript")); + ignoredApplicationSubtypes.add(String("ecmascript")); + ignoredApplicationSubtypes.add(String("x-javascript")); + ignoredApplicationSubtypes.add(String("xml")); + ignoredApplicationSubtypes.add(String("xhtml+xml")); + ignoredApplicationSubtypes.add(String("rss+xml")); + ignoredApplicationSubtypes.add(String("atom+xml")); + ignoredApplicationSubtypes.add(String("x-ftp-directory")); + ignoredApplicationSubtypes.add(String("x-java-applet")); + ignoredApplicationSubtypes.add(String("x-java-bean")); + ignoredApplicationSubtypes.add(String("x-java-vm")); + ignoredApplicationSubtypes.add(String("x-shockwave-flash")); + + GList* factories = gst_type_find_factory_get_list(); + for (GList* iterator = factories; iterator; iterator = iterator->next) { + GstTypeFindFactory* factory = GST_TYPE_FIND_FACTORY(iterator->data); + GstCaps* caps = gst_type_find_factory_get_caps(factory); + + // Splitting the capability by comma and taking the first part + // as capability can be something like "audio/x-wavpack, framed=(boolean)false" + GOwnPtr<gchar> capabilityString(gst_caps_to_string(caps)); + gchar** capability = g_strsplit(capabilityString.get(), ",", 2); + gchar** mimetype = g_strsplit(capability[0], "/", 2); + + // GStreamer plugins can be capable of supporting types which WebKit supports + // by default. In that case, we should not consider these types supportable by GStreamer. + // Examples of what GStreamer can support but should not be added: + // text/plain, text/html, image/jpeg, application/xml + if (g_str_equal(mimetype[0], "audio") || + g_str_equal(mimetype[0], "video") || + (g_str_equal(mimetype[0], "application") && + !ignoredApplicationSubtypes.contains(String(mimetype[1])))) { + cache.add(String(capability[0])); + + // These formats are supported by GStreamer, but not correctly advertised + if (g_str_equal(capability[0], "video/x-h264") || + g_str_equal(capability[0], "audio/x-m4a")) { + cache.add(String("video/mp4")); + cache.add(String("audio/aac")); + } + + if (g_str_equal(capability[0], "video/x-theora")) + cache.add(String("video/ogg")); + + if (g_str_equal(capability[0], "audio/x-wav")) + cache.add(String("audio/wav")); + + if (g_str_equal(capability[0], "audio/mpeg")) { + // This is what we are handling: mpegversion=(int)1, layer=(int)[ 1, 3 ] + gchar** versionAndLayer = g_strsplit(capability[1], ",", 2); + + if (g_str_has_suffix (versionAndLayer[0], "(int)1")) { + for (int i = 0; versionAndLayer[1][i] != '\0'; i++) { + if (versionAndLayer[1][i] == '1') + cache.add(String("audio/mp1")); + else if (versionAndLayer[1][i] == '2') + cache.add(String("audio/mp2")); + else if (versionAndLayer[1][i] == '3') + cache.add(String("audio/mp3")); + } + } + + g_strfreev(versionAndLayer); + } + } + + g_strfreev(capability); + g_strfreev(mimetype); + } + + gst_plugin_feature_list_free(factories); + typeListInitialized = true; + } + + return cache; +} + void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types) { - // FIXME: query the engine to see what types are supported - notImplemented(); - types.add(String("video/x-theora+ogg")); + types = mimeTypeCache(); } MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs) { - // FIXME: query the engine to see what types are supported - notImplemented(); - return type == "video/x-theora+ogg" ? (codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported; + if (type.isNull() || type.isEmpty()) + return MediaPlayer::IsNotSupported; + + // spec says we should not return "probably" if the codecs string is empty + if (mimeTypeCache().contains(type)) + return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported; + return MediaPlayer::IsNotSupported; +} + +bool MediaPlayerPrivate::hasSingleSecurityOrigin() const +{ + return true; +} + +bool MediaPlayerPrivate::supportsFullscreen() const +{ + return true; } void MediaPlayerPrivate::createGSTPlayBin(String url) { ASSERT(!m_playBin); - m_playBin = gst_element_factory_make("playbin", "play"); + m_playBin = gst_element_factory_make("playbin2", "play"); GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_playBin)); gst_bus_add_signal_watch(bus); @@ -627,10 +813,12 @@ void MediaPlayerPrivate::createGSTPlayBin(String url) g_object_set(G_OBJECT(m_playBin), "uri", url.utf8().data(), NULL); - GstElement* audioSink = gst_element_factory_make("gconfaudiosink", 0); m_videoSink = webkit_video_sink_new(m_surface); - g_object_set(m_playBin, "audio-sink", audioSink, NULL); + // This ref is to protect the sink from being destroyed before we stop the idle it + // creates internally. See the comment in ~MediaPlayerPrivate. + g_object_ref(m_videoSink); + g_object_set(m_playBin, "video-sink", m_videoSink, NULL); g_signal_connect(m_videoSink, "repaint-requested", G_CALLBACK(mediaPlayerPrivateRepaintCallback), this); @@ -641,4 +829,3 @@ void MediaPlayerPrivate::createGSTPlayBin(String url) } #endif - diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h index 8842f84..d305759 100644 --- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h +++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h @@ -56,6 +56,7 @@ namespace WebCore { IntSize naturalSize() const; bool hasVideo() const; + bool hasAudio() const; void load(const String &url); void cancelLoad(); @@ -80,7 +81,7 @@ namespace WebCore { MediaPlayer::NetworkState networkState() const; MediaPlayer::ReadyState readyState() const; - float maxTimeBuffered() const; + PassRefPtr<TimeRanges> buffered() const; float maxTimeSeekable() const; unsigned bytesLoaded() const; bool totalBytesKnown() const; @@ -95,11 +96,15 @@ namespace WebCore { void timeChanged(); void volumeChanged(); void didEnd(); - void loadingFailed(); + void loadingFailed(MediaPlayer::NetworkState); void repaint(); void paint(GraphicsContext*, const IntRect&); + bool hasSingleSecurityOrigin() const; + + bool supportsFullscreen() const; + private: MediaPlayerPrivate(MediaPlayer*); static MediaPlayerPrivateInterface* create(MediaPlayer* player); @@ -132,6 +137,10 @@ namespace WebCore { IntSize m_size; bool m_visible; cairo_surface_t* m_surface; + + bool m_paused; + bool m_seeking; + bool m_errorOccured; }; } diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp index a77c1cf..9a616f4 100644 --- a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp +++ b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp @@ -50,9 +50,9 @@ void SimpleFontData::platformInit() cairo_font_extents_t font_extents; cairo_text_extents_t text_extents; cairo_scaled_font_extents(m_platformData.m_scaledFont, &font_extents); - m_ascent = static_cast<int>(font_extents.ascent); - m_descent = static_cast<int>(font_extents.descent); - m_lineSpacing = static_cast<int>(font_extents.height); + m_ascent = static_cast<int>(lroundf(font_extents.ascent)); + m_descent = static_cast<int>(lroundf(font_extents.descent)); + m_lineSpacing = static_cast<int>(lroundf(font_extents.height)); // There seems to be some rounding error in cairo (or in how we // use cairo) with some fonts, like DejaVu Sans Mono, which makes // cairo report a height smaller than ascent + descent, which is @@ -63,7 +63,7 @@ void SimpleFontData::platformInit() cairo_scaled_font_text_extents(m_platformData.m_scaledFont, "x", &text_extents); m_xHeight = text_extents.height; cairo_scaled_font_text_extents(m_platformData.m_scaledFont, " ", &text_extents); - m_spaceWidth = static_cast<int>(text_extents.x_advance); + m_spaceWidth = static_cast<float>(text_extents.x_advance); m_lineGap = m_lineSpacing - m_ascent - m_descent; m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; } @@ -130,10 +130,4 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const return w; } -void SimpleFontData::setFont(cairo_t* cr) const -{ - ASSERT(cr); - m_platformData.setFont(cr); -} - } diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp index e57d9e6..975143e 100644 --- a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp +++ b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp @@ -49,9 +49,9 @@ void SimpleFontData::platformInit() cairo_font_extents_t font_extents; cairo_text_extents_t text_extents; cairo_scaled_font_extents(m_platformData.m_scaledFont, &font_extents); - m_ascent = static_cast<int>(font_extents.ascent); - m_descent = static_cast<int>(font_extents.descent); - m_lineSpacing = static_cast<int>(font_extents.height); + m_ascent = static_cast<int>(lroundf(font_extents.ascent)); + m_descent = static_cast<int>(lroundf(font_extents.descent)); + m_lineSpacing = static_cast<int>(lroundf(font_extents.height)); // There seems to be some rounding error in cairo (or in how we // use cairo) with some fonts, like DejaVu Sans Mono, which makes // cairo report a height smaller than ascent + descent, which is @@ -62,7 +62,7 @@ void SimpleFontData::platformInit() cairo_scaled_font_text_extents(m_platformData.m_scaledFont, "x", &text_extents); m_xHeight = text_extents.height; cairo_scaled_font_text_extents(m_platformData.m_scaledFont, " ", &text_extents); - m_spaceWidth = static_cast<int>(text_extents.x_advance); + m_spaceWidth = static_cast<float>(text_extents.x_advance); m_lineGap = m_lineSpacing - m_ascent - m_descent; m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; } @@ -133,10 +133,4 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const return w; } -void SimpleFontData::setFont(cairo_t* cr) const -{ - ASSERT(cr); - m_platformData.setFont(cr); -} - } diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp index f049998..fb86fe9 100644 --- a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp +++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp @@ -33,8 +33,14 @@ #include <gst/video/video.h> static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE("sink", - GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS(GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx)); + GST_PAD_SINK, GST_PAD_ALWAYS, +// CAIRO_FORMAT_RGB24 used to render the video buffers is little/big endian dependant. +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + GST_STATIC_CAPS(GST_VIDEO_CAPS_BGRx) +#else + GST_STATIC_CAPS(GST_VIDEO_CAPS_xRGB) +#endif +); GST_DEBUG_CATEGORY_STATIC(webkit_video_sink_debug); #define GST_CAT_DEFAULT webkit_video_sink_debug @@ -102,9 +108,14 @@ webkit_video_sink_init(WebKitVideoSink* sink, WebKitVideoSinkClass* klass) static gboolean webkit_video_sink_idle_func(gpointer data) { - WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(data); + WebKitVideoSink* sink = reinterpret_cast<WebKitVideoSink*>(data); WebKitVideoSinkPrivate* priv = sink->priv; GstBuffer* buffer; + GstCaps* caps; + GstVideoFormat format; + gint par_n, par_d; + gfloat par; + gint bwidth, bheight; if (!priv->async_queue) return FALSE; @@ -113,19 +124,35 @@ webkit_video_sink_idle_func(gpointer data) if (!buffer || G_UNLIKELY(!GST_IS_BUFFER(buffer))) return FALSE; + caps = GST_BUFFER_CAPS(buffer); + if (!gst_video_format_parse_caps(caps, &format, &bwidth, &bheight)) { + GST_ERROR_OBJECT(sink, "Unknown video format in buffer caps '%s'", + gst_caps_to_string(caps)); + return FALSE; + } + + if (!gst_video_parse_caps_pixel_aspect_ratio(caps, &par_n, &par_d)) + par_n = par_d = 1; + + par = (gfloat) par_n / (gfloat) par_d; + // TODO: consider priv->rgb_ordering? - cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(buffer), CAIRO_FORMAT_RGB24, priv->width, priv->height, (4 * priv->width + 3) & ~3); + cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(buffer), + CAIRO_FORMAT_RGB24, + bwidth, bheight, + 4 * bwidth); // TODO: We copy the data twice right now. This could be easily improved. cairo_t* cr = cairo_create(priv->surface); + cairo_scale(cr, par, 1.0 / par); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_set_source_surface(cr, src, 0, 0); cairo_surface_destroy(src); cairo_rectangle(cr, 0, 0, priv->width, priv->height); cairo_fill(cr); cairo_destroy(cr); - gst_buffer_unref(buffer); + g_async_queue_unref(priv->async_queue); g_signal_emit(sink, webkit_video_sink_signals[REPAINT_REQUESTED], 0); @@ -138,6 +165,7 @@ webkit_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer) WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink); WebKitVideoSinkPrivate* priv = sink->priv; + g_async_queue_ref(priv->async_queue); g_async_queue_push(priv->async_queue, gst_buffer_ref(buffer)); g_idle_add_full(G_PRIORITY_HIGH_IDLE, webkit_video_sink_idle_func, sink, 0); @@ -151,9 +179,7 @@ webkit_video_sink_set_caps(GstBaseSink* bsink, GstCaps* caps) WebKitVideoSinkPrivate* priv = sink->priv; GstStructure* structure; gboolean ret; - const GValue* fps; - const GValue* par; - gint width, height; + gint width, height, fps_n, fps_d; int red_mask; GstCaps* intersection = gst_caps_intersect(gst_static_pad_template_get_caps(&sinktemplate), caps); @@ -167,25 +193,19 @@ webkit_video_sink_set_caps(GstBaseSink* bsink, GstCaps* caps) ret = gst_structure_get_int(structure, "width", &width); ret &= gst_structure_get_int(structure, "height", &height); - fps = gst_structure_get_value(structure, "framerate"); - ret &= (fps != 0); - - par = gst_structure_get_value(structure, "pixel-aspect-ratio"); - if (!ret) - return FALSE; + /* We dont yet use fps but handy to have */ + ret &= gst_structure_get_fraction(structure, "framerate", + &fps_n, &fps_d); + g_return_val_if_fail(ret, FALSE); priv->width = width; priv->height = height; + priv->fps_n = fps_n; + priv->fps_d = fps_d; - /* We dont yet use fps or pixel aspect into but handy to have */ - priv->fps_n = gst_value_get_fraction_numerator(fps); - priv->fps_d = gst_value_get_fraction_denominator(fps); - - if (par) { - priv->par_n = gst_value_get_fraction_numerator(par); - priv->par_d = gst_value_get_fraction_denominator(par); - } else + if (!gst_structure_get_fraction(structure, "pixel-aspect-ratio", + &priv->par_n, &priv->par_d)) priv->par_n = priv->par_d = 1; gst_structure_get_int(structure, "red_mask", &red_mask); @@ -265,6 +285,8 @@ webkit_video_sink_stop(GstBaseSink* base_sink) g_async_queue_unlock(priv->async_queue); + g_idle_remove_by_data(base_sink); + return TRUE; } diff --git a/WebCore/platform/graphics/haiku/ColorHaiku.cpp b/WebCore/platform/graphics/haiku/ColorHaiku.cpp new file mode 100644 index 0000000..a9ac186 --- /dev/null +++ b/WebCore/platform/graphics/haiku/ColorHaiku.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Color.h" + +#include <InterfaceDefs.h> + + +namespace WebCore { + +Color::Color(const rgb_color& color) + : m_color(makeRGBA(color.red, color.green, color.blue, color.alpha)) + , m_valid(true) +{ +} + +Color::operator rgb_color() const +{ + return make_color(red(), green(), blue(), alpha()); +} + + +Color focusRingColor() +{ + return Color(keyboard_navigation_color()); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/FloatPointHaiku.cpp b/WebCore/platform/graphics/haiku/FloatPointHaiku.cpp new file mode 100644 index 0000000..0f50898 --- /dev/null +++ b/WebCore/platform/graphics/haiku/FloatPointHaiku.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FloatPoint.h" + +#include <Point.h> + + +namespace WebCore { + +FloatPoint::FloatPoint(const BPoint& point) + : m_x(point.x) + , m_y(point.y) +{ +} + +FloatPoint::operator BPoint() const +{ + return BPoint(m_x, m_y); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/FloatRectHaiku.cpp b/WebCore/platform/graphics/haiku/FloatRectHaiku.cpp new file mode 100644 index 0000000..67af3af --- /dev/null +++ b/WebCore/platform/graphics/haiku/FloatRectHaiku.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FloatRect.h" + +#include <Rect.h> + + +namespace WebCore { + +FloatRect::FloatRect(const BRect& rect) + : m_location(rect.LeftTop()) + , m_size(rect.Width(), rect.Height()) +{ +} + +FloatRect::operator BRect() const +{ + return BRect(BPoint(x(), y()), BSize(width(), height())); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/FontCacheHaiku.cpp b/WebCore/platform/graphics/haiku/FontCacheHaiku.cpp new file mode 100644 index 0000000..b99bf42 --- /dev/null +++ b/WebCore/platform/graphics/haiku/FontCacheHaiku.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2006 Dirk Mueller <mueller@kde.org> + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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 "FontCache.h" + +#include "Font.h" +#include "FontData.h" +#include "FontPlatformData.h" +#include "NotImplemented.h" +#include <String.h> + + +namespace WebCore { + +void FontCache::platformInit() +{ +} + +const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length) +{ + FontPlatformData data(font.fontDescription(), font.family().family()); + return getCachedFontData(&data); +} + +FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) +{ + notImplemented(); + return 0; +} + +FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription) +{ + // FIXME: Would be even better to somehow get the user's default font here. + // For now we'll pick the default that the user would get without changing any prefs. + static AtomicString defaultString("DejaVu Serif"); + return getCachedFontPlatformData(fontDescription, defaultString); +} + +FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) +{ + return new FontPlatformData(fontDescription, family); +} + +void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks) +{ + notImplemented(); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/FontCustomPlatformData.cpp b/WebCore/platform/graphics/haiku/FontCustomPlatformData.cpp new file mode 100644 index 0000000..6008bb1 --- /dev/null +++ b/WebCore/platform/graphics/haiku/FontCustomPlatformData.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "FontCustomPlatformData.h" + +#include "SharedBuffer.h" +#include "FontPlatformData.h" + + +namespace WebCore { + +FontCustomPlatformData::~FontCustomPlatformData() +{ +} + +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode) +{ + return FontPlatformData(size, bold, italic); +} + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) +{ + // FIXME: We need support in Haiku to read fonts from memory to implement this. + return 0; +} + +} diff --git a/WebCore/platform/graphics/haiku/FontCustomPlatformData.h b/WebCore/platform/graphics/haiku/FontCustomPlatformData.h new file mode 100644 index 0000000..c5a814e --- /dev/null +++ b/WebCore/platform/graphics/haiku/FontCustomPlatformData.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2008 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef FontCustomPlatformData_h +#define FontCustomPlatformData_h + +#include "FontRenderingMode.h" +#include <wtf/Noncopyable.h> + +namespace WebCore { + + class FontPlatformData; + class SharedBuffer; + + struct FontCustomPlatformData : Noncopyable { + public: + FontCustomPlatformData() { } + ~FontCustomPlatformData(); + + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode); + }; + + FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*); + +} + +#endif diff --git a/WebCore/platform/graphics/haiku/FontHaiku.cpp b/WebCore/platform/graphics/haiku/FontHaiku.cpp new file mode 100644 index 0000000..48744d9 --- /dev/null +++ b/WebCore/platform/graphics/haiku/FontHaiku.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Font.h" + +#include "FontData.h" +#include "FontDescription.h" +#include "FontSelector.h" +#include "GraphicsContext.h" +#include "NotImplemented.h" +#include <Font.h> +#include <String.h> +#include <View.h> + + +// FIXME: Temp routine to convert unicode character to UTF8. +int charUnicodeToUTF8HACK(unsigned short glyph, char* out) +{ + int i = 0; + + if (glyph < 0x0080) + out[i++] = static_cast<char>(glyph); + else if (glyph < 0x0800) { // 2 bytes + out[i++] = 0xc0 | (glyph >> 6); + out[i++] = 0x80 | (glyph & 0x3F); + } else if (glyph > 0x0800) { // 3 bytes + out[i++] = 0xe0 | (glyph >> 12); + out[i++] = 0x80 | ((glyph >> 6) & 0x3F); + out[i++] = 0x80 | (glyph & 0x3F); + } + + out[i] = '\0'; + return i; +} + +namespace WebCore { + +bool Font::canReturnFallbackFontsForComplexText() +{ + return false; +} + +void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, + const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const +{ + Color color = graphicsContext->fillColor(); + BView* view = graphicsContext->platformContext(); + BFont* m_font = font->platformData().font(); + + graphicsContext->setCompositeOperation(CompositeSourceOver); + view->SetHighColor(color); + view->SetFont(m_font); + + GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from)); + float offset = point.x(); + for (int i = 0; i < numGlyphs; i++) { + char out[4]; + charUnicodeToUTF8HACK(glyphs[i], out); + + view->DrawString(out, sizeof(out), BPoint(offset, point.y())); + offset += glyphBuffer.advanceAt(from + i); + } +} + +void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, + int from, int to) const +{ + notImplemented(); +} + + +float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const +{ + notImplemented(); + return 0; +} + +FloatRect Font::selectionRectForComplexText(const TextRun&, const IntPoint&, int, int, int) const +{ + notImplemented(); + return FloatRect(); +} + +int Font::offsetForPositionForComplexText(const TextRun&, int, bool) const +{ + notImplemented(); + return 0; +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/FontPlatformData.h b/WebCore/platform/graphics/haiku/FontPlatformData.h new file mode 100644 index 0000000..9feab8e --- /dev/null +++ b/WebCore/platform/graphics/haiku/FontPlatformData.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * Copyright (C) 2006 Dirk Mueller <mueller@kde.org> + * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com> + * + * All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef FontPlatformData_H +#define FontPlatformData_H + +#include "FontDescription.h" +#include "GlyphBuffer.h" +#include <interface/Font.h> + +namespace WebCore { + + class FontPlatformData { + public: + FontPlatformData(WTF::HashTableDeletedValueType) + : m_font(hashTableDeletedFontValue()) + { } + + FontPlatformData() + : m_font(0) + { } + + FontPlatformData(const FontDescription&, const AtomicString& family); + FontPlatformData(float size, bool bold, bool oblique); + FontPlatformData(const FontPlatformData&); + + ~FontPlatformData(); + + BFont* font() const { return m_font; } + + bool isFixedPitch(); + float size() const { return m_size; } + bool bold() const { return m_bold; } + bool oblique() const { return m_oblique; } + + unsigned hash() const; + bool isHashTableDeletedValue() const; + + bool operator==(const FontPlatformData&) const; + +#ifndef NDEBUG + String description() const; +#endif + + BFont* m_font; + float m_size; + bool m_bold; + bool m_oblique; + + private: + static BFont* hashTableDeletedFontValue() { return reinterpret_cast<BFont*>(-1); } + }; + +} // namespace WebCore + +#endif + diff --git a/WebCore/platform/graphics/haiku/GradientHaiku.cpp b/WebCore/platform/graphics/haiku/GradientHaiku.cpp new file mode 100644 index 0000000..469a17f --- /dev/null +++ b/WebCore/platform/graphics/haiku/GradientHaiku.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2008 Kevin Ollivier <kevino@theolliviers.com> All rights reserved. + * Copyright (C) 2009 Maxime Simon <simon.maxime@theolliviers.com> + * + * 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 "Gradient.h" + +#include "CSSParser.h" +#include "NotImplemented.h" + + +namespace WebCore { + +void Gradient::platformDestroy() +{ + notImplemented(); +} + +PlatformGradient Gradient::platformGradient() +{ + notImplemented(); + return 0; +} + +void Gradient::fill(GraphicsContext*, const FloatRect&) +{ + notImplemented(); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp new file mode 100644 index 0000000..d785ef4 --- /dev/null +++ b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp @@ -0,0 +1,536 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "GraphicsContext.h" + +#include "CString.h" +#include "Color.h" +#include "Font.h" +#include "FontData.h" +#include "NotImplemented.h" +#include "Path.h" +#include "Pen.h" +#include "TransformationMatrix.h" +#include <GraphicsDefs.h> +#include <Region.h> +#include <View.h> +#include <Window.h> +#include <stdio.h> + + +namespace WebCore { + +class GraphicsContextPlatformPrivate { +public: + GraphicsContextPlatformPrivate(BView* view); + ~GraphicsContextPlatformPrivate(); + + BView* m_view; +}; + +GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(BView* view) + : m_view(view) +{ +} + +GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate() +{ +} + +GraphicsContext::GraphicsContext(PlatformGraphicsContext* context) + : m_common(createGraphicsContextPrivate()) + , m_data(new GraphicsContextPlatformPrivate(context)) +{ + setPaintingDisabled(!context); +} + +GraphicsContext::~GraphicsContext() +{ + destroyGraphicsContextPrivate(m_common); + delete m_data; +} + +PlatformGraphicsContext* GraphicsContext::platformContext() const +{ + return m_data->m_view; +} + +void GraphicsContext::savePlatformState() +{ + m_data->m_view->PushState(); +} + +void GraphicsContext::restorePlatformState() +{ + m_data->m_view->PopState(); +} + +// Draws a filled rectangle with a stroked border. +void GraphicsContext::drawRect(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + m_data->m_view->FillRect(rect); + if (strokeStyle() != NoStroke) + m_data->m_view->StrokeRect(rect, getHaikuStrokeStyle()); +} + +// This is only used to draw borders. +void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) +{ + if (paintingDisabled()) + return; + + if (strokeStyle() == NoStroke) + return; + + m_data->m_view->StrokeLine(point1, point2, getHaikuStrokeStyle()); +} + +// This method is only used to draw the little circles used in lists. +void GraphicsContext::drawEllipse(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + m_data->m_view->FillEllipse(rect); + if (strokeStyle() != NoStroke) + m_data->m_view->StrokeEllipse(rect, getHaikuStrokeStyle()); +} + +void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan) +{ + if (paintingDisabled()) + return; + + m_data->m_view->StrokeArc(rect, startAngle, angleSpan, getHaikuStrokeStyle()); +} + +void GraphicsContext::strokePath() +{ + notImplemented(); +} + +void GraphicsContext::drawConvexPolygon(size_t pointsLength, const FloatPoint* points, bool shouldAntialias) +{ + if (paintingDisabled()) + return; + + BPoint bPoints[pointsLength]; + for (size_t i = 0; i < pointsLength; i++) + bPoints[i] = points[i]; + + m_data->m_view->FillPolygon(bPoints, pointsLength); + if (strokeStyle() != NoStroke) + // Stroke with low color + m_data->m_view->StrokePolygon(bPoints, pointsLength, true, getHaikuStrokeStyle()); +} + +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +{ + if (paintingDisabled()) + return; + + rgb_color oldColor = m_data->m_view->HighColor(); + m_data->m_view->SetHighColor(color); + m_data->m_view->FillRect(rect); + m_data->m_view->SetHighColor(oldColor); +} + +void GraphicsContext::fillRect(const FloatRect& rect) +{ + if (paintingDisabled()) + return; +} + +void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) +{ + if (paintingDisabled() || !color.alpha()) + return; + + notImplemented(); + // FIXME: A simple implementation could just use FillRoundRect if all + // the sizes are the same, or even if they are not. Otherwise several + // FillRect and FillArc calls are needed. +} + +void GraphicsContext::fillPath() +{ + notImplemented(); +} + +void GraphicsContext::beginPath() +{ + notImplemented(); +} + +void GraphicsContext::addPath(const Path& path) +{ + notImplemented(); +} + +void GraphicsContext::clip(const FloatRect& rect) +{ + if (paintingDisabled()) + return; + + BRegion region(rect); + m_data->m_view->ConstrainClippingRegion(®ion); +} + +void GraphicsContext::drawFocusRing(const Color& color) +{ + if (paintingDisabled()) + return; + + const Vector<IntRect>& rects = focusRingRects(); + unsigned rectCount = rects.size(); + + // FIXME: maybe we should implement this with BShape? + + if (rects.size() > 1) { + BRegion region; + for (int i = 0; i < rectCount; ++i) + region.Include(BRect(rects[i])); + + m_data->m_view->SetHighColor(color); + m_data->m_view->StrokeRect(region.Frame(), B_MIXED_COLORS); + } +} + +void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing) +{ + if (paintingDisabled()) + return; + + IntPoint endPoint = origin + IntSize(width, 0); + drawLine(origin, endPoint); +} + +void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, int width, bool grammar) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) +{ + notImplemented(); + return rect; +} + +void GraphicsContext::beginTransparencyLayer(float opacity) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::endTransparencyLayer() +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::clearRect(const FloatRect& rect) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::strokeRect(const FloatRect& rect, float width) +{ + if (paintingDisabled()) + return; + + float oldSize = m_data->m_view->PenSize(); + m_data->m_view->SetPenSize(width); + m_data->m_view->StrokeRect(rect, getHaikuStrokeStyle()); + m_data->m_view->SetPenSize(oldSize); +} + +void GraphicsContext::setLineCap(LineCap lineCap) +{ + if (paintingDisabled()) + return; + + cap_mode mode = B_BUTT_CAP; + switch (lineCap) { + case RoundCap: + mode = B_ROUND_CAP; + break; + case SquareCap: + mode = B_SQUARE_CAP; + break; + case ButtCap: + default: + break; + } + + m_data->m_view->SetLineMode(mode, m_data->m_view->LineJoinMode(), m_data->m_view->LineMiterLimit()); +} + +void GraphicsContext::setLineJoin(LineJoin lineJoin) +{ + if (paintingDisabled()) + return; + + join_mode mode = B_MITER_JOIN; + switch (lineJoin) { + case RoundJoin: + mode = B_ROUND_JOIN; + break; + case BevelJoin: + mode = B_BEVEL_JOIN; + break; + case MiterJoin: + default: + break; + } + + m_data->m_view->SetLineMode(m_data->m_view->LineCapMode(), mode, m_data->m_view->LineMiterLimit()); +} + +void GraphicsContext::setMiterLimit(float limit) +{ + if (paintingDisabled()) + return; + + m_data->m_view->SetLineMode(m_data->m_view->LineCapMode(), m_data->m_view->LineJoinMode(), limit); +} + +void GraphicsContext::setAlpha(float opacity) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::setCompositeOperation(CompositeOperator op) +{ + if (paintingDisabled()) + return; + + drawing_mode mode = B_OP_COPY; + switch (op) { + case CompositeClear: + case CompositeCopy: + // Use the default above + break; + case CompositeSourceOver: + mode = B_OP_OVER; + break; + default: + printf("GraphicsContext::setCompositeOperation: Unsupported composite operation %s\n", + compositeOperatorName(op).utf8().data()); + } + m_data->m_view->SetDrawingMode(mode); +} + +void GraphicsContext::clip(const Path& path) +{ + if (paintingDisabled()) + return; + + m_data->m_view->ConstrainClippingRegion(path.platformPath()); +} + +void GraphicsContext::clipOut(const Path& path) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*) +{ + notImplemented(); +} + +TransformationMatrix GraphicsContext::getCTM() const +{ + notImplemented(); + return TransformationMatrix(); +} + +void GraphicsContext::translate(float x, float y) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +IntPoint GraphicsContext::origin() +{ + notImplemented(); + return IntPoint(0, 0); +} + +void GraphicsContext::rotate(float radians) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::scale(const FloatSize& size) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::clipOut(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::concatCTM(const TransformationMatrix& transform) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::setPlatformShouldAntialias(bool enable) +{ + if (paintingDisabled()) + return; + + notImplemented(); +} + +void GraphicsContext::setImageInterpolationQuality(InterpolationQuality) +{ +} + +void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) +{ + notImplemented(); +} + +void GraphicsContext::setPlatformFont(const Font& font) +{ + m_data->m_view->SetFont(font.primaryFont()->platformData().font()); +} + +void GraphicsContext::setPlatformStrokeColor(const Color& color) +{ + if (paintingDisabled()) + return; + + m_data->m_view->SetHighColor(color); +} + +pattern GraphicsContext::getHaikuStrokeStyle() +{ + switch (strokeStyle()) { + case SolidStroke: + return B_SOLID_HIGH; + break; + case DottedStroke: + return B_MIXED_COLORS; + break; + case DashedStroke: + // FIXME: use a better dashed stroke! + notImplemented(); + return B_MIXED_COLORS; + break; + default: + return B_SOLID_LOW; + break; + } +} + +void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& strokeStyle) +{ + // FIXME: see getHaikuStrokeStyle. + notImplemented(); +} + +void GraphicsContext::setPlatformStrokeThickness(float thickness) +{ + if (paintingDisabled()) + return; + + m_data->m_view->SetPenSize(thickness); +} + +void GraphicsContext::setPlatformFillColor(const Color& color) +{ + if (paintingDisabled()) + return; + + m_data->m_view->SetHighColor(color); +} + +void GraphicsContext::clearPlatformShadow() +{ + notImplemented(); +} + +void GraphicsContext::setPlatformShadow(IntSize const&, int, Color const&) +{ + notImplemented(); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/IconHaiku.cpp b/WebCore/platform/graphics/haiku/IconHaiku.cpp new file mode 100644 index 0000000..dccac4a --- /dev/null +++ b/WebCore/platform/graphics/haiku/IconHaiku.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" +#include "Icon.h" + +#include "GraphicsContext.h" +#include "IntRect.h" +#include "NotImplemented.h" +#include "PlatformString.h" + + +namespace WebCore { + +Icon::~Icon() +{ + notImplemented(); +} + +PassRefPtr<Icon> Icon::createIconForFile(const String& filename) +{ + notImplemented(); + return 0; +} + +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) +{ + notImplemented(); + return 0; +} + +void Icon::paint(GraphicsContext*, const IntRect&) +{ + notImplemented(); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/ImageBufferData.h b/WebCore/platform/graphics/haiku/ImageBufferData.h new file mode 100644 index 0000000..f978c34 --- /dev/null +++ b/WebCore/platform/graphics/haiku/ImageBufferData.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ImageBufferData_h +#define ImageBufferData_h + +namespace WebCore { + + class IntSize; + + class ImageBufferData { + public: + ImageBufferData(const IntSize&); + }; + +} // namespace WebCore + +#endif // ImageBufferData_h + diff --git a/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp b/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp new file mode 100644 index 0000000..276c968 --- /dev/null +++ b/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com> + * + * 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 "ImageBuffer.h" + +#include "GraphicsContext.h" +#include "ImageData.h" +#include "NotImplemented.h" + + +namespace WebCore { + +ImageBufferData::ImageBufferData(const IntSize&) +{ +} + +ImageBuffer::ImageBuffer(const IntSize&, ImageColorSpace imageColorSpace, bool& success) + : m_data(IntSize()) +{ + notImplemented(); + success = false; +} + +ImageBuffer::~ImageBuffer() +{ +} + +GraphicsContext* ImageBuffer::context() const +{ + notImplemented(); + return 0; +} + +PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const +{ + notImplemented(); + return 0; +} + +PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const +{ + notImplemented(); + return 0; +} + +void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + notImplemented(); +} + +void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + notImplemented(); +} + +String ImageBuffer::toDataURL(const String&) const +{ + notImplemented(); + return String(); +} + +Image* ImageBuffer::image() const +{ + notImplemented(); + return 0; +} + +void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) +{ + notImplemented(); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/ImageHaiku.cpp b/WebCore/platform/graphics/haiku/ImageHaiku.cpp new file mode 100644 index 0000000..323d6ab --- /dev/null +++ b/WebCore/platform/graphics/haiku/ImageHaiku.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2006 Dirk Mueller <mueller@kde.org> + * Copyright (C) 2006 Zack Rusin <zack@kde.org> + * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org> + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * Copyright (C) 2008 Andrea Anzani <andrea.anzani@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Image.h" + +#include "BitmapImage.h" +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "NotImplemented.h" +#include "PlatformString.h" +#include <Application.h> +#include <Bitmap.h> +#include <View.h> + + +// This function loads resources from WebKit +Vector<char> loadResourceIntoArray(const char*); + + +namespace WebCore { + +bool FrameData::clear(bool clearMetadata) +{ + if (clearMetadata) + m_haveMetadata = false; + + if (m_frame) { + delete m_frame; + m_frame = 0; + m_duration = 0.0f; + m_hasAlpha = true; + return true; + } + + return false; +} + +WTF::PassRefPtr<Image> Image::loadPlatformResource(const char* name) +{ + Vector<char> array = loadResourceIntoArray(name); + WTF::PassRefPtr<BitmapImage> image = BitmapImage::create(); + RefPtr<SharedBuffer> buffer = SharedBuffer::create(array.data(), array.size()); + image->setData(buffer, true); + + return image; +} + +void BitmapImage::initPlatformData() +{ +} + +void BitmapImage::invalidatePlatformData() +{ +} + +// Drawing Routines +void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, CompositeOperator op) +{ + startAnimation(); + + BBitmap* image = nativeImageForCurrentFrame(); + if (!image || !image->IsValid()) // If the image hasn't fully loaded. + return; + + if (mayFillWithSolidColor()) { + fillWithSolidColor(ctxt, dst, solidColor(), op); + return; + } + + ctxt->save(); + ctxt->setCompositeOperation(op); + + BRect srcRect(src); + BRect dstRect(dst); + + // Test using example site at + // http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html + ctxt->platformContext()->SetDrawingMode(B_OP_ALPHA); + ctxt->platformContext()->DrawBitmap(image, srcRect & image->Bounds(), dstRect); + ctxt->restore(); +} + +void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const TransformationMatrix& patternTransform, const FloatPoint& srcPoint, CompositeOperator op, const FloatRect& dstRect) +{ + // FIXME: finish this to support also phased position (srcPoint) + startAnimation(); + + BBitmap* image = nativeImageForCurrentFrame(); + if (!image || !image->IsValid()) // If the image hasn't fully loaded. + return; + + float currentW = 0; + float currentH = 0; + + context->save(); + context->platformContext()->SetDrawingMode(B_OP_ALPHA); + context->clip(enclosingIntRect(dstRect)); + + while (currentW < dstRect.width()) { + while (currentH < dstRect.height()) { + context->platformContext()->DrawBitmap(image, BPoint(dstRect.x() + currentW, dstRect.y() + currentH)); + currentH += tileRect.height(); + } + currentW += tileRect.width(); + currentH = 0; + } + context->restore(); +} + +void BitmapImage::checkForSolidColor() +{ + // FIXME: need to check the RGBA32 buffer to see if it is 1x1. + m_isSolidColor = false; + m_checkedForSolidColor = true; +} + +BBitmap* BitmapImage::getBBitmap() const +{ + return const_cast<BitmapImage*>(this)->frameAtIndex(0); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/IntPointHaiku.cpp b/WebCore/platform/graphics/haiku/IntPointHaiku.cpp new file mode 100644 index 0000000..327e503 --- /dev/null +++ b/WebCore/platform/graphics/haiku/IntPointHaiku.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IntPoint.h" + +#include <Point.h> + + +namespace WebCore { + +IntPoint::IntPoint(const BPoint& point) + : m_x(static_cast<int>(point.x)) + , m_y(static_cast<int>(point.y)) +{ +} + +IntPoint::operator BPoint() const +{ + return BPoint(m_x, m_y); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/IntRectHaiku.cpp b/WebCore/platform/graphics/haiku/IntRectHaiku.cpp new file mode 100644 index 0000000..74a0b9d --- /dev/null +++ b/WebCore/platform/graphics/haiku/IntRectHaiku.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IntRect.h" + +#include <Rect.h> + + +namespace WebCore { + +IntRect::IntRect(const BRect& rect) + : m_location(rect.LeftTop()) + , m_size(rect.IntegerWidth(), rect.IntegerHeight()) +{ +} + +IntRect::operator BRect() const +{ + return BRect(BPoint(x(), y()), BSize(width(), height())); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/IntSizeHaiku.cpp b/WebCore/platform/graphics/haiku/IntSizeHaiku.cpp new file mode 100644 index 0000000..08c3a9d --- /dev/null +++ b/WebCore/platform/graphics/haiku/IntSizeHaiku.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IntSize.h" + +#include <Size.h> + + +namespace WebCore { + +IntSize::IntSize(const BSize& size) + : m_width(size.IntegerWidth()) + , m_height(size.IntegerHeight()) +{ +} + +IntSize::operator BSize() const +{ + return BSize(width(), height()); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/PathHaiku.cpp b/WebCore/platform/graphics/haiku/PathHaiku.cpp new file mode 100644 index 0000000..d0da025 --- /dev/null +++ b/WebCore/platform/graphics/haiku/PathHaiku.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Path.h" + +#include "FloatRect.h" +#include "NotImplemented.h" +#include "PlatformString.h" +#include <Region.h> + + +namespace WebCore { + +Path::Path() + : m_path(new BRegion()) +{ +} + +Path::~Path() +{ + delete m_path; +} + +Path::Path(const Path& other) + : m_path(new BRegion(*other.platformPath())) +{ +} + +Path& Path::operator=(const Path& other) +{ + if (&other != this) + m_path = other.platformPath(); + + return *this; +} + +bool Path::hasCurrentPoint() const +{ + return !isEmpty(); +} + +bool Path::contains(const FloatPoint& point, WindRule rule) const +{ + return m_path->Contains(point); +} + +void Path::translate(const FloatSize& size) +{ + notImplemented(); +} + +FloatRect Path::boundingRect() const +{ + return m_path->Frame(); +} + +void Path::moveTo(const FloatPoint& point) +{ + // FIXME: Use OffsetBy? + notImplemented(); +} + +void Path::addLineTo(const FloatPoint& p) +{ + notImplemented(); +} + +void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p) +{ + notImplemented(); +} + +void Path::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p) +{ + notImplemented(); +} + +void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius) +{ + notImplemented(); +} + +void Path::closeSubpath() +{ + notImplemented(); +} + +void Path::addArc(const FloatPoint& p, float r, float sar, float ear, bool anticlockwise) +{ + notImplemented(); +} + +void Path::addRect(const FloatRect& r) +{ + m_path->Include(r); +} + +void Path::addEllipse(const FloatRect& r) +{ + notImplemented(); +} + +void Path::clear() +{ + m_path->MakeEmpty(); +} + +bool Path::isEmpty() const +{ + return !m_path->Frame().IsValid(); +} + +String Path::debugString() const +{ + notImplemented(); + return String(); +} + +void Path::apply(void* info, PathApplierFunction function) const +{ + notImplemented(); +} + +void Path::transform(const TransformationMatrix& transform) +{ + notImplemented(); +} + +FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) +{ + notImplemented(); + return FloatRect(); +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp b/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp new file mode 100644 index 0000000..34941c0 --- /dev/null +++ b/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com> All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 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 "SimpleFontData.h" + +#include "FloatRect.h" +#include "FontCache.h" +#include "FontDescription.h" +#include "NotImplemented.h" +#include <Rect.h> +#include <unicode/uchar.h> +#include <unicode/unorm.h> + + +namespace WebCore { + +void SimpleFontData::platformInit() +{ + BFont* font = m_platformData.font(); + if (!font) + return; + + font_height height; + font->GetHeight(&height); + m_ascent = static_cast<int>(height.ascent); + m_descent = static_cast<int>(height.descent); + m_lineSpacing = m_ascent + m_descent; + m_xHeight = height.ascent * 0.56f; // Hack taken from the win port. + m_lineGap = height.leading; +} + +void SimpleFontData::platformCharWidthInit() +{ + m_avgCharWidth = 0.f; + m_maxCharWidth = 0.f; + initCharWidths(); +} + +void SimpleFontData::platformDestroy() +{ + delete m_smallCapsFontData; + m_smallCapsFontData = 0; +} + +SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const +{ + if (!m_smallCapsFontData) { + FontDescription desc = FontDescription(fontDescription); + desc.setSpecifiedSize(0.70f * fontDescription.computedSize()); + const FontPlatformData* fontPlatformData = new FontPlatformData(desc, desc.family().family()); + m_smallCapsFontData = new SimpleFontData(*fontPlatformData); + } + return m_smallCapsFontData; +} + +bool SimpleFontData::containsCharacters(const UChar* characters, int length) const +{ + // FIXME: We will need to implement this to load non-ASCII encoding sites + return true; +} + +void SimpleFontData::determinePitch() +{ + m_treatAsFixedPitch = m_platformData.font() && m_platformData.font()->IsFixed(); +} + +float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +{ + const char charArray[1] = { glyph }; + float escapements[1]; + + if (m_platformData.font()) { + m_platformData.font()->GetEscapements(charArray, 1, escapements); + return escapements[0] * m_platformData.font()->Size(); + } + + return 0; +} + +} // namespace WebCore + diff --git a/WebCore/platform/graphics/mac/Canvas3DLayer.h b/WebCore/platform/graphics/mac/Canvas3DLayer.h new file mode 100644 index 0000000..6c65676 --- /dev/null +++ b/WebCore/platform/graphics/mac/Canvas3DLayer.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2009 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 Canvas3DLayer_h +#define Canvas3DLayer_h + +#if USE(ACCELERATED_COMPOSITING) + +#import "WebLayer.h" + +namespace WebCore { + class GraphicsLayer; +} + +@interface Canvas3DLayer : CAOpenGLLayer +{ + WebCore::GraphicsLayer* m_layerOwner; + CGLContextObj m_contextObj; + GLuint m_texture; +} + +-(id)initWithContext:(CGLContextObj)context texture:(GLuint)texture; + +@end + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // Canvas3DLayer_h diff --git a/WebCore/platform/graphics/mac/Canvas3DLayer.mm b/WebCore/platform/graphics/mac/Canvas3DLayer.mm new file mode 100644 index 0000000..545c58b --- /dev/null +++ b/WebCore/platform/graphics/mac/Canvas3DLayer.mm @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2009 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" + +#if USE(ACCELERATED_COMPOSITING) +#if ENABLE(3D_CANVAS) + +#import "Canvas3DLayer.h" + +#import "GraphicsLayer.h" +#import <QuartzCore/QuartzCore.h> +#import <OpenGL/OpenGL.h> + +using namespace WebCore; + +@implementation Canvas3DLayer + +-(id)initWithContext:(CGLContextObj)context texture:(GLuint)texture +{ + m_contextObj = context; + m_texture = texture; + self = [super init]; + return self; +} + +-(CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask +{ + CGLPixelFormatAttribute attribs[] = + { + (CGLPixelFormatAttribute) kCGLPFAAccelerated, + (CGLPixelFormatAttribute) kCGLPFAColorSize, (CGLPixelFormatAttribute) 32, + (CGLPixelFormatAttribute) kCGLPFADisplayMask, (CGLPixelFormatAttribute) mask, + (CGLPixelFormatAttribute) 0 + }; + + CGLPixelFormatObj pixelFormatObj; + GLint numPixelFormats; + + CGLChoosePixelFormat(attribs, &pixelFormatObj, &numPixelFormats); + return pixelFormatObj; +} + +-(CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat +{ + CGLContextObj contextObj; + CGLCreateContext(pixelFormat, m_contextObj, &contextObj); + return contextObj; +} + +-(void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp +{ + CGRect frame = [self frame]; + + // draw the FBO into the layer + glViewport(0, 0, frame.size.width, frame.size.height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-1, 1, -1, 1, -1, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, m_texture); + + glBegin(GL_TRIANGLE_FAN); + glTexCoord2f(0, 0); + glVertex2f(-1, -1); + glTexCoord2f(1, 0); + glVertex2f(1, -1); + glTexCoord2f(1, 1); + glVertex2f(1, 1); + glTexCoord2f(0, 1); + glVertex2f(-1, 1); + glEnd(); + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + // Call super to finalize the drawing. By default all it does is call glFlush(). + [super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp]; +} + +@end + +@implementation Canvas3DLayer(WebLayerAdditions) + +-(void)setLayerOwner:(GraphicsLayer*)aLayer +{ + m_layerOwner = aLayer; +} + +-(GraphicsLayer*)layerOwner +{ + return m_layerOwner; +} + +@end + +#endif // ENABLE(3D_CANVAS) +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/mac/CoreTextController.cpp b/WebCore/platform/graphics/mac/CoreTextController.cpp index 05f29b5..b2682e4 100644 --- a/WebCore/platform/graphics/mac/CoreTextController.cpp +++ b/WebCore/platform/graphics/mac/CoreTextController.cpp @@ -365,7 +365,7 @@ void CoreTextController::collectCoreTextRunsForCharacters(const UChar* cp, unsig RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(NULL, cp, length, kCFAllocatorNull)); - RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(NULL, string.get(), fontData->getCFStringAttributes())); + RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(NULL, string.get(), fontData->getCFStringAttributes(m_font.fontDescription().textRenderingMode()))); RetainPtr<CTTypesetterRef> typesetter; diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp index e40bbab..5e72101 100644 --- a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp @@ -46,11 +46,13 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) ATSFontContainerRef containerRef = 0; ATSFontRef fontRef = 0; + RetainPtr<CGFontRef> cgFontRef; + #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) RetainPtr<CFDataRef> bufferData(AdoptCF, buffer->createCFData()); RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(bufferData.get())); - CGFontRef cgFontRef = CGFontCreateWithDataProvider(dataProvider.get()); + cgFontRef.adoptCF(CGFontCreateWithDataProvider(dataProvider.get())); if (!cgFontRef) return 0; #else @@ -75,13 +77,11 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) return 0; } - CGFontRef cgFontRef = CGFontCreateWithPlatformFont(&fontRef); + cgFontRef.adoptCF(CGFontCreateWithPlatformFont(&fontRef)); #ifndef BUILDING_ON_TIGER // Workaround for <rdar://problem/5675504>. - if (cgFontRef && !CGFontGetNumberOfGlyphs(cgFontRef)) { - CFRelease(cgFontRef); + if (cgFontRef && !CGFontGetNumberOfGlyphs(cgFontRef.get())) cgFontRef = 0; - } #endif if (!cgFontRef) { ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault); @@ -89,7 +89,7 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) } #endif // !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) - return new FontCustomPlatformData(containerRef, fontRef, cgFontRef); + return new FontCustomPlatformData(containerRef, fontRef, cgFontRef.releaseRef()); } } diff --git a/WebCore/platform/graphics/mac/FontMac.mm b/WebCore/platform/graphics/mac/FontMac.mm index df9494a..b2b9a5c 100644 --- a/WebCore/platform/graphics/mac/FontMac.mm +++ b/WebCore/platform/graphics/mac/FontMac.mm @@ -50,10 +50,33 @@ bool Font::canReturnFallbackFontsForComplexText() void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { CGContextRef cgContext = context->platformContext(); + bool newShouldUseFontSmoothing = shouldUseSmoothing(); + + switch(fontDescription().fontSmoothing()) { + case Antialiased: { + context->setShouldAntialias(true); + newShouldUseFontSmoothing = false; + break; + } + case SubpixelAntialiased: { + context->setShouldAntialias(true); + newShouldUseFontSmoothing = true; + break; + } + case NoSmoothing: { + context->setShouldAntialias(false); + newShouldUseFontSmoothing = false; + break; + } + case AutoSmoothing: { + // For the AutoSmooth case, don't do anything! Keep the default settings. + break; + } + default: + ASSERT_NOT_REACHED(); + } bool originalShouldUseFontSmoothing = wkCGContextGetShouldSmoothFonts(cgContext); - bool newShouldUseFontSmoothing = shouldUseSmoothing(); - if (originalShouldUseFontSmoothing != newShouldUseFontSmoothing) CGContextSetShouldSmoothFonts(cgContext, newShouldUseFontSmoothing); diff --git a/WebCore/platform/graphics/mac/FontMacATSUI.mm b/WebCore/platform/graphics/mac/FontMacATSUI.mm index 051abb7..409bda4 100644 --- a/WebCore/platform/graphics/mac/FontMacATSUI.mm +++ b/WebCore/platform/graphics/mac/FontMacATSUI.mm @@ -105,12 +105,12 @@ static bool fontHasMirroringInfo(ATSUFontID fontID) return false; } -static void disableLigatures(const SimpleFontData* fontData) +static void disableLigatures(const SimpleFontData* fontData, TextRenderingMode textMode) { // Don't be too aggressive: if the font doesn't contain 'a', then assume that any ligatures it contains are // in characters that always go through ATSUI, and therefore allow them. Geeza Pro is an example. // See bugzilla 5166. - if (fontData->platformData().allowsLigatures()) + if (textMode == OptimizeLegibility || textMode == GeometricPrecision || fontData->platformData().allowsLigatures()) return; ATSUFontFeatureType featureTypes[] = { kLigaturesType }; @@ -120,7 +120,7 @@ static void disableLigatures(const SimpleFontData* fontData) LOG_ERROR("ATSUSetFontFeatures failed (%d) -- ligatures remain enabled", status); } -static void initializeATSUStyle(const SimpleFontData* fontData) +static void initializeATSUStyle(const SimpleFontData* fontData, TextRenderingMode textMode) { if (fontData->m_ATSUStyleInitialized) return; @@ -141,19 +141,28 @@ static void initializeATSUStyle(const SimpleFontData* fontData) transform = CGAffineTransformConcat(transform, CGAffineTransformMake(1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, 0, 0)); Fixed fontSize = FloatToFixed(fontData->platformData().m_size); ByteCount styleSizes[4] = { sizeof(Fixed), sizeof(ATSUFontID), sizeof(CGAffineTransform), sizeof(Fract) }; - // Turn off automatic kerning until it is supported in the CG code path (bug 6136) - Fract kerningInhibitFactor = FloatToFract(1.0); - ATSUAttributeTag styleTags[4] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag, kATSUKerningInhibitFactorTag }; - ATSUAttributeValuePtr styleValues[4] = { &fontSize, &fontID, &transform, &kerningInhibitFactor }; - status = ATSUSetAttributes(fontData->m_ATSUStyle, 4, styleTags, styleSizes, styleValues); - if (status != noErr) - LOG_ERROR("ATSUSetAttributes failed (%d)", status); + bool allowKerning = textMode == OptimizeLegibility || textMode == GeometricPrecision; + if (!allowKerning) { + // Turn off automatic kerning until it is supported in the CG code path (bug 6136) + Fract kerningInhibitFactor = FloatToFract(1.0); + ATSUAttributeTag styleTags[4] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag, kATSUKerningInhibitFactorTag }; + ATSUAttributeValuePtr styleValues[4] = { &fontSize, &fontID, &transform, &kerningInhibitFactor }; + status = ATSUSetAttributes(fontData->m_ATSUStyle, 4, styleTags, styleSizes, styleValues); + if (status != noErr) + LOG_ERROR("ATSUSetAttributes failed (%d)", status); + } else { + ATSUAttributeTag styleTags[3] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag }; + ATSUAttributeValuePtr styleValues[3] = { &fontSize, &fontID, &transform, }; + status = ATSUSetAttributes(fontData->m_ATSUStyle, 3, styleTags, styleSizes, styleValues); + if (status != noErr) + LOG_ERROR("ATSUSetAttributes failed (%d)", status); + } fontData->m_ATSUMirrors = fontHasMirroringInfo(fontID); // Turn off ligatures such as 'fi' to match the CG code path's behavior, until bug 6135 is fixed. - disableLigatures(fontData); + disableLigatures(fontData, textMode); fontData->m_ATSUStyleInitialized = true; } @@ -329,7 +338,7 @@ void ATSULayoutParameters::initialize(const Font* font, const GraphicsContext* g OSStatus status; ATSULayoutOperationOverrideSpecifier overrideSpecifier; - initializeATSUStyle(fontData); + initializeATSUStyle(fontData, m_font->fontDescription().textRenderingMode()); // FIXME: This is currently missing the following required features that the CoreGraphics code path has: // - \n, \t, and nonbreaking space render as a space. @@ -393,7 +402,7 @@ void ATSULayoutParameters::initialize(const Font* font, const GraphicsContext* g const FontData* fallbackFontData = m_font->fontDataForCharacters(m_run.characters() + substituteOffset, substituteLength); substituteFontData = fallbackFontData ? fallbackFontData->fontDataForCharacter(m_run[0]) : 0; if (substituteFontData) { - initializeATSUStyle(substituteFontData); + initializeATSUStyle(substituteFontData, m_font->fontDescription().textRenderingMode()); if (substituteFontData->m_ATSUStyle) ATSUSetRunStyle(layout, substituteFontData->m_ATSUStyle, substituteOffset, substituteLength); } else @@ -412,7 +421,7 @@ void ATSULayoutParameters::initialize(const Font* font, const GraphicsContext* g if (i == substituteOffset || i == substituteOffset + substituteLength) { if (isSmallCap) { isSmallCap = false; - initializeATSUStyle(r->smallCapsFontData(m_font->fontDescription())); + initializeATSUStyle(r->smallCapsFontData(m_font->fontDescription()), m_font->fontDescription().textRenderingMode()); ATSUSetRunStyle(layout, r->smallCapsFontData(m_font->fontDescription())->m_ATSUStyle, firstSmallCap, i - firstSmallCap); } if (i == substituteOffset && substituteLength > 0) @@ -456,7 +465,7 @@ void ATSULayoutParameters::initialize(const Font* font, const GraphicsContext* g } else { if (isSmallCap) { isSmallCap = false; - initializeATSUStyle(smallCapsData); + initializeATSUStyle(smallCapsData, m_font->fontDescription().textRenderingMode()); ATSUSetRunStyle(layout, smallCapsData->m_ATSUStyle, firstSmallCap, i - firstSmallCap); } m_fonts[i] = r; @@ -504,8 +513,8 @@ FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& firstGlyphBounds = zeroTrapezoid; } - float beforeWidth = MIN(FixedToFloat(firstGlyphBounds.lowerLeft.x), FixedToFloat(firstGlyphBounds.upperLeft.x)); - float afterWidth = MAX(FixedToFloat(firstGlyphBounds.lowerRight.x), FixedToFloat(firstGlyphBounds.upperRight.x)); + float beforeWidth = min(FixedToFloat(firstGlyphBounds.lowerLeft.x), FixedToFloat(firstGlyphBounds.upperLeft.x)); + float afterWidth = max(FixedToFloat(firstGlyphBounds.lowerRight.x), FixedToFloat(firstGlyphBounds.upperRight.x)); FloatRect rect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h); @@ -591,8 +600,8 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon if (actualNumBounds != 1) LOG_ERROR("unexpected result from ATSUGetGlyphBounds(): actualNumBounds(%d) != 1", actualNumBounds); - return MAX(FixedToFloat(firstGlyphBounds.upperRight.x), FixedToFloat(firstGlyphBounds.lowerRight.x)) - - MIN(FixedToFloat(firstGlyphBounds.upperLeft.x), FixedToFloat(firstGlyphBounds.lowerLeft.x)); + return max(FixedToFloat(firstGlyphBounds.upperRight.x), FixedToFloat(firstGlyphBounds.lowerRight.x)) - + min(FixedToFloat(firstGlyphBounds.upperLeft.x), FixedToFloat(firstGlyphBounds.lowerLeft.x)); } int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool /*includePartialGlyphs*/) const diff --git a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp new file mode 100644 index 0000000..cd66445 --- /dev/null +++ b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp @@ -0,0 +1,1698 @@ +/* + * Copyright (C) 2009 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" + +#if ENABLE(3D_CANVAS) + +#include "GraphicsContext3D.h" + +#include "CachedImage.h" +#include "CanvasBuffer.h" +#include "CanvasFramebuffer.h" +#include "CanvasArray.h" +#include "CanvasFloatArray.h" +#include "CanvasIntArray.h" +#include "CanvasObject.h" +#include "CanvasProgram.h" +#include "CanvasRenderbuffer.h" +#include "CanvasShader.h" +#include "CanvasTexture.h" +#include "CanvasUnsignedByteArray.h" +#include "CString.h" +#include "HTMLCanvasElement.h" +#include "HTMLImageElement.h" +#include "ImageBuffer.h" +#include "NotImplemented.h" +#include "WebKitCSSMatrix.h" + +#include <CoreGraphics/CGBitmapContext.h> + +namespace WebCore { + +GraphicsContext3D::GraphicsContext3D() +{ + CGLPixelFormatAttribute attribs[] = + { + (CGLPixelFormatAttribute) kCGLPFAAccelerated, + (CGLPixelFormatAttribute) kCGLPFAColorSize, (CGLPixelFormatAttribute) 32, + (CGLPixelFormatAttribute) kCGLPFADepthSize, (CGLPixelFormatAttribute) 32, + (CGLPixelFormatAttribute) kCGLPFASupersample, + (CGLPixelFormatAttribute) 0 + }; + + CGLPixelFormatObj pixelFormatObj; + GLint numPixelFormats; + + CGLChoosePixelFormat(attribs, &pixelFormatObj, &numPixelFormats); + + CGLCreateContext(pixelFormatObj, 0, &m_contextObj); + + CGLDestroyPixelFormat(pixelFormatObj); + + // Set the current context to the one given to us. + CGLSetCurrentContext(m_contextObj); + + // create a texture to render into + ::glGenTextures(1, &m_texture); + ::glBindTexture(GL_TEXTURE_2D, m_texture); + ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + ::glBindTexture(GL_TEXTURE_2D, 0); + + // create an FBO + ::glGenFramebuffersEXT(1, &m_fbo); + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); + + ::glGenRenderbuffersEXT(1, &m_depthBuffer); + ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthBuffer); + ::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, 1, 1); + ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); + + ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture, 0); + ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthBuffer); + + ::glClearColor(0, 0, 0, 0); +} + +GraphicsContext3D::~GraphicsContext3D() +{ + CGLSetCurrentContext(m_contextObj); + ::glDeleteRenderbuffersEXT(1, & m_depthBuffer); + ::glDeleteTextures(1, &m_texture); + ::glDeleteFramebuffersEXT(1, &m_fbo); + CGLSetCurrentContext(0); + CGLDestroyContext(m_contextObj); +} + +void GraphicsContext3D::checkError() const +{ + // FIXME: This needs to only be done in the debug context. It will probably throw an exception + // on error and print the error message to the debug console + GLenum error = ::glGetError(); + if (error != GL_NO_ERROR) + notImplemented(); +} + +void GraphicsContext3D::makeContextCurrent() +{ + CGLSetCurrentContext(m_contextObj); +} + +void GraphicsContext3D::beginPaint(CanvasRenderingContext3D* context) +{ + UNUSED_PARAM(context); +} + +void GraphicsContext3D::endPaint() +{ +} + +void GraphicsContext3D::reshape(int width, int height) +{ + if (width == m_currentWidth && height == m_currentHeight) + return; + + m_currentWidth = width; + m_currentHeight = height; + + CGLSetCurrentContext(m_contextObj); + + ::glBindTexture(GL_TEXTURE_2D, m_texture); + ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + ::glBindTexture(GL_TEXTURE_2D, 0); + + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); + ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthBuffer); + ::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height); + ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); + + ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture, 0); + ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthBuffer); + GLenum status = ::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + // FIXME: cleanup + notImplemented(); + } + + ::glViewport(0, 0, m_currentWidth, m_currentHeight); + ::glClear(GL_COLOR_BUFFER_BIT); + ::glFlush(); +} + +static inline void ensureContext(CGLContextObj context) +{ + CGLContextObj currentContext = CGLGetCurrentContext(); + if (currentContext != context) + CGLSetCurrentContext(context); +} + +void GraphicsContext3D::activeTexture(unsigned long texture) +{ + ensureContext(m_contextObj); + ::glActiveTexture(texture); +} + +void GraphicsContext3D::attachShader(CanvasProgram* program, CanvasShader* shader) +{ + if (!program || !shader) + return; + ensureContext(m_contextObj); + ::glAttachShader((GLuint) program->object(), (GLuint) shader->object()); +} + +void GraphicsContext3D::bindAttribLocation(CanvasProgram* program, unsigned long index, const String& name) +{ + if (!program) + return; + ensureContext(m_contextObj); + ::glBindAttribLocation((GLuint) program->object(), index, name.utf8().data()); +} + +void GraphicsContext3D::bindBuffer(unsigned long target, CanvasBuffer* buffer) +{ + ensureContext(m_contextObj); + ::glBindBuffer(target, buffer ? (GLuint) buffer->object() : 0); +} + + +void GraphicsContext3D::bindFramebuffer(unsigned long target, CanvasFramebuffer* buffer) +{ + ensureContext(m_contextObj); + ::glBindFramebufferEXT(target, buffer ? (GLuint) buffer->object() : m_fbo); +} + +void GraphicsContext3D::bindRenderbuffer(unsigned long target, CanvasRenderbuffer* renderbuffer) +{ + ensureContext(m_contextObj); + ::glBindBuffer(target, renderbuffer ? (GLuint) renderbuffer->object() : 0); +} + + +void GraphicsContext3D::bindTexture(unsigned long target, CanvasTexture* texture) +{ + ensureContext(m_contextObj); + ::glBindTexture(target, texture ? (GLuint) texture->object() : 0); +} + +void GraphicsContext3D::blendColor(double red, double green, double blue, double alpha) +{ + ensureContext(m_contextObj); + ::glBlendColor(static_cast<float>(red), static_cast<float>(green), static_cast<float>(blue), static_cast<float>(alpha)); +} + +void GraphicsContext3D::blendEquation( unsigned long mode ) +{ + ensureContext(m_contextObj); + ::glBlendEquation(mode); +} + +void GraphicsContext3D::blendEquationSeparate(unsigned long modeRGB, unsigned long modeAlpha) +{ + ensureContext(m_contextObj); + ::glBlendEquationSeparate(modeRGB, modeAlpha); +} + + +void GraphicsContext3D::blendFunc(unsigned long sfactor, unsigned long dfactor) +{ + ensureContext(m_contextObj); + ::glBlendFunc(sfactor, dfactor); +} + +void GraphicsContext3D::blendFuncSeparate(unsigned long srcRGB, unsigned long dstRGB, unsigned long srcAlpha, unsigned long dstAlpha) +{ + ensureContext(m_contextObj); + ::glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); +} + +void GraphicsContext3D::bufferData(unsigned long target, int size, unsigned long usage) +{ + ensureContext(m_contextObj); + ::glBufferData(target, size, 0, usage); +} +void GraphicsContext3D::bufferData(unsigned long target, CanvasArray* array, unsigned long usage) +{ + if (!array || !array->length()) + return; + + ensureContext(m_contextObj); + ::glBufferData(target, array->sizeInBytes(), array->baseAddress(), usage); +} + +void GraphicsContext3D::bufferSubData(unsigned long target, long offset, CanvasArray* array) +{ + if (!array || !array->length()) + return; + + ensureContext(m_contextObj); + ::glBufferSubData(target, offset, array->sizeInBytes(), array->baseAddress()); +} + +unsigned long GraphicsContext3D::checkFramebufferStatus(unsigned long target) +{ + ensureContext(m_contextObj); + return ::glCheckFramebufferStatusEXT(target); +} + +void GraphicsContext3D::clearColor(double r, double g, double b, double a) +{ + ensureContext(m_contextObj); + ::glClearColor(static_cast<float>(r), static_cast<float>(g), static_cast<float>(b), static_cast<float>(a)); +} + +void GraphicsContext3D::clear(unsigned long mask) +{ + ensureContext(m_contextObj); + ::glClear(mask); +} + +void GraphicsContext3D::clearDepth(double depth) +{ + ensureContext(m_contextObj); + ::glClearDepth(depth); +} + +void GraphicsContext3D::clearStencil(long s) +{ + ensureContext(m_contextObj); + ::glClearStencil(s); +} + +void GraphicsContext3D::colorMask(bool red, bool green, bool blue, bool alpha) +{ + ensureContext(m_contextObj); + ::glColorMask(red, green, blue, alpha); +} + +void GraphicsContext3D::compileShader(CanvasShader* shader) +{ + if (!shader) + return; + + ensureContext(m_contextObj); + ::glCompileShader((GLuint) shader->object()); +} + +void GraphicsContext3D::copyTexImage2D(unsigned long target, long level, unsigned long internalformat, long x, long y, unsigned long width, unsigned long height, long border) +{ + ensureContext(m_contextObj); + ::glCopyTexImage2D(target, level, internalformat, x, y, width, height, border); +} + +void GraphicsContext3D::copyTexSubImage2D(unsigned long target, long level, long xoffset, long yoffset, long x, long y, unsigned long width, unsigned long height) +{ + ensureContext(m_contextObj); + ::glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); +} + +void GraphicsContext3D::cullFace(unsigned long mode) +{ + ensureContext(m_contextObj); + ::glCullFace(mode); +} + +void GraphicsContext3D::depthFunc(unsigned long func) +{ + ensureContext(m_contextObj); + ::glDepthFunc(func); +} + +void GraphicsContext3D::depthMask(bool flag) +{ + ensureContext(m_contextObj); + ::glDepthMask(flag); +} + +void GraphicsContext3D::depthRange(double zNear, double zFar) +{ + ensureContext(m_contextObj); + ::glDepthRange(zNear, zFar); +} + +void GraphicsContext3D::detachShader(CanvasProgram* program, CanvasShader* shader) +{ + if (!program || !shader) + return; + + ensureContext(m_contextObj); + ::glDetachShader((GLuint) program->object(), (GLuint) shader->object()); +} + +void GraphicsContext3D::disable(unsigned long cap) +{ + ensureContext(m_contextObj); + ::glDisable(cap); +} + +void GraphicsContext3D::disableVertexAttribArray(unsigned long index) +{ + ensureContext(m_contextObj); + ::glDisableVertexAttribArray(index); +} + +void GraphicsContext3D::drawArrays(unsigned long mode, long first, long count) +{ + ensureContext(m_contextObj); + ::glDrawArrays(mode, first, count); +} + +void GraphicsContext3D::drawElements(unsigned long mode, unsigned long count, unsigned long type, long offset) +{ + ensureContext(m_contextObj); + ::glDrawElements(mode, count, type, reinterpret_cast<void*>(static_cast<intptr_t>(offset))); +} + +void GraphicsContext3D::enable(unsigned long cap) +{ + ensureContext(m_contextObj); + ::glEnable(cap); +} + +void GraphicsContext3D::enableVertexAttribArray(unsigned long index) +{ + ensureContext(m_contextObj); + ::glEnableVertexAttribArray(index); +} + +void GraphicsContext3D::finish() +{ + ensureContext(m_contextObj); + ::glFinish(); +} + +void GraphicsContext3D::flush() +{ + ensureContext(m_contextObj); + ::glFlush(); +} + +void GraphicsContext3D::framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, CanvasRenderbuffer* buffer) +{ + if (!buffer) + return; + + ensureContext(m_contextObj); + ::glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, (GLuint) buffer->object()); +} + +void GraphicsContext3D::framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, CanvasTexture* texture, long level) +{ + if (!texture) + return; + + ensureContext(m_contextObj); + ::glFramebufferTexture2DEXT(target, attachment, textarget, (GLuint) texture->object(), level); +} + +void GraphicsContext3D::frontFace(unsigned long mode) +{ + ensureContext(m_contextObj); + ::glFrontFace(mode); +} + +void GraphicsContext3D::generateMipmap(unsigned long target) +{ + ensureContext(m_contextObj); + ::glGenerateMipmapEXT(target); +} + +int GraphicsContext3D::getAttribLocation(CanvasProgram* program, const String& name) +{ + if (!program) + return -1; + + ensureContext(m_contextObj); + return ::glGetAttribLocation((GLuint) program->object(), name.utf8().data()); +} + +unsigned long GraphicsContext3D::getError() +{ + ensureContext(m_contextObj); + return ::glGetError(); +} + +String GraphicsContext3D::getString(unsigned long name) +{ + ensureContext(m_contextObj); + return String((const char*) ::glGetString(name)); +} + +void GraphicsContext3D::hint(unsigned long target, unsigned long mode) +{ + ensureContext(m_contextObj); + ::glHint(target, mode); +} + +bool GraphicsContext3D::isBuffer(CanvasBuffer* buffer) +{ + if (!buffer) + return false; + + ensureContext(m_contextObj); + return ::glIsBuffer((GLuint) buffer->object()); +} + +bool GraphicsContext3D::isEnabled(unsigned long cap) +{ + ensureContext(m_contextObj); + return ::glIsEnabled(cap); +} + +bool GraphicsContext3D::isFramebuffer(CanvasFramebuffer* framebuffer) +{ + if (!framebuffer) + return false; + + ensureContext(m_contextObj); + return ::glIsFramebufferEXT((GLuint) framebuffer->object()); +} + +bool GraphicsContext3D::isProgram(CanvasProgram* program) +{ + if (!program) + return false; + + ensureContext(m_contextObj); + return ::glIsProgram((GLuint) program->object()); +} + +bool GraphicsContext3D::isRenderbuffer(CanvasRenderbuffer* renderbuffer) +{ + if (!renderbuffer) + return false; + + ensureContext(m_contextObj); + return ::glIsRenderbufferEXT((GLuint) renderbuffer->object()); +} + +bool GraphicsContext3D::isShader(CanvasShader* shader) +{ + if (!shader) + return false; + + ensureContext(m_contextObj); + return ::glIsShader((GLuint) shader->object()); +} + +bool GraphicsContext3D::isTexture(CanvasTexture* texture) +{ + if (!texture) + return false; + + ensureContext(m_contextObj); + return ::glIsTexture((GLuint) texture->object()); +} + +void GraphicsContext3D::lineWidth(double width) +{ + ensureContext(m_contextObj); + ::glLineWidth(static_cast<float>(width)); +} + +void GraphicsContext3D::linkProgram(CanvasProgram* program) +{ + if (!program) + return; + + ensureContext(m_contextObj); + ::glLinkProgram((GLuint) program->object()); +} + +void GraphicsContext3D::pixelStorei(unsigned long pname, long param) +{ + ensureContext(m_contextObj); + ::glPixelStorei(pname, param); +} + +void GraphicsContext3D::polygonOffset(double factor, double units) +{ + ensureContext(m_contextObj); + ::glPolygonOffset(static_cast<float>(factor), static_cast<float>(units)); +} + +void GraphicsContext3D::releaseShaderCompiler() +{ + // FIXME: This is not implemented on desktop OpenGL. We need to have ifdefs for the different GL variants + ensureContext(m_contextObj); + //::glReleaseShaderCompiler(); +} + +void GraphicsContext3D::renderbufferStorage(unsigned long target, unsigned long internalformat, unsigned long width, unsigned long height) +{ + ensureContext(m_contextObj); + ::glRenderbufferStorageEXT(target, internalformat, width, height); +} + +void GraphicsContext3D::sampleCoverage(double value, bool invert) +{ + ensureContext(m_contextObj); + ::glSampleCoverage(static_cast<float>(value), invert); +} + +void GraphicsContext3D::scissor(long x, long y, unsigned long width, unsigned long height) +{ + ensureContext(m_contextObj); + ::glScissor(x, y, width, height); +} + +void GraphicsContext3D::shaderSource(CanvasShader* shader, const String& string) +{ + if (!shader) + return; + + ensureContext(m_contextObj); + const CString& cs = string.utf8(); + const char* s = cs.data(); + + int length = string.length(); + ::glShaderSource((GLuint) shader->object(), 1, &s, &length); +} + +void GraphicsContext3D::stencilFunc(unsigned long func, long ref, unsigned long mask) +{ + ensureContext(m_contextObj); + ::glStencilFunc(func, ref, mask); +} + +void GraphicsContext3D::stencilFuncSeparate(unsigned long face, unsigned long func, long ref, unsigned long mask) +{ + ensureContext(m_contextObj); + ::glStencilFuncSeparate(face, func, ref, mask); +} + +void GraphicsContext3D::stencilMask(unsigned long mask) +{ + ensureContext(m_contextObj); + ::glStencilMask(mask); +} + +void GraphicsContext3D::stencilMaskSeparate(unsigned long face, unsigned long mask) +{ + ensureContext(m_contextObj); + ::glStencilMaskSeparate(face, mask); +} + +void GraphicsContext3D::stencilOp(unsigned long fail, unsigned long zfail, unsigned long zpass) +{ + ensureContext(m_contextObj); + ::glStencilOp(fail, zfail, zpass); +} + +void GraphicsContext3D::stencilOpSeparate(unsigned long face, unsigned long fail, unsigned long zfail, unsigned long zpass) +{ + ensureContext(m_contextObj); + ::glStencilOpSeparate(face, fail, zfail, zpass); +} + +void GraphicsContext3D::texParameterf(unsigned target, unsigned pname, float value) +{ + ensureContext(m_contextObj); + ::glTexParameterf(target, pname, static_cast<float>(value)); +} + +void GraphicsContext3D::texParameteri(unsigned target, unsigned pname, int value) +{ + ensureContext(m_contextObj); + ::glTexParameteri(target, pname, static_cast<float>(value)); +} + +void GraphicsContext3D::uniform1f(long location, float v0) +{ + ensureContext(m_contextObj); + ::glUniform1f(location, v0); +} + +void GraphicsContext3D::uniform1fv(long location, float* array, int size) +{ + ensureContext(m_contextObj); + ::glUniform1fv(location, size, array); +} + +void GraphicsContext3D::uniform2f(long location, float v0, float v1) +{ + ensureContext(m_contextObj); + ::glUniform2f(location, v0, v1); +} + +void GraphicsContext3D::uniform2fv(long location, float* array, int size) +{ + // FIXME: length needs to be a multiple of 2 + ensureContext(m_contextObj); + ::glUniform2fv(location, size, array); +} + +void GraphicsContext3D::uniform3f(long location, float v0, float v1, float v2) +{ + ensureContext(m_contextObj); + ::glUniform3f(location, v0, v1, v2); +} + +void GraphicsContext3D::uniform3fv(long location, float* array, int size) +{ + // FIXME: length needs to be a multiple of 3 + ensureContext(m_contextObj); + ::glUniform3fv(location, size, array); +} + +void GraphicsContext3D::uniform4f(long location, float v0, float v1, float v2, float v3) +{ + ensureContext(m_contextObj); + ::glUniform4f(location, v0, v1, v2, v3); +} + +void GraphicsContext3D::uniform4fv(long location, float* array, int size) +{ + // FIXME: length needs to be a multiple of 4 + ensureContext(m_contextObj); + ::glUniform4fv(location, size, array); +} + +void GraphicsContext3D::uniform1i(long location, int v0) +{ + ensureContext(m_contextObj); + ::glUniform1i(location, v0); +} + +void GraphicsContext3D::uniform1iv(long location, int* array, int size) +{ + ensureContext(m_contextObj); + ::glUniform1iv(location, size, array); +} + +void GraphicsContext3D::uniform2i(long location, int v0, int v1) +{ + ensureContext(m_contextObj); + ::glUniform2i(location, v0, v1); +} + +void GraphicsContext3D::uniform2iv(long location, int* array, int size) +{ + // FIXME: length needs to be a multiple of 2 + ensureContext(m_contextObj); + ::glUniform2iv(location, size, array); +} + +void GraphicsContext3D::uniform3i(long location, int v0, int v1, int v2) +{ + ensureContext(m_contextObj); + ::glUniform3i(location, v0, v1, v2); +} + +void GraphicsContext3D::uniform3iv(long location, int* array, int size) +{ + // FIXME: length needs to be a multiple of 3 + ensureContext(m_contextObj); + ::glUniform3iv(location, size, array); +} + +void GraphicsContext3D::uniform4i(long location, int v0, int v1, int v2, int v3) +{ + ensureContext(m_contextObj); + ::glUniform4i(location, v0, v1, v2, v3); +} + +void GraphicsContext3D::uniform4iv(long location, int* array, int size) +{ + // FIXME: length needs to be a multiple of 4 + ensureContext(m_contextObj); + ::glUniform4iv(location, size, array); +} + +void GraphicsContext3D::uniformMatrix2fv(long location, bool transpose, float* array, int size) +{ + // FIXME: length needs to be a multiple of 4 + ensureContext(m_contextObj); + ::glUniformMatrix2fv(location, size, transpose, array); +} + +void GraphicsContext3D::uniformMatrix3fv(long location, bool transpose, float* array, int size) +{ + // FIXME: length needs to be a multiple of 9 + ensureContext(m_contextObj); + ::glUniformMatrix3fv(location, size, transpose, array); +} + +void GraphicsContext3D::uniformMatrix4fv(long location, bool transpose, float* array, int size) +{ + // FIXME: length needs to be a multiple of 16 + ensureContext(m_contextObj); + ::glUniformMatrix4fv(location, size, transpose, array); +} + +void GraphicsContext3D::useProgram(CanvasProgram* program) +{ + if (!program) + return; + + ensureContext(m_contextObj); + ::glUseProgram((GLuint) program->object()); +} + +void GraphicsContext3D::validateProgram(CanvasProgram* program) +{ + if (!program) + return; + + ensureContext(m_contextObj); + ::glValidateProgram((GLuint) program->object()); +} + +void GraphicsContext3D::vertexAttrib1f(unsigned long indx, float v0) +{ + ensureContext(m_contextObj); + ::glVertexAttrib1f(indx, v0); +} + +void GraphicsContext3D::vertexAttrib1fv(unsigned long indx, float* array) +{ + ensureContext(m_contextObj); + ::glVertexAttrib1fv(indx, array); +} + +void GraphicsContext3D::vertexAttrib2f(unsigned long indx, float v0, float v1) +{ + ensureContext(m_contextObj); + ::glVertexAttrib2f(indx, v0, v1); +} + +void GraphicsContext3D::vertexAttrib2fv(unsigned long indx, float* array) +{ + ensureContext(m_contextObj); + ::glVertexAttrib2fv(indx, array); +} + +void GraphicsContext3D::vertexAttrib3f(unsigned long indx, float v0, float v1, float v2) +{ + ensureContext(m_contextObj); + ::glVertexAttrib3f(indx, v0, v1, v2); +} + +void GraphicsContext3D::vertexAttrib3fv(unsigned long indx, float* array) +{ + ensureContext(m_contextObj); + ::glVertexAttrib3fv(indx, array); +} + +void GraphicsContext3D::vertexAttrib4f(unsigned long indx, float v0, float v1, float v2, float v3) +{ + ensureContext(m_contextObj); + ::glVertexAttrib4f(indx, v0, v1, v2, v3); +} + +void GraphicsContext3D::vertexAttrib4fv(unsigned long indx, float* array) +{ + ensureContext(m_contextObj); + ::glVertexAttrib4fv(indx, array); +} + +void GraphicsContext3D::vertexAttribPointer(unsigned long indx, int size, int type, bool normalized, unsigned long stride, unsigned long offset) +{ + ensureContext(m_contextObj); + ::glVertexAttribPointer(indx, size, type, normalized, stride, reinterpret_cast<void*>(static_cast<intptr_t>(offset))); +} + +void GraphicsContext3D::viewport(long x, long y, unsigned long width, unsigned long height) +{ + ensureContext(m_contextObj); + ::glViewport(static_cast<GLint>(x), static_cast<GLint>(y), static_cast<GLsizei>(width), static_cast<GLsizei>(height)); +} + +static int sizeForGetParam(unsigned long pname) +{ + switch(pname) { + case GL_ACTIVE_TEXTURE: return 1; + case GL_ALIASED_LINE_WIDTH_RANGE: return 2; + case GL_ALIASED_POINT_SIZE_RANGE: return 2; + case GL_ALPHA_BITS: return 1; + case GL_ARRAY_BUFFER_BINDING: return 1; // (* actually a CanvasBuffer*) + case GL_BLEND: return 1; + case GL_BLEND_COLOR: return 4; + case GL_BLEND_DST_ALPHA: return 1; + case GL_BLEND_DST_RGB: return 1; + case GL_BLEND_EQUATION_ALPHA: return 1; + case GL_BLEND_EQUATION_RGB: return 1; + case GL_BLEND_SRC_ALPHA: return 1; + case GL_BLEND_SRC_RGB: return 1; + case GL_BLUE_BITS: return 1; + case GL_COLOR_CLEAR_VALUE: return 4; + case GL_COLOR_WRITEMASK: return 4; + case GL_COMPRESSED_TEXTURE_FORMATS: return GL_NUM_COMPRESSED_TEXTURE_FORMATS; + case GL_CULL_FACE: return 1; + case GL_CULL_FACE_MODE: return 1; + case GL_CURRENT_PROGRAM: return 1; // (* actually a CanvasProgram*) + case GL_DEPTH_BITS: return 1; + case GL_DEPTH_CLEAR_VALUE: return 1; + case GL_DEPTH_FUNC: return 1; + case GL_DEPTH_RANGE: return 2; + case GL_DEPTH_TEST: return 1; + case GL_DEPTH_WRITEMASK: return 1; + case GL_DITHER: return 1; + case GL_ELEMENT_ARRAY_BUFFER_BINDING: return 1; // (* actually a CanvasBuffer*) + case GL_FRAMEBUFFER_BINDING_EXT: return 1; // (* actually a CanvasFramebuffer*) + case GL_FRONT_FACE: return 1; + case GL_GENERATE_MIPMAP_HINT: return 1; + case GL_GREEN_BITS: return 1; + //case GL_IMPLEMENTATION_COLOR_READ_FORMAT:return 1; + //case GL_IMPLEMENTATION_COLOR_READ_TYPE: return 1; + case GL_LINE_WIDTH: return 1; + case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:return 1; + case GL_MAX_CUBE_MAP_TEXTURE_SIZE: return 1; + //case GL_MAX_FRAGMENT_UNIFORM_VECTORS: return 1; + case GL_MAX_RENDERBUFFER_SIZE_EXT: return 1; + case GL_MAX_TEXTURE_IMAGE_UNITS: return 1; + case GL_MAX_TEXTURE_SIZE: return 1; + //case GL_MAX_VARYING_VECTORS: return 1; + case GL_MAX_VERTEX_ATTRIBS: return 1; + case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: return 1; + //case GL_MAX_VERTEX_UNIFORM_VECTORS: return 1; + case GL_MAX_VIEWPORT_DIMS: return 2; + case GL_NUM_COMPRESSED_TEXTURE_FORMATS: return 1; + //case GL_NUM_SHADER_BINARY_FORMATS: return 1; + case GL_PACK_ALIGNMENT: return 1; + case GL_POLYGON_OFFSET_FACTOR: return 1; + case GL_POLYGON_OFFSET_FILL: return 1; + case GL_POLYGON_OFFSET_UNITS: return 1; + case GL_RED_BITS: return 1; + case GL_RENDERBUFFER_BINDING_EXT: return 1; // (* actually a CanvasRenderbuffer*) + case GL_SAMPLE_BUFFERS: return 1; + case GL_SAMPLE_COVERAGE_INVERT: return 1; + case GL_SAMPLE_COVERAGE_VALUE: return 1; + case GL_SAMPLES: return 1; + case GL_SCISSOR_BOX: return 4; + case GL_SCISSOR_TEST: return 1; + //case GL_SHADER_BINARY_FORMATS: return GL_NUM_SHADER_BINARY_FORMATS; + //case GL_SHADER_COMPILER: return 1; + case GL_STENCIL_BACK_FAIL: return 1; + case GL_STENCIL_BACK_FUNC: return 1; + case GL_STENCIL_BACK_PASS_DEPTH_FAIL: return 1; + case GL_STENCIL_BACK_PASS_DEPTH_PASS: return 1; + case GL_STENCIL_BACK_REF: return 1; + case GL_STENCIL_BACK_VALUE_MASK: return 1; + case GL_STENCIL_BACK_WRITEMASK: return 1; + case GL_STENCIL_BITS: return 1; + case GL_STENCIL_CLEAR_VALUE: return 1; + case GL_STENCIL_FAIL: return 1; + case GL_STENCIL_FUNC: return 1; + case GL_STENCIL_PASS_DEPTH_FAIL: return 1; + case GL_STENCIL_PASS_DEPTH_PASS: return 1; + case GL_STENCIL_REF: return 1; + case GL_STENCIL_TEST: return 1; + case GL_STENCIL_VALUE_MASK: return 1; + case GL_STENCIL_WRITEMASK: return 1; + case GL_SUBPIXEL_BITS: return 1; + case GL_TEXTURE_BINDING_2D: return 1; // (* actually a CanvasTexture*) + case GL_TEXTURE_BINDING_CUBE_MAP: return 1; // (* actually a CanvasTexture*) + case GL_UNPACK_ALIGNMENT: return 1; + case GL_VIEWPORT: return 4; + } + + return -1; +} + +bool GraphicsContext3D::getBoolean(unsigned long pname) +{ + int size = sizeForGetParam(pname); + if (size < 1) + return 0; + + ensureContext(m_contextObj); + + bool isAlloced = false; + GLboolean buf[4]; + GLboolean* pbuf = buf; + + if (size > 4) { + pbuf = (GLboolean*) malloc(size * sizeof(GLboolean)); + isAlloced = true; + } + + ::glGetBooleanv(pname, pbuf); + + bool value = pbuf[0]; + + if (isAlloced) + free(pbuf); + + return value; +} + +PassRefPtr<CanvasUnsignedByteArray> GraphicsContext3D::getBooleanv(unsigned long pname) +{ + int size = sizeForGetParam(pname); + if (size < 1) + return 0; + + ensureContext(m_contextObj); + + RefPtr<CanvasUnsignedByteArray> array = CanvasUnsignedByteArray::create(size); + bool isAlloced = false; + GLboolean buf[4]; + GLboolean* pbuf = buf; + + if (size > 4) { + pbuf = (GLboolean*) malloc(size * sizeof(GLboolean)); + isAlloced = true; + } + + ::glGetBooleanv(pname, pbuf); + + for (int i = 0; i < size; ++i) + array->set(i, static_cast<unsigned char>(pbuf[i])); + + if (isAlloced) + free(pbuf); + + return array; +} + +float GraphicsContext3D::getFloat(unsigned long pname) +{ + int size = sizeForGetParam(pname); + if (size < 1) + return 0; + + ensureContext(m_contextObj); + + bool isAlloced = false; + GLfloat buf[4]; + GLfloat* pbuf = buf; + + if (size > 4) { + pbuf = (GLfloat*) malloc(size * sizeof(GLfloat)); + isAlloced = true; + } + + ::glGetFloatv(pname, pbuf); + + float value = pbuf[0]; + + if (isAlloced) + free(pbuf); + + return value; +} + +PassRefPtr<CanvasFloatArray> GraphicsContext3D::getFloatv(unsigned long pname) +{ + int size = sizeForGetParam(pname); + if (size < 1) + return 0; + + ensureContext(m_contextObj); + + RefPtr<CanvasFloatArray> array = CanvasFloatArray::create(size); + bool isAlloced = false; + GLfloat buf[4]; + GLfloat* pbuf = buf; + + if (size > 4) { + pbuf = (GLfloat*) malloc(size * sizeof(GLfloat)); + isAlloced = true; + } + + ::glGetFloatv(pname, pbuf); + + for (int i = 0; i < size; ++i) + array->set(i, static_cast<float>(pbuf[i])); + + if (isAlloced) + free(pbuf); + + return array; +} + +int GraphicsContext3D::getInteger(unsigned long pname) +{ + int size = sizeForGetParam(pname); + if (size < 1) + return 0; + + ensureContext(m_contextObj); + + bool isAlloced = false; + GLint buf[4]; + GLint* pbuf = buf; + + if (size > 4) { + pbuf = (GLint*) malloc(size * sizeof(GLint)); + isAlloced = true; + } + + ::glGetIntegerv(pname, pbuf); + + int value = pbuf[0]; + + if (isAlloced) + free(pbuf); + + return value; +} + +PassRefPtr<CanvasIntArray> GraphicsContext3D::getIntegerv(unsigned long pname) +{ + int size = sizeForGetParam(pname); + if (size < 1) + return 0; + + ensureContext(m_contextObj); + + RefPtr<CanvasIntArray> array = CanvasIntArray::create(size); + bool isAlloced = false; + GLint buf[4]; + GLint* pbuf = buf; + + if (size > 4) { + pbuf = (GLint*) malloc(size * sizeof(GLint)); + isAlloced = true; + } + + ::glGetIntegerv(pname, pbuf); + + for (int i = 0; i < size; ++i) + array->set(i, static_cast<int>(pbuf[i])); + + if (isAlloced) + free(pbuf); + + return array; +} + +int GraphicsContext3D::getBufferParameteri(unsigned long target, unsigned long pname) +{ + ensureContext(m_contextObj); + GLint data; + ::glGetBufferParameteriv(target, pname, &data); + return data; +} + +PassRefPtr<CanvasIntArray> GraphicsContext3D::getBufferParameteriv(unsigned long target, unsigned long pname) +{ + ensureContext(m_contextObj); + RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); + GLint data; + ::glGetBufferParameteriv(target, pname, &data); + array->set(0, static_cast<int>(data)); + + return array; +} + +int GraphicsContext3D::getFramebufferAttachmentParameteri(unsigned long target, unsigned long attachment, unsigned long pname) +{ + ensureContext(m_contextObj); + GLint data; + ::glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, &data); + return data; +} + +PassRefPtr<CanvasIntArray> GraphicsContext3D::getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long pname) +{ + ensureContext(m_contextObj); + RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); + GLint data; + ::glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, &data); + array->set(0, static_cast<int>(data)); + + return array; +} + +int GraphicsContext3D::getProgrami(CanvasProgram* program, unsigned long pname) +{ + ensureContext(m_contextObj); + GLint data; + ::glGetProgramiv((GLuint) program->object(), pname, &data); + return data; +} + +PassRefPtr<CanvasIntArray> GraphicsContext3D::getProgramiv(CanvasProgram* program, unsigned long pname) +{ + ensureContext(m_contextObj); + RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); + GLint data; + ::glGetProgramiv((GLuint) program->object(), pname, &data); + array->set(0, static_cast<int>(data)); + + return array; +} + +String GraphicsContext3D::getProgramInfoLog(CanvasProgram* program) +{ + if (!program) + return String(); + + ensureContext(m_contextObj); + GLint length; + ::glGetProgramiv((GLuint) program->object(), GL_INFO_LOG_LENGTH, &length); + + GLsizei size; + GLchar* info = (GLchar*) malloc(length); + ::glGetProgramInfoLog((GLuint) program->object(), length, &size, info); + String s(info); + free(info); + return s; +} + +int GraphicsContext3D::getRenderbufferParameteri(unsigned long target, unsigned long pname) +{ + ensureContext(m_contextObj); + GLint data; + ::glGetBufferParameteriv(target, pname, &data); + return data; +} + +PassRefPtr<CanvasIntArray> GraphicsContext3D::getRenderbufferParameteriv(unsigned long target, unsigned long pname) +{ + ensureContext(m_contextObj); + RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); + GLint data; + ::glGetBufferParameteriv(target, pname, &data); + array->set(0, static_cast<int>(data)); + + return array; +} + +int GraphicsContext3D::getShaderi(CanvasShader* shader, unsigned long pname) +{ + if (!shader) + return 0; + + ensureContext(m_contextObj); + GLint data; + ::glGetShaderiv((GLuint) shader->object(), pname, &data); + return data; +} + +PassRefPtr<CanvasIntArray> GraphicsContext3D::getShaderiv(CanvasShader* shader, unsigned long pname) +{ + if (!shader) + return 0; + + ensureContext(m_contextObj); + RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); + GLint data; + ::glGetShaderiv((GLuint) shader->object(), pname, &data); + array->set(0, static_cast<int>(data)); + + return array; +} + +String GraphicsContext3D::getShaderInfoLog(CanvasShader* shader) +{ + if (!shader) + return String(); + + ensureContext(m_contextObj); + GLint length; + ::glGetShaderiv((GLuint) shader->object(), GL_INFO_LOG_LENGTH, &length); + + GLsizei size; + GLchar* info = (GLchar*) malloc(length); + ::glGetShaderInfoLog((GLuint) shader->object(), length, &size, info); + String s(info); + free(info); + return s; +} + +String GraphicsContext3D::getShaderSource(CanvasShader* shader) +{ + if (!shader) + return String(); + + ensureContext(m_contextObj); + GLint length; + ::glGetShaderiv((GLuint) shader->object(), GL_SHADER_SOURCE_LENGTH, &length); + + GLsizei size; + GLchar* info = (GLchar*) malloc(length); + ::glGetShaderSource((GLuint) shader->object(), length, &size, info); + String s(info); + free(info); + return s; +} + + +float GraphicsContext3D::getTexParameterf(unsigned long target, unsigned long pname) +{ + ensureContext(m_contextObj); + GLfloat data; + ::glGetTexParameterfv(target, pname, &data); + return data; +} + +PassRefPtr<CanvasFloatArray> GraphicsContext3D::getTexParameterfv(unsigned long target, unsigned long pname) +{ + ensureContext(m_contextObj); + RefPtr<CanvasFloatArray> array = CanvasFloatArray::create(1); + GLfloat data; + ::glGetTexParameterfv(target, pname, &data); + array->set(0, static_cast<float>(data)); + + return array; +} + +int GraphicsContext3D::getTexParameteri(unsigned long target, unsigned long pname) +{ + ensureContext(m_contextObj); + GLint data; + ::glGetTexParameteriv(target, pname, &data); + return data; +} + +PassRefPtr<CanvasIntArray> GraphicsContext3D::getTexParameteriv(unsigned long target, unsigned long pname) +{ + ensureContext(m_contextObj); + RefPtr<CanvasIntArray> array = CanvasIntArray::create(1); + GLint data; + ::glGetTexParameteriv(target, pname, &data); + array->set(0, static_cast<int>(data)); + + return array; +} + +float GraphicsContext3D::getUniformf(CanvasProgram* program, long location) +{ + // FIXME: We need to query glGetUniformLocation to determine the size needed + UNUSED_PARAM(program); + UNUSED_PARAM(location); + notImplemented(); + return 0; +} + +PassRefPtr<CanvasFloatArray> GraphicsContext3D::getUniformfv(CanvasProgram* program, long location) +{ + // FIXME: We need to query glGetUniformLocation to determine the size needed + UNUSED_PARAM(program); + UNUSED_PARAM(location); + notImplemented(); + return 0; +} + +int GraphicsContext3D::getUniformi(CanvasProgram* program, long location) +{ + // FIXME: We need to query glGetUniformLocation to determine the size needed + UNUSED_PARAM(program); + UNUSED_PARAM(location); + notImplemented(); + return 0; +} + +PassRefPtr<CanvasIntArray> GraphicsContext3D::getUniformiv(CanvasProgram* program, long location) +{ + // FIXME: We need to query glGetUniformLocation to determine the size needed + UNUSED_PARAM(program); + UNUSED_PARAM(location); + notImplemented(); + return 0; +} + +long GraphicsContext3D::getUniformLocation(CanvasProgram* program, const String& name) +{ + if (!program) + return -1; + + ensureContext(m_contextObj); + return ::glGetUniformLocation((GLuint) program->object(), name.utf8().data()); +} + +static int sizeForGetVertexAttribParam(unsigned long pname) +{ + switch(pname) { + case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: return 1; // (* actually a CanvasBuffer*) + case GL_VERTEX_ATTRIB_ARRAY_ENABLED: return 1; + case GL_VERTEX_ATTRIB_ARRAY_SIZE: return 1; + case GL_VERTEX_ATTRIB_ARRAY_STRIDE: return 1; + case GL_VERTEX_ATTRIB_ARRAY_TYPE: return 1; + case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: return 1; + case GL_CURRENT_VERTEX_ATTRIB: return 4; + } + + return -1; +} + +float GraphicsContext3D::getVertexAttribf(unsigned long index, unsigned long pname) +{ + ensureContext(m_contextObj); + GLfloat buf[4]; + ::glGetVertexAttribfv(index, pname, buf); + return buf[0]; +} + +PassRefPtr<CanvasFloatArray> GraphicsContext3D::getVertexAttribfv(unsigned long index, unsigned long pname) +{ + int size = sizeForGetVertexAttribParam(pname); + if (size < 1) + return 0; + + ensureContext(m_contextObj); + + RefPtr<CanvasFloatArray> array = CanvasFloatArray::create(size); + GLfloat buf[4]; + ::glGetVertexAttribfv(index, pname, buf); + + for (int i = 0; i < size; ++i) + array->set(i, static_cast<float>(buf[i])); + + return array; +} + +int GraphicsContext3D::getVertexAttribi(unsigned long index, unsigned long pname) +{ + ensureContext(m_contextObj); + GLint buf[4]; + ::glGetVertexAttribiv(index, pname, buf); + return buf[0]; +} + +PassRefPtr<CanvasIntArray> GraphicsContext3D::getVertexAttribiv(unsigned long index, unsigned long pname) +{ + int size = sizeForGetVertexAttribParam(pname); + if (size < 1) + return 0; + + ensureContext(m_contextObj); + + RefPtr<CanvasIntArray> array = CanvasIntArray::create(size); + GLint buf[4]; + ::glGetVertexAttribiv(index, pname, buf); + + for (int i = 0; i < size; ++i) + array->set(i, static_cast<int>(buf[i])); + + return array; +} + +long GraphicsContext3D::getVertexAttribOffset(unsigned long index, unsigned long pname) +{ + ensureContext(m_contextObj); + + void* pointer; + ::glGetVertexAttribPointerv(index, pname, &pointer); + return reinterpret_cast<long>(pointer); +} + +// Assumes the texture you want to go into is bound +static void imageToTexture(Image* image, unsigned target, unsigned level) +{ + if (!image) + return; + + CGImageRef textureImage = image->getCGImageRef(); + if (!textureImage) + return; + + size_t textureWidth = CGImageGetWidth(textureImage); + size_t textureHeight = CGImageGetHeight(textureImage); + + GLubyte* textureData = (GLubyte*) malloc(textureWidth * textureHeight * 4); + CGContextRef textureContext = CGBitmapContextCreate(textureData, textureWidth, textureHeight, 8, textureWidth * 4, + CGImageGetColorSpace(textureImage), kCGImageAlphaPremultipliedLast); + + CGContextDrawImage(textureContext, CGRectMake(0, 0, (CGFloat)textureWidth, (CGFloat)textureHeight), textureImage); + CGContextRelease(textureContext); + + ::glTexImage2D(target, level, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData); + free(textureData); +} + +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, CanvasArray* pixels) +{ + // FIXME: Need to do bounds checking on the buffer here. + ::glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels->baseAddress()); + return 0; +} + +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, ImageData* pixels) +{ + // FIXME: need to implement this form + UNUSED_PARAM(target); + UNUSED_PARAM(level); + UNUSED_PARAM(internalformat); + UNUSED_PARAM(width); + UNUSED_PARAM(height); + UNUSED_PARAM(border); + UNUSED_PARAM(format); + UNUSED_PARAM(type); + UNUSED_PARAM(pixels); + return -1; +} + +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLImageElement* image, bool flipY, bool premultiplyAlpha) +{ + // FIXME: need to support flipY and premultiplyAlpha + UNUSED_PARAM(flipY); + UNUSED_PARAM(premultiplyAlpha); + + if (!image) + return -1; + + ensureContext(m_contextObj); + CachedImage* cachedImage = image->cachedImage(); + if (!cachedImage) + return -1; + + imageToTexture(cachedImage->image(), target, level); + return 0; +} + +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLCanvasElement* canvas, bool flipY, bool premultiplyAlpha) +{ + // FIXME: need to support flipY and premultiplyAlpha + UNUSED_PARAM(flipY); + UNUSED_PARAM(premultiplyAlpha); + + if (!canvas) + return -1; + + ensureContext(m_contextObj); + ImageBuffer* buffer = canvas->buffer(); + if (!buffer) + return -1; + + imageToTexture(buffer->image(), target, level); + return 0; +} + +int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLVideoElement* video, bool flipY, bool premultiplyAlpha) +{ + // FIXME: need to implement this form + UNUSED_PARAM(target); + UNUSED_PARAM(level); + UNUSED_PARAM(video); + + // FIXME: need to support flipY and premultiplyAlpha + UNUSED_PARAM(flipY); + UNUSED_PARAM(premultiplyAlpha); + return -1; +} + +int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, unsigned format, unsigned type, CanvasArray* pixels) +{ + // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size + UNUSED_PARAM(target); + UNUSED_PARAM(level); + UNUSED_PARAM(xoff); + UNUSED_PARAM(yoff); + UNUSED_PARAM(width); + UNUSED_PARAM(height); + UNUSED_PARAM(format); + UNUSED_PARAM(type); + UNUSED_PARAM(pixels); + return -1; +} + +int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, unsigned format, unsigned type, ImageData* pixels) +{ + // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size + UNUSED_PARAM(target); + UNUSED_PARAM(level); + UNUSED_PARAM(xoff); + UNUSED_PARAM(yoff); + UNUSED_PARAM(width); + UNUSED_PARAM(height); + UNUSED_PARAM(format); + UNUSED_PARAM(type); + UNUSED_PARAM(pixels); + return -1; +} + +int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, HTMLImageElement* image, bool flipY, bool premultiplyAlpha) +{ + // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size + UNUSED_PARAM(target); + UNUSED_PARAM(level); + UNUSED_PARAM(xoff); + UNUSED_PARAM(yoff); + UNUSED_PARAM(width); + UNUSED_PARAM(height); + UNUSED_PARAM(image); + + // FIXME: need to support flipY and premultiplyAlpha + UNUSED_PARAM(flipY); + UNUSED_PARAM(premultiplyAlpha); + return -1; +} + +int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, HTMLCanvasElement* canvas, bool flipY, bool premultiplyAlpha) +{ + // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size + UNUSED_PARAM(target); + UNUSED_PARAM(level); + UNUSED_PARAM(xoff); + UNUSED_PARAM(yoff); + UNUSED_PARAM(width); + UNUSED_PARAM(height); + UNUSED_PARAM(canvas); + + // FIXME: need to support flipY and premultiplyAlpha + UNUSED_PARAM(flipY); + UNUSED_PARAM(premultiplyAlpha); + return -1; +} + +int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, HTMLVideoElement* video, bool flipY, bool premultiplyAlpha) +{ + // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size + UNUSED_PARAM(target); + UNUSED_PARAM(level); + UNUSED_PARAM(xoff); + UNUSED_PARAM(yoff); + UNUSED_PARAM(width); + UNUSED_PARAM(height); + UNUSED_PARAM(video); + + // FIXME: need to support flipY and premultiplyAlpha + UNUSED_PARAM(flipY); + UNUSED_PARAM(premultiplyAlpha); + return -1; +} + +unsigned GraphicsContext3D::createBuffer() +{ + ensureContext(m_contextObj); + GLuint o; + glGenBuffers(1, &o); + return o; +} + +unsigned GraphicsContext3D::createFramebuffer() +{ + ensureContext(m_contextObj); + GLuint o; + glGenFramebuffersEXT(1, &o); + return o; +} + +unsigned GraphicsContext3D::createProgram() +{ + ensureContext(m_contextObj); + return glCreateProgram(); +} + +unsigned GraphicsContext3D::createRenderbuffer() +{ + ensureContext(m_contextObj); + GLuint o; + glGenRenderbuffersEXT(1, &o); + return o; +} + +unsigned GraphicsContext3D::createShader(ShaderType type) +{ + ensureContext(m_contextObj); + return glCreateShader((type == FRAGMENT_SHADER) ? GL_FRAGMENT_SHADER : GL_VERTEX_SHADER); +} + +unsigned GraphicsContext3D::createTexture() +{ + ensureContext(m_contextObj); + GLuint o; + glGenTextures(1, &o); + return o; +} + +void GraphicsContext3D::deleteBuffer(unsigned buffer) +{ + ensureContext(m_contextObj); + glDeleteBuffers(1, &buffer); +} + +void GraphicsContext3D::deleteFramebuffer(unsigned framebuffer) +{ + ensureContext(m_contextObj); + glDeleteFramebuffersEXT(1, &framebuffer); +} + +void GraphicsContext3D::deleteProgram(unsigned program) +{ + ensureContext(m_contextObj); + glDeleteProgram(program); +} + +void GraphicsContext3D::deleteRenderbuffer(unsigned renderbuffer) +{ + ensureContext(m_contextObj); + glDeleteRenderbuffersEXT(1, &renderbuffer); +} + +void GraphicsContext3D::deleteShader(unsigned shader) +{ + ensureContext(m_contextObj); + glDeleteShader(shader); +} + +void GraphicsContext3D::deleteTexture(unsigned texture) +{ + ensureContext(m_contextObj); + glDeleteTextures(1, &texture); +} + +int GraphicsContext3D::sizeInBytes(int type) +{ + switch (type) { + case GL_BYTE: + return sizeof(GLbyte); + case GL_UNSIGNED_BYTE: + return sizeof(GLubyte); + case GL_SHORT: + return sizeof(GLshort); + case GL_UNSIGNED_SHORT: + return sizeof(GLushort); + case GL_INT: + return sizeof(GLint); + case GL_UNSIGNED_INT: + return sizeof(GLuint); + case GL_FLOAT: + return sizeof(GLfloat); + default: + return 0; + } +} + +} + +#endif // ENABLE(3D_CANVAS) diff --git a/WebCore/platform/graphics/mac/GraphicsContextMac.mm b/WebCore/platform/graphics/mac/GraphicsContextMac.mm index 2404319..6c9b872 100644 --- a/WebCore/platform/graphics/mac/GraphicsContextMac.mm +++ b/WebCore/platform/graphics/mac/GraphicsContextMac.mm @@ -50,27 +50,26 @@ void GraphicsContext::drawFocusRing(const Color& color) int radius = (focusRingWidth() - 1) / 2; int offset = radius + focusRingOffset(); - CGColorRef colorRef = color.isValid() ? createCGColor(color) : 0; + RetainPtr<CGColorRef> colorRef; + if (color.isValid()) + colorRef.adoptCF(createCGColor(color)); - CGMutablePathRef focusRingPath = CGPathCreateMutable(); + RetainPtr<CGMutablePathRef> focusRingPath(AdoptCF, CGPathCreateMutable()); const Vector<IntRect>& rects = focusRingRects(); unsigned rectCount = rects.size(); for (unsigned i = 0; i < rectCount; i++) - CGPathAddRect(focusRingPath, 0, CGRectInset(rects[i], -offset, -offset)); + CGPathAddRect(focusRingPath.get(), 0, CGRectInset(rects[i], -offset, -offset)); CGContextRef context = platformContext(); #ifdef BUILDING_ON_TIGER CGContextBeginTransparencyLayer(context, NULL); #endif CGContextBeginPath(context); - CGContextAddPath(context, focusRingPath); - wkDrawFocusRing(context, colorRef, radius); + CGContextAddPath(context, focusRingPath.get()); + wkDrawFocusRing(context, colorRef.get(), radius); #ifdef BUILDING_ON_TIGER CGContextEndTransparencyLayer(context); #endif - CGColorRelease(colorRef); - - CGPathRelease(focusRingPath); } #ifdef BUILDING_ON_TIGER // Post-Tiger's setCompositeOperation() is defined in GraphicsContextCG.cpp. diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.h b/WebCore/platform/graphics/mac/GraphicsLayerCA.h index ebdc6ac..d0e1108 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.h +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.h @@ -62,6 +62,8 @@ public: virtual void removeFromParent(); + virtual void setMaskLayer(GraphicsLayer*); + virtual void setPosition(const FloatPoint&); virtual void setAnchorPoint(const FloatPoint3D&); virtual void setSize(const FloatSize&); @@ -86,6 +88,10 @@ public: virtual void setNeedsDisplay(); virtual void setNeedsDisplayInRect(const FloatRect&); +#if ENABLE(3D_CANVAS) + virtual void setGraphicsContext3DNeedsDisplay(); +#endif + virtual void setContentsRect(const IntRect&); virtual void suspendAnimations(double time); @@ -98,6 +104,9 @@ public: virtual void setContentsToImage(Image*); virtual void setContentsToVideo(PlatformLayer*); +#if ENABLE(3D_CANVAS) + virtual void setContentsToGraphicsContext3D(const GraphicsContext3D*); +#endif virtual PlatformLayer* platformLayer() const; @@ -170,8 +179,12 @@ private: void updateContentsImage(); void updateContentsVideo(); +#if ENABLE(3D_CANVAS) + void updateContentsGraphicsContext3D(); +#endif void updateContentsRect(); void updateGeometryOrientation(); + void updateMaskLayer(); void updateLayerAnimations(); @@ -199,8 +212,12 @@ private: DirtyRectsChanged = 1 << 16, ContentsImageChanged = 1 << 17, ContentsVideoChanged = 1 << 18, - ContentsRectChanged = 1 << 19, - GeometryOrientationChanged = 1 << 20 +#if ENABLE(3D_CANVAS) + ContentsGraphicsContext3DChanged = 1 << 19, +#endif + ContentsRectChanged = 1 << 20, + GeometryOrientationChanged = 1 << 21, + MaskLayerChanged = 1 << 22 }; typedef unsigned LayerChangeFlags; void noteLayerPropertyChanged(LayerChangeFlags flags); @@ -215,6 +232,9 @@ private: NoContentsLayer = 0, ContentsLayerForImage, ContentsLayerForVideo +#if ENABLE(3D_CANVAS) + ,ContentsLayerForGraphicsLayer3D +#endif }; ContentsLayerPurpose m_contentsLayerPurpose; @@ -260,6 +280,11 @@ private: Vector<FloatRect> m_dirtyRects; LayerChangeFlags m_uncommittedChanges; + +#if ENABLE(3D_CANVAS) + PlatformGraphicsContext3D m_platformGraphicsContext3D; + Platform3DObject m_platformTexture; +#endif }; } // namespace WebCore diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm index e5b9035..e9960f1 100644 --- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm @@ -31,6 +31,9 @@ #import "Animation.h" #import "BlockExceptions.h" +#if ENABLE(3D_CANVAS) +#import "Canvas3DLayer.h" +#endif #import "CString.h" #import "FloatConversion.h" #import "FloatRect.h" @@ -145,11 +148,11 @@ static NSValue* getTransformFunctionValue(const TransformOperation* transformOp, case TransformOperation::ROTATE_Y: return [NSNumber numberWithDouble:transformOp ? deg2rad(static_cast<const RotateTransformOperation*>(transformOp)->angle()) : 0]; case TransformOperation::SCALE_X: - return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->x() : 0]; + return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->x() : 1]; case TransformOperation::SCALE_Y: - return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->y() : 0]; + return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->y() : 1]; case TransformOperation::SCALE_Z: - return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->z() : 0]; + return [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->z() : 1]; case TransformOperation::TRANSLATE_X: return [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->x(size) : 0]; case TransformOperation::TRANSLATE_Y: @@ -157,13 +160,23 @@ static NSValue* getTransformFunctionValue(const TransformOperation* transformOp, case TransformOperation::TRANSLATE_Z: return [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->z(size) : 0]; case TransformOperation::SCALE: + case TransformOperation::SCALE_3D: + return [NSArray arrayWithObjects: + [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->x() : 1], + [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->y() : 1], + [NSNumber numberWithDouble:transformOp ? static_cast<const ScaleTransformOperation*>(transformOp)->z() : 1], + nil]; case TransformOperation::TRANSLATE: + case TransformOperation::TRANSLATE_3D: + return [NSArray arrayWithObjects: + [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->x(size) : 0], + [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->y(size) : 0], + [NSNumber numberWithDouble:transformOp ? static_cast<const TranslateTransformOperation*>(transformOp)->z(size) : 0], + nil]; case TransformOperation::SKEW_X: case TransformOperation::SKEW_Y: case TransformOperation::SKEW: case TransformOperation::MATRIX: - case TransformOperation::SCALE_3D: - case TransformOperation::TRANSLATE_3D: case TransformOperation::ROTATE_3D: case TransformOperation::MATRIX_3D: case TransformOperation::PERSPECTIVE: @@ -204,6 +217,12 @@ static NSString* getValueFunctionNameForTransformOperation(TransformOperation::O return @"translateY"; // kCAValueFunctionTranslateY; case TransformOperation::TRANSLATE_Z: return @"translateZ"; // kCAValueFunctionTranslateZ; + case TransformOperation::SCALE: + case TransformOperation::SCALE_3D: + return @"scale"; // kCAValueFunctionScale; + case TransformOperation::TRANSLATE: + case TransformOperation::TRANSLATE_3D: + return @"translate"; // kCAValueFunctionTranslate; default: return nil; } @@ -331,7 +350,7 @@ static NSDictionary* nullActionsDictionary() return actions; } -GraphicsLayer* GraphicsLayer::createGraphicsLayer(GraphicsLayerClient* client) +PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client) { return new GraphicsLayerCA(client); } @@ -341,6 +360,10 @@ GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client) , m_contentsLayerPurpose(NoContentsLayer) , m_contentsLayerHasBackgroundColor(false) , m_uncommittedChanges(NoChange) +#if ENABLE(3D_CANVAS) +, m_platformGraphicsContext3D(NullPlatformGraphicsContext3D) +, m_platformTexture(NullPlatform3DObject) +#endif { BEGIN_BLOCK_OBJC_EXCEPTIONS m_layer.adoptNS([[WebLayer alloc] init]); @@ -432,6 +455,15 @@ void GraphicsLayerCA::removeFromParent() GraphicsLayer::removeFromParent(); } +void GraphicsLayerCA::setMaskLayer(GraphicsLayer* layer) +{ + if (layer == m_maskLayer) + return; + + GraphicsLayer::setMaskLayer(layer); + noteLayerPropertyChanged(MaskLayerChanged); +} + void GraphicsLayerCA::setPosition(const FloatPoint& point) { if (point == m_position) @@ -672,10 +704,10 @@ void GraphicsLayerCA::setContentsToImage(Image* image) CGColorSpaceRef colorSpace = CGImageGetColorSpace(m_pendingContentsImage.get()); static CGColorSpaceRef deviceRGB = CGColorSpaceCreateDeviceRGB(); - if (CFEqual(colorSpace, deviceRGB)) { - // CoreGraphics renders images tagged with DeviceRGB using GenericRGB. When we hand such + if (colorSpace && CFEqual(colorSpace, deviceRGB)) { + // CoreGraphics renders images tagged with DeviceRGB using the color space of the main display. When we hand such // images to CA we need to tag them similarly so CA rendering matches CG rendering. - static CGColorSpaceRef genericRGB = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + static CGColorSpaceRef genericRGB = CGDisplayCopyColorSpace(kCGDirectMainDisplay); m_pendingContentsImage.adoptCF(CGImageCreateCopyWithColorSpace(m_pendingContentsImage.get(), genericRGB)); } m_contentsLayerPurpose = ContentsLayerForImage; @@ -733,6 +765,9 @@ void GraphicsLayerCA::recursiveCommitChanges() { commitLayerChanges(); + if (m_maskLayer) + static_cast<GraphicsLayerCA*>(m_maskLayer)->commitLayerChanges(); + const Vector<GraphicsLayer*>& childLayers = children(); size_t numChildren = childLayers.size(); for (size_t i = 0; i < numChildren; ++i) { @@ -763,7 +798,12 @@ void GraphicsLayerCA::commitLayerChanges() if (m_uncommittedChanges & ContentsVideoChanged) // Needs to happen before ChildrenChanged updateContentsVideo(); - + +#if ENABLE(3D_CANVAS) + if (m_uncommittedChanges & ContentsGraphicsContext3DChanged) // Needs to happen before ChildrenChanged + updateContentsGraphicsContext3D(); +#endif + if (m_uncommittedChanges & BackgroundColorChanged) // Needs to happen before ChildrenChanged, and after updating image or video updateLayerBackgroundColor(); @@ -812,6 +852,9 @@ void GraphicsLayerCA::commitLayerChanges() if (m_uncommittedChanges & GeometryOrientationChanged) updateGeometryOrientation(); + if (m_uncommittedChanges & MaskLayerChanged) + updateMaskLayer(); + m_uncommittedChanges = NoChange; END_BLOCK_OBJC_EXCEPTIONS } @@ -821,10 +864,12 @@ void GraphicsLayerCA::updateSublayerList() NSMutableArray* newSublayers = nil; if (m_transformLayer) { - // FIXME: add the primary layer in the correct order with negative z-order children. + // Add the primary layer first. Even if we have negative z-order children, the primary layer always comes behind. newSublayers = [[NSMutableArray alloc] initWithObjects:m_layer.get(), nil]; } else if (m_contentsLayer) { // FIXME: add the contents layer in the correct order with negative z-order children. + // This does not cause visible rendering issues because currently contents layers are only used + // for replaced elements that don't have children. newSublayers = [[NSMutableArray alloc] initWithObjects:m_contentsLayer.get(), nil]; } @@ -1061,6 +1106,18 @@ void GraphicsLayerCA::updateContentsVideo() } } +#if ENABLE(3D_CANVAS) +void GraphicsLayerCA::updateContentsGraphicsContext3D() +{ + // Canvas3D layer was set as m_contentsLayer, and will get parented in updateSublayerList(). + if (m_contentsLayer) { + setupContentsLayer(m_contentsLayer.get()); + [m_contentsLayer.get() setNeedsDisplay]; + updateContentsRect(); + } +} +#endif + void GraphicsLayerCA::updateContentsRect() { if (!m_contentsLayer) @@ -1094,6 +1151,12 @@ void GraphicsLayerCA::updateGeometryOrientation() #endif } +void GraphicsLayerCA::updateMaskLayer() +{ + CALayer* maskCALayer = m_maskLayer ? m_maskLayer->platformLayer() : 0; + [m_layer.get() setMask:maskCALayer]; +} + void GraphicsLayerCA::updateLayerAnimations() { if (m_transitionPropertiesToRemove.size()) { @@ -1247,6 +1310,40 @@ void GraphicsLayerCA::pauseAnimationOnLayer(AnimatedPropertyID property, int ind [layer addAnimation:pausedAnim forKey:animationName]; // This will replace the running animation. } +#if ENABLE(3D_CANVAS) +void GraphicsLayerCA::setContentsToGraphicsContext3D(const GraphicsContext3D* graphicsContext3D) +{ + PlatformGraphicsContext3D context = graphicsContext3D->platformGraphicsContext3D(); + Platform3DObject texture = graphicsContext3D->platformTexture(); + + if (context == m_platformGraphicsContext3D && texture == m_platformTexture) + return; + + m_platformGraphicsContext3D = context; + m_platformTexture = texture; + + noteLayerPropertyChanged(ChildrenChanged); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + + if (m_platformGraphicsContext3D != NullPlatformGraphicsContext3D && m_platformTexture != NullPlatform3DObject) { + // create the inner 3d layer + m_contentsLayer.adoptNS([[Canvas3DLayer alloc] initWithContext:static_cast<CGLContextObj>(m_platformGraphicsContext3D) texture:static_cast<GLuint>(m_platformTexture)]); +#ifndef NDEBUG + [m_contentsLayer.get() setName:@"3D Layer"]; +#endif + } else { + // remove the inner layer + m_contentsLayer = 0; + } + + END_BLOCK_OBJC_EXCEPTIONS + + noteLayerPropertyChanged(ContentsGraphicsContext3DChanged); + m_contentsLayerPurpose = m_contentsLayer ? ContentsLayerForGraphicsLayer3D : NoContentsLayer; +} +#endif + void GraphicsLayerCA::repaintLayerDirtyRects() { if (!m_dirtyRects.size()) @@ -1765,6 +1862,14 @@ void GraphicsLayerCA::noteLayerPropertyChanged(LayerChangeFlags flags) m_uncommittedChanges |= flags; } +#if ENABLE(3D_CANVAS) +void GraphicsLayerCA::setGraphicsContext3DNeedsDisplay() +{ + if (m_contentsLayerPurpose == ContentsLayerForGraphicsLayer3D) + [m_contentsLayer.get() setNeedsDisplay]; +} +#endif + } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/mac/ImageMac.mm b/WebCore/platform/graphics/mac/ImageMac.mm index a0d257b..672c3c8 100644 --- a/WebCore/platform/graphics/mac/ImageMac.mm +++ b/WebCore/platform/graphics/mac/ImageMac.mm @@ -94,16 +94,15 @@ CFDataRef BitmapImage::getTIFFRepresentation() RetainPtr<CFMutableDataRef> data(AdoptCF, CFDataCreateMutable(0, 0)); // FIXME: Use type kCGImageTypeIdentifierTIFF constant once is becomes available in the API - CGImageDestinationRef destination = CGImageDestinationCreateWithData(data.get(), CFSTR("public.tiff"), numValidFrames, 0); - + RetainPtr<CGImageDestinationRef> destination(AdoptCF, CGImageDestinationCreateWithData(data.get(), CFSTR("public.tiff"), numValidFrames, 0)); + if (!destination) return 0; for (unsigned i = 0; i < numValidFrames; ++i) - CGImageDestinationAddImage(destination, images[i], 0); + CGImageDestinationAddImage(destination.get(), images[i], 0); - CGImageDestinationFinalize(destination); - CFRelease(destination); + CGImageDestinationFinalize(destination.get()); m_tiffRep = data; return m_tiffRep.get(); diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h index 54eea00..0a63626 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h @@ -77,8 +77,12 @@ private: static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); static bool isAvailable(); + PlatformMedia platformMedia() const; + IntSize naturalSize() const; bool hasVideo() const; + bool hasAudio() const; + bool supportsFullscreen() const; void load(const String& url); void cancelLoad(); @@ -104,7 +108,7 @@ private: MediaPlayer::NetworkState networkState() const { return m_networkState; } MediaPlayer::ReadyState readyState() const { return m_readyState; } - float maxTimeBuffered() const; + PassRefPtr<TimeRanges> buffered() const; float maxTimeSeekable() const; unsigned bytesLoaded() const; bool totalBytesKnown() const; diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm index c1d7fcb..30d0c82 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm @@ -39,6 +39,7 @@ #import "KURL.h" #import "MIMETypeRegistry.h" #import "SoftLinking.h" +#import "TimeRanges.h" #import "WebCoreSystemInterface.h" #import <QTKit/QTKit.h> #import <objc/objc-runtime.h> @@ -84,6 +85,7 @@ SOFT_LINK_POINTER(QTKit, QTMovieAskUnresolvedDataRefsAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieDataSizeAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieDidEndNotification, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieHasVideoAttribute, NSString *) +SOFT_LINK_POINTER(QTKit, QTMovieHasAudioAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieIsActiveAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieLoadStateAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMovieLoadStateDidChangeNotification, NSString *) @@ -119,6 +121,7 @@ SOFT_LINK_POINTER(QTKit, QTMovieApertureModeAttribute, NSString *) #define QTMovieDataSizeAttribute getQTMovieDataSizeAttribute() #define QTMovieDidEndNotification getQTMovieDidEndNotification() #define QTMovieHasVideoAttribute getQTMovieHasVideoAttribute() +#define QTMovieHasAudioAttribute getQTMovieHasAudioAttribute() #define QTMovieIsActiveAttribute getQTMovieIsActiveAttribute() #define QTMovieLoadStateAttribute getQTMovieLoadStateAttribute() #define QTMovieLoadStateDidChangeNotification getQTMovieLoadStateDidChangeNotification() @@ -230,7 +233,7 @@ MediaPlayerPrivate::~MediaPlayerPrivate() void MediaPlayerPrivate::createQTMovie(const String& url) { - NSURL *cocoaURL = KURL(url); + NSURL *cocoaURL = KURL(ParsedURLString, url); NSDictionary *movieAttributes = [NSDictionary dictionaryWithObjectsAndKeys: cocoaURL, QTMovieURLAttribute, [NSNumber numberWithBool:m_player->preservesPitch()], QTMovieRateChangesPreservePitchAttribute, @@ -562,6 +565,12 @@ void MediaPlayerPrivate::load(const String& url) [m_objcObserver.get() setDelayCallbacks:NO]; } +PlatformMedia MediaPlayerPrivate::platformMedia() const +{ + PlatformMedia plaftformMedia = { m_qtMovie.get() }; + return plaftformMedia; +} + void MediaPlayerPrivate::play() { if (!metaDataAvailable()) @@ -719,18 +728,28 @@ bool MediaPlayerPrivate::hasVideo() const return [[m_qtMovie.get() attributeForKey:QTMovieHasVideoAttribute] boolValue]; } +bool MediaPlayerPrivate::hasAudio() const +{ + if (!m_qtMovie) + return false; + return [[m_qtMovie.get() attributeForKey:QTMovieHasAudioAttribute] boolValue]; +} + +bool MediaPlayerPrivate::supportsFullscreen() const +{ + return true; +} + void MediaPlayerPrivate::setVolume(float volume) { - if (!metaDataAvailable()) - return; - [m_qtMovie.get() setVolume:volume]; + if (m_qtMovie) + [m_qtMovie.get() setVolume:volume]; } void MediaPlayerPrivate::setRate(float rate) { - if (!metaDataAvailable()) - return; - [m_qtMovie.get() setRate:rate]; + if (m_qtMovie) + [m_qtMovie.get() setRate:rate]; } void MediaPlayerPrivate::setPreservesPitch(bool preservesPitch) @@ -758,10 +777,13 @@ int MediaPlayerPrivate::dataRate() const return wkQTMovieDataRate(m_qtMovie.get()); } - -float MediaPlayerPrivate::maxTimeBuffered() const +PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const { - return maxTimeLoaded(); + RefPtr<TimeRanges> timeRanges = TimeRanges::create(); + float loaded = maxTimeLoaded(); + if (loaded > 0) + timeRanges->add(0, loaded); + return timeRanges.release(); } float MediaPlayerPrivate::maxTimeSeekable() const diff --git a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm index cdde7cf..97a7251 100644 --- a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm +++ b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm @@ -50,6 +50,8 @@ - (BOOL)_isFakeFixedPitch; @end +using namespace std; + namespace WebCore { const float smallCapsFontSizeMultiplier = 0.7f; @@ -269,7 +271,7 @@ void SimpleFontData::platformInit() // and web pages that foolishly use this metric for width will be laid out // poorly if we return an accurate height. Classic case is Times 13 point, // which has an "x" that is 7x6 pixels. - m_xHeight = MAX(NSMaxX(xBox), NSMaxY(xBox)); + m_xHeight = max(NSMaxX(xBox), NSMaxY(xBox)); } else m_xHeight = [m_platformData.font() xHeight]; } @@ -443,13 +445,13 @@ CTFontRef SimpleFontData::getCTFont() const return m_CTFont.get(); } -CFDictionaryRef SimpleFontData::getCFStringAttributes() const +CFDictionaryRef SimpleFontData::getCFStringAttributes(TextRenderingMode textMode) const { if (m_CFStringAttributes) return m_CFStringAttributes.get(); - static const float kerningAdjustmentValue = 0; - static CFNumberRef kerningAdjustment = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &kerningAdjustmentValue); + bool allowKerning = textMode == OptimizeLegibility || textMode == GeometricPrecision; + bool allowLigatures = platformData().allowsLigatures() || allowKerning; static const int ligaturesNotAllowedValue = 0; static CFNumberRef ligaturesNotAllowed = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &ligaturesNotAllowedValue); @@ -457,10 +459,23 @@ CFDictionaryRef SimpleFontData::getCFStringAttributes() const static const int ligaturesAllowedValue = 1; static CFNumberRef ligaturesAllowed = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &ligaturesAllowedValue); - static const void* attributeKeys[] = { kCTFontAttributeName, kCTKernAttributeName, kCTLigatureAttributeName }; - const void* attributeValues[] = { getCTFont(), kerningAdjustment, platformData().allowsLigatures() ? ligaturesAllowed : ligaturesNotAllowed }; - - m_CFStringAttributes.adoptCF(CFDictionaryCreate(NULL, attributeKeys, attributeValues, sizeof(attributeKeys) / sizeof(*attributeKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + if (!allowKerning) { + static const float kerningAdjustmentValue = 0; + static CFNumberRef kerningAdjustment = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &kerningAdjustmentValue); + static const void* keysWithKerningDisabled[] = { kCTFontAttributeName, kCTKernAttributeName, kCTLigatureAttributeName }; + const void* valuesWithKerningDisabled[] = { getCTFont(), kerningAdjustment, allowLigatures + ? ligaturesAllowed : ligaturesNotAllowed }; + m_CFStringAttributes.adoptCF(CFDictionaryCreate(NULL, keysWithKerningDisabled, valuesWithKerningDisabled, + sizeof(keysWithKerningDisabled) / sizeof(*keysWithKerningDisabled), + &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + } else { + // By omitting the kCTKernAttributeName attribute, we get Core Text's standard kerning. + static const void* keysWithKerningEnabled[] = { kCTFontAttributeName, kCTLigatureAttributeName }; + const void* valuesWithKerningEnabled[] = { getCTFont(), allowLigatures ? ligaturesAllowed : ligaturesNotAllowed }; + m_CFStringAttributes.adoptCF(CFDictionaryCreate(NULL, keysWithKerningEnabled, valuesWithKerningEnabled, + sizeof(keysWithKerningEnabled) / sizeof(*keysWithKerningEnabled), + &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + } return m_CFStringAttributes.get(); } diff --git a/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp b/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp index 895887f..b2e3d92 100644 --- a/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp +++ b/WebCore/platform/graphics/opentype/OpenTypeUtilities.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Torch Mobile, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -339,7 +340,10 @@ bool getEOTHeader(SharedBuffer* fontData, EOTHeader& eotHeader, size_t& overlayD return true; } -HANDLE renameAndActivateFont(SharedBuffer* fontData, const String& fontName) +// code shared by renameFont and renameAndActivateFont +// adds fontName to the font table in fontData, and writes the new font table to rewrittenFontTable +// returns the size of the name table (which is used by renameAndActivateFont), or 0 on early abort +static size_t renameFontInternal(SharedBuffer* fontData, const String& fontName, Vector<char> &rewrittenFontData) { size_t originalDataSize = fontData->size(); const sfntHeader* sfnt = reinterpret_cast<const sfntHeader*>(fontData->data()); @@ -357,7 +361,7 @@ HANDLE renameAndActivateFont(SharedBuffer* fontData, const String& fontName) // Rounded up to a multiple of 4 to simplify the checksum calculation. size_t nameTableSize = ((offsetof(nameTable, nameRecords) + nameRecordCount * sizeof(nameRecord) + fontName.length() * sizeof(UChar)) & ~3) + 4; - Vector<char> rewrittenFontData(fontData->size() + nameTableSize); + rewrittenFontData.resize(fontData->size() + nameTableSize); char* data = rewrittenFontData.data(); memcpy(data, fontData->data(), originalDataSize); @@ -394,8 +398,42 @@ HANDLE renameAndActivateFont(SharedBuffer* fontData, const String& fontName) for (unsigned i = 0; i * sizeof(BigEndianULong) < nameTableSize; ++i) rewrittenSfnt->tables[t].checkSum = rewrittenSfnt->tables[t].checkSum + reinterpret_cast<BigEndianULong*>(name)[i]; + return nameTableSize; +} + +#if PLATFORM(WINCE) +// AddFontMemResourceEx does not exist on WinCE, so we must handle the font data manually +// This function just renames the font and overwrites the old font data with the new +bool renameFont(SharedBuffer* fontData, const String& fontName) +{ + // abort if the data is too small to be a font header with a "tables" entry + if (fontData->size() < offsetof(sfntHeader, tables)) + return false; + + // abort if the data is too small to hold all the tables specified in the header + const sfntHeader* header = reinterpret_cast<const sfntHeader*>(fontData->data()); + if (fontData->size() < offsetof(sfntHeader, tables) + header->numTables * sizeof(TableDirectoryEntry)) + return false; + + Vector<char> rewrittenFontData; + if (!renameFontInternal(fontData, fontName, rewrittenFontData)) + return false; + + fontData->clear(); + fontData->append(rewrittenFontData.data(), rewrittenFontData.size()); + return true; +} +#else +// Rename the font and install the new font data into the system +HANDLE renameAndActivateFont(SharedBuffer* fontData, const String& fontName) +{ + Vector<char> rewrittenFontData; + size_t nameTableSize = renameFontInternal(fontData, fontName, rewrittenFontData); + if (!nameTableSize) + return 0; + DWORD numFonts = 0; - HANDLE fontHandle = AddFontMemResourceEx(data, originalDataSize + nameTableSize, 0, &numFonts); + HANDLE fontHandle = AddFontMemResourceEx(rewrittenFontData.data(), fontData->size() + nameTableSize, 0, &numFonts); if (fontHandle && numFonts != 1) { RemoveFontMemResourceEx(fontHandle); @@ -404,5 +442,6 @@ HANDLE renameAndActivateFont(SharedBuffer* fontData, const String& fontName) return fontHandle; } +#endif } diff --git a/WebCore/platform/graphics/opentype/OpenTypeUtilities.h b/WebCore/platform/graphics/opentype/OpenTypeUtilities.h index 13dad6f..4c75314 100644 --- a/WebCore/platform/graphics/opentype/OpenTypeUtilities.h +++ b/WebCore/platform/graphics/opentype/OpenTypeUtilities.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Torch Mobile, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,6 +36,10 @@ struct BigEndianUShort; struct EOTPrefix; class SharedBuffer; +#if PLATFORM(WINCE) +typedef unsigned __int8 UInt8; +#endif + struct EOTHeader { EOTHeader(); diff --git a/WebCore/platform/graphics/qt/ColorQt.cpp b/WebCore/platform/graphics/qt/ColorQt.cpp index 5d16740..151766a 100644 --- a/WebCore/platform/graphics/qt/ColorQt.cpp +++ b/WebCore/platform/graphics/qt/ColorQt.cpp @@ -40,7 +40,10 @@ Color::Color(const QColor& c) Color::operator QColor() const { - return QColor(red(), green(), blue(), alpha()); + if (m_valid) + return QColor(red(), green(), blue(), alpha()); + else + return QColor(); } } diff --git a/WebCore/platform/graphics/qt/FontCacheQt.cpp b/WebCore/platform/graphics/qt/FontCacheQt.cpp index 5d29389..1113eae 100644 --- a/WebCore/platform/graphics/qt/FontCacheQt.cpp +++ b/WebCore/platform/graphics/qt/FontCacheQt.cpp @@ -48,7 +48,7 @@ FontCache::FontCache() { } -void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks) +void FontCache::getTraitsInFamily(const AtomicString&, Vector<unsigned>&) { } @@ -58,8 +58,8 @@ class FontPlatformDataCacheKey { public: FontPlatformDataCacheKey(const FontDescription& description) : m_familyName() - , m_bold(false) , m_size(description.computedPixelSize()) + , m_bold(false) , m_italic(description.italic()) , m_smallCaps(description.smallCaps()) , m_hash(0) @@ -177,7 +177,7 @@ typedef HashMap<FontPlatformDataCacheKey, FontPlatformData*, FontPlatformDataCac // using Q_GLOBAL_STATIC leads to crash. TODO investigate the way to fix this. static FontPlatformDataCache* gFontPlatformDataCache = 0; -FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& description, const AtomicString& family, bool checkingAlternateName) +FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& description, const AtomicString&, bool) { if (!gFontPlatformDataCache) gFontPlatformDataCache = new FontPlatformDataCache; diff --git a/WebCore/platform/graphics/qt/FontFallbackListQt.cpp b/WebCore/platform/graphics/qt/FontFallbackListQt.cpp index c29fd56..8e1e4f6 100644 --- a/WebCore/platform/graphics/qt/FontFallbackListQt.cpp +++ b/WebCore/platform/graphics/qt/FontFallbackListQt.cpp @@ -130,7 +130,7 @@ const FontData* FontFallbackList::fontDataForCharacters(const WebCore::Font* fon return primaryFontData(font); } -void FontFallbackList::setPlatformFont(const WebCore::FontPlatformData& platformData) +void FontFallbackList::setPlatformFont(const WebCore::FontPlatformData&) { m_familyIndex = cAllFamiliesScanned; } diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp index e8eb923..c5960ac 100644 --- a/WebCore/platform/graphics/qt/FontQt.cpp +++ b/WebCore/platform/graphics/qt/FontQt.cpp @@ -197,7 +197,7 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon return w + run.padding(); } -int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool includePartialGlyphs) const +int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool) const { const QString string = fixSpacing(qstring(run)); QTextLayout layout(string, font()); diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index e259a4e..fa7b070 100644 --- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -34,29 +34,29 @@ */ #include "config.h" +#include "GraphicsContext.h" #ifdef Q_WS_WIN #include <windows.h> #endif -#include "TransformationMatrix.h" #include "Color.h" #include "FloatConversion.h" #include "Font.h" -#include "GraphicsContext.h" #include "GraphicsContextPrivate.h" #include "ImageBuffer.h" +#include "NotImplemented.h" #include "Path.h" #include "Pattern.h" #include "Pen.h" -#include "NotImplemented.h" +#include "TransformationMatrix.h" #include <QBrush> #include <QDebug> #include <QGradient> -#include <QPainter> #include <QPaintDevice> #include <QPaintEngine> +#include <QPainter> #include <QPainterPath> #include <QPixmap> #include <QPolygonF> @@ -72,35 +72,35 @@ namespace WebCore { static inline QPainter::CompositionMode toQtCompositionMode(CompositeOperator op) { switch (op) { - case CompositeClear: - return QPainter::CompositionMode_Clear; - case CompositeCopy: - return QPainter::CompositionMode_Source; - case CompositeSourceOver: - return QPainter::CompositionMode_SourceOver; - case CompositeSourceIn: - return QPainter::CompositionMode_SourceIn; - case CompositeSourceOut: - return QPainter::CompositionMode_SourceOut; - case CompositeSourceAtop: - return QPainter::CompositionMode_SourceAtop; - case CompositeDestinationOver: - return QPainter::CompositionMode_DestinationOver; - case CompositeDestinationIn: - return QPainter::CompositionMode_DestinationIn; - case CompositeDestinationOut: - return QPainter::CompositionMode_DestinationOut; - case CompositeDestinationAtop: - return QPainter::CompositionMode_DestinationAtop; - case CompositeXOR: - return QPainter::CompositionMode_Xor; - case CompositePlusDarker: - // there is no exact match, but this is the closest - return QPainter::CompositionMode_Darken; - case CompositeHighlight: - return QPainter::CompositionMode_SourceOver; - case CompositePlusLighter: - return QPainter::CompositionMode_Plus; + case CompositeClear: + return QPainter::CompositionMode_Clear; + case CompositeCopy: + return QPainter::CompositionMode_Source; + case CompositeSourceOver: + return QPainter::CompositionMode_SourceOver; + case CompositeSourceIn: + return QPainter::CompositionMode_SourceIn; + case CompositeSourceOut: + return QPainter::CompositionMode_SourceOut; + case CompositeSourceAtop: + return QPainter::CompositionMode_SourceAtop; + case CompositeDestinationOver: + return QPainter::CompositionMode_DestinationOver; + case CompositeDestinationIn: + return QPainter::CompositionMode_DestinationIn; + case CompositeDestinationOut: + return QPainter::CompositionMode_DestinationOut; + case CompositeDestinationAtop: + return QPainter::CompositionMode_DestinationAtop; + case CompositeXOR: + return QPainter::CompositionMode_Xor; + case CompositePlusDarker: + // there is no exact match, but this is the closest + return QPainter::CompositionMode_Darken; + case CompositeHighlight: + return QPainter::CompositionMode_SourceOver; + case CompositePlusLighter: + return QPainter::CompositionMode_Plus; } return QPainter::CompositionMode_SourceOver; @@ -109,12 +109,12 @@ static inline QPainter::CompositionMode toQtCompositionMode(CompositeOperator op static inline Qt::PenCapStyle toQtLineCap(LineCap lc) { switch (lc) { - case ButtCap: - return Qt::FlatCap; - case RoundCap: - return Qt::RoundCap; - case SquareCap: - return Qt::SquareCap; + case ButtCap: + return Qt::FlatCap; + case RoundCap: + return Qt::RoundCap; + case SquareCap: + return Qt::SquareCap; } return Qt::FlatCap; @@ -123,12 +123,12 @@ static inline Qt::PenCapStyle toQtLineCap(LineCap lc) static inline Qt::PenJoinStyle toQtLineJoin(LineJoin lj) { switch (lj) { - case MiterJoin: - return Qt::SvgMiterJoin; - case RoundJoin: - return Qt::RoundJoin; - case BevelJoin: - return Qt::BevelJoin; + case MiterJoin: + return Qt::SvgMiterJoin; + case RoundJoin: + return Qt::RoundJoin; + case BevelJoin: + return Qt::BevelJoin; } return Qt::MiterJoin; @@ -210,8 +210,8 @@ public: return redirect; return painter; - } else - return &layers.top()->painter; + } + return &layers.top()->painter; } bool antiAliasingForRectsAndLines; @@ -411,46 +411,25 @@ void GraphicsContext::drawRect(const IntRect& rect) if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines); + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (getShadow(shadowSize, shadowBlur, shadowColor)) { + IntRect shadowRect = rect; + shadowRect.move(shadowSize.width(), shadowSize.height()); + shadowRect.inflate(static_cast<int>(p->pen().widthF())); + p->fillRect(shadowRect, QColor(shadowColor)); + } + p->drawRect(rect); p->setRenderHint(QPainter::Antialiasing, antiAlias); } -// FIXME: Now that this is refactored, it should be shared by all contexts. -static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, - const StrokeStyle& penStyle) -{ - // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic - // works out. For example, with a border width of 3, KHTML will pass us (y1+y2)/2, e.g., - // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave - // us a perfect position, but an odd width gave us a position that is off by exactly 0.5. - if (penStyle == DottedStroke || penStyle == DashedStroke) { - if (p1.x() == p2.x()) { - p1.setY(p1.y() + strokeWidth); - p2.setY(p2.y() - strokeWidth); - } else { - p1.setX(p1.x() + strokeWidth); - p2.setX(p2.x() - strokeWidth); - } - } - - if (((int) strokeWidth) % 2) { - if (p1.x() == p2.x()) { - // We're a vertical line. Adjust our x. - p1.setX(p1.x() + 0.5); - p2.setX(p2.x() + 0.5); - } else { - // We're a horizontal line. Adjust our y. - p1.setY(p1.y() + 0.5); - p2.setY(p2.y() + 0.5); - } - } -} - // This is only used to draw borders. void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) { @@ -468,7 +447,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) FloatPoint p2 = point2; bool isVerticalLine = (p1.x() == p2.x()); - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines); adjustLineToPixelBoundaries(p1, p2, width, style); @@ -479,22 +458,22 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) if (textDrawingMode() == cTextFill && getShadow(shadowSize, shadowBlur, shadowColor)) { p->save(); p->translate(shadowSize.width(), shadowSize.height()); - p->setPen(QColor(shadowColor)); + p->setPen(shadowColor); p->drawLine(p1, p2); p->restore(); } int patWidth = 0; switch (style) { - case NoStroke: - case SolidStroke: - break; - case DottedStroke: - patWidth = (int)width; - break; - case DashedStroke: - patWidth = 3 * (int)width; - break; + case NoStroke: + case SolidStroke: + break; + case DottedStroke: + patWidth = static_cast<int>(width); + break; + case DashedStroke: + patWidth = 3 * static_cast<int>(width); + break; } if (patWidth) { @@ -523,7 +502,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) if (patWidth == 1) patternOffset = 1.0f; else { - bool evenNumberOfSegments = numSegments % 2 == 0; + bool evenNumberOfSegments = !(numSegments % 2); if (remainder) evenNumberOfSegments = !evenNumberOfSegments; if (evenNumberOfSegments) { @@ -571,11 +550,25 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f || !strokeColor().alpha()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); p->setRenderHint(QPainter::Antialiasing, true); - p->drawArc(rect, startAngle * 16, angleSpan * 16); + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + startAngle *= 16; + angleSpan *= 16; + if (getShadow(shadowSize, shadowBlur, shadowColor)) { + p->save(); + p->translate(shadowSize.width(), shadowSize.height()); + QPen pen(p->pen()); + pen.setColor(shadowColor); + p->setPen(pen); + p->drawArc(rect, startAngle, angleSpan); + p->restore(); + } + p->drawArc(rect, startAngle, angleSpan); p->setRenderHint(QPainter::Antialiasing, antiAlias); } @@ -593,9 +586,25 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points for (size_t i = 0; i < npoints; i++) polygon[i] = points[i]; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); p->save(); p->setRenderHint(QPainter::Antialiasing, shouldAntialias); + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (getShadow(shadowSize, shadowBlur, shadowColor)) { + p->save(); + p->translate(shadowSize.width(), shadowSize.height()); + if (p->brush().style() != Qt::NoBrush) + p->setBrush(QBrush(shadowColor)); + QPen pen(p->pen()); + if (pen.style() != Qt::NoPen) { + pen.setColor(shadowColor); + p->setPen(pen); + } + p->drawConvexPolygon(polygon); + p->restore(); + } p->drawConvexPolygon(polygon); p->restore(); } @@ -605,34 +614,50 @@ QPen GraphicsContext::pen() if (paintingDisabled()) return QPen(); - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); return p->pen(); } +static void inline drawFilledShadowPath(GraphicsContext* context, QPainter* p, const QPainterPath *path) +{ + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (context->getShadow(shadowSize, shadowBlur, shadowColor)) { + p->translate(shadowSize.width(), shadowSize.height()); + p->fillPath(*path, QBrush(shadowColor)); + p->translate(-shadowSize.width(), -shadowSize.height()); + } +} + void GraphicsContext::fillPath() { if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); QPainterPath path = m_data->currentPath; path.setFillRule(toQtFillRule(fillRule())); - switch (m_common->state.fillColorSpace) { - case SolidColorSpace: - if (fillColor().alpha()) - p->fillPath(path, p->brush()); - break; - case PatternColorSpace: { - TransformationMatrix affine; - p->fillPath(path, QBrush(m_common->state.fillPattern->createPlatformPattern(affine))); - break; - } - case GradientColorSpace: - QBrush brush(*m_common->state.fillGradient->platformGradient()); - brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform()); - p->fillPath(path, brush); - break; + if ((m_common->state.fillColorSpace != SolidColorSpace) + || (fillColor().alpha())) { + drawFilledShadowPath(this, p, &path); + switch (m_common->state.fillColorSpace) { + case SolidColorSpace: + if (fillColor().alpha()) + p->fillPath(path, p->brush()); + break; + case PatternColorSpace: { + TransformationMatrix affine; + p->fillPath(path, QBrush(m_common->state.fillPattern->createPlatformPattern(affine))); + break; + } + case GradientColorSpace: + QBrush brush(*m_common->state.fillGradient->platformGradient()); + brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform()); + p->fillPath(path, brush); + break; + } } m_data->currentPath = QPainterPath(); } @@ -642,59 +667,88 @@ void GraphicsContext::strokePath() if (paintingDisabled()) return; - QPainter *p = m_data->p(); - QPen pen = p->pen(); + QPainter* p = m_data->p(); + QPen pen(p->pen()); QPainterPath path = m_data->currentPath; path.setFillRule(toQtFillRule(fillRule())); - switch (m_common->state.strokeColorSpace) { - case SolidColorSpace: - if (strokeColor().alpha()) + if ((m_common->state.strokeColorSpace != SolidColorSpace) + || (strokeColor().alpha())) { + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (getShadow(shadowSize, shadowBlur, shadowColor)) { + QTransform t(p->worldTransform()); + p->translate(shadowSize.width(), shadowSize.height()); + QPen shadowPen(pen); + shadowPen.setColor(shadowColor); + p->strokePath(path, shadowPen); + p->setWorldTransform(t); + } + switch (m_common->state.strokeColorSpace) { + case SolidColorSpace: + if (strokeColor().alpha()) + p->strokePath(path, pen); + break; + case PatternColorSpace: { + TransformationMatrix affine; + pen.setBrush(QBrush(m_common->state.strokePattern->createPlatformPattern(affine))); + p->setPen(pen); p->strokePath(path, pen); - break; - case PatternColorSpace: { - TransformationMatrix affine; - pen.setBrush(QBrush(m_common->state.strokePattern->createPlatformPattern(affine))); - p->setPen(pen); - p->strokePath(path, pen); - break; - } - case GradientColorSpace: { - QBrush brush(*m_common->state.strokeGradient->platformGradient()); - brush.setTransform(m_common->state.strokeGradient->gradientSpaceTransform()); - pen.setBrush(brush); - p->setPen(pen); - p->strokePath(path, pen); - break; - } + break; + } + case GradientColorSpace: { + QBrush brush(*m_common->state.strokeGradient->platformGradient()); + brush.setTransform(m_common->state.strokeGradient->gradientSpaceTransform()); + pen.setBrush(brush); + p->setPen(pen); + p->strokePath(path, pen); + break; + } + } } m_data->currentPath = QPainterPath(); } +static inline void drawBorderlessRectShadow(GraphicsContext* context, QPainter* p, const FloatRect& rect) +{ + IntSize shadowSize; + int shadowBlur; + Color shadowColor; + if (context->getShadow(shadowSize, shadowBlur, shadowColor)) { + FloatRect shadowRect(rect); + shadowRect.move(shadowSize.width(), shadowSize.height()); + p->fillRect(shadowRect, QColor(shadowColor)); + } +} + void GraphicsContext::fillRect(const FloatRect& rect) { if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); - switch (m_common->state.fillColorSpace) { - case SolidColorSpace: - if (fillColor().alpha()) - p->fillRect(rect, p->brush()); - break; - case PatternColorSpace: { - TransformationMatrix affine; - p->fillRect(rect, QBrush(m_common->state.fillPattern->createPlatformPattern(affine))); - break; - } - case GradientColorSpace: - QBrush brush(*m_common->state.fillGradient->platformGradient()); - brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform()); - p->fillRect(rect, brush); - break; + if ((m_common->state.fillColorSpace != SolidColorSpace) + || (fillColor().alpha())) { + drawBorderlessRectShadow(this, p, rect); + switch (m_common->state.fillColorSpace) { + case SolidColorSpace: + if (fillColor().alpha()) + p->fillRect(rect, p->brush()); + break; + case PatternColorSpace: { + TransformationMatrix affine; + p->fillRect(rect, QBrush(m_common->state.fillPattern->createPlatformPattern(affine))); + break; + } + case GradientColorSpace: + QBrush brush(*m_common->state.fillGradient->platformGradient()); + brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform()); + p->fillRect(rect, brush); + break; + } } - m_data->currentPath = QPainterPath(); } void GraphicsContext::fillRect(const FloatRect& rect, const Color& c) @@ -702,8 +756,10 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& c) if (paintingDisabled()) return; - m_data->solidColor.setColor(QColor(c)); - m_data->p()->fillRect(rect, m_data->solidColor); + m_data->solidColor.setColor(c); + QPainter* p = m_data->p(); + drawBorderlessRectShadow(this, p, rect); + p->fillRect(rect, m_data->solidColor); } void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) @@ -712,7 +768,9 @@ void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLef return; Path path = Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight); - m_data->p()->fillPath(*path.platformPath(), QColor(color)); + QPainter* p = m_data->p(); + drawFilledShadowPath(this, p, path.platformPath()); + p->fillPath(*path.platformPath(), QColor(color)); } void GraphicsContext::beginPath() @@ -750,7 +808,7 @@ void GraphicsContext::clipPath(WindRule clipRule) if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); QPainterPath newPath = m_data->currentPath; newPath.setFillRule(clipRule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill); p->setClipPath(newPath); @@ -769,10 +827,10 @@ void GraphicsContext::drawFocusRing(const Color& color) const Vector<IntRect>& rects = focusRingRects(); unsigned rectCount = rects.size(); - if (rects.size() == 0) + if (!rects.size()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines); @@ -793,7 +851,7 @@ void GraphicsContext::drawFocusRing(const Color& color) QPainterPath newPath = stroker.createStroke(path); p->strokePath(newPath, nPen); #else - for (int i = 0; i < rectCount; ++i) + for (unsigned i = 0; i < rectCount; ++i) p->drawRect(QRectF(rects[i])); #endif p->setPen(oldPen); @@ -802,7 +860,7 @@ void GraphicsContext::drawFocusRing(const Color& color) p->setRenderHint(QPainter::Antialiasing, antiAlias); } -void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool printing) +void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool) { if (paintingDisabled()) return; @@ -811,8 +869,7 @@ void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool pr drawLine(origin, endPoint); } -void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, - int width, bool grammar) +void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, int, bool) { if (paintingDisabled()) return; @@ -829,10 +886,16 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect) return FloatRect(QRectF(result)); } -void GraphicsContext::setPlatformShadow(const IntSize& pos, int blur, const Color &color) +void GraphicsContext::setPlatformShadow(const IntSize& size, int, const Color&) { // Qt doesn't support shadows natively, they are drawn manually in the draw* // functions + + if (m_common->state.shadowsIgnoreTransforms) { + // Meaning that this graphics context is associated with a CanvasRenderingContext + // We flip the height since CG and HTML5 Canvas have opposite Y axis + m_common->state.shadowSize = IntSize(size.width(), -size.height()); + } } void GraphicsContext::clearPlatformShadow() @@ -848,8 +911,8 @@ void GraphicsContext::beginTransparencyLayer(float opacity) int x, y, w, h; x = y = 0; - QPainter *p = m_data->p(); - const QPaintDevice *device = p->device(); + QPainter* p = m_data->p(); + const QPaintDevice* device = p->device(); w = device->width(); h = device->height(); @@ -871,10 +934,10 @@ void GraphicsContext::endTransparencyLayer() if (paintingDisabled()) return; - TransparencyLayer *layer = m_data->layers.pop(); + TransparencyLayer* layer = m_data->layers.pop(); layer->painter.end(); - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); p->save(); p->resetTransform(); p->setOpacity(layer->opacity); @@ -889,7 +952,7 @@ void GraphicsContext::clearRect(const FloatRect& rect) if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); QPainter::CompositionMode currentCompositionMode = p->compositionMode(); if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff)) p->setCompositionMode(QPainter::CompositionMode_Source); @@ -916,7 +979,7 @@ void GraphicsContext::setLineCap(LineCap lc) if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); QPen nPen = p->pen(); nPen.setCapStyle(toQtLineCap(lc)); p->setPen(nPen); @@ -948,7 +1011,7 @@ void GraphicsContext::setLineJoin(LineJoin lj) if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); QPen nPen = p->pen(); nPen.setJoinStyle(toQtLineJoin(lj)); p->setPen(nPen); @@ -959,7 +1022,7 @@ void GraphicsContext::setMiterLimit(float limit) if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); QPen nPen = p->pen(); nPen.setMiterLimit(limit); p->setPen(nPen); @@ -969,7 +1032,7 @@ void GraphicsContext::setAlpha(float opacity) { if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); p->setOpacity(opacity); } @@ -995,15 +1058,19 @@ void GraphicsContext::clipOut(const Path& path) if (paintingDisabled()) return; - QPainter *p = m_data->p(); - QRectF clipBounds = p->clipPath().boundingRect(); + QPainter* p = m_data->p(); QPainterPath clippedOut = *path.platformPath(); QPainterPath newClip; newClip.setFillRule(Qt::OddEvenFill); - newClip.addRect(clipBounds); - newClip.addPath(clippedOut); - - p->setClipPath(newClip, Qt::IntersectClip); + if (p->hasClipping()) { + newClip.addRect(p->clipPath().boundingRect()); + newClip.addPath(clippedOut); + p->setClipPath(newClip, Qt::IntersectClip); + } else { + newClip.addRect(p->window()); + newClip.addPath(clippedOut & newClip); + p->setClipPath(newClip); + } } void GraphicsContext::translate(float x, float y) @@ -1061,14 +1128,21 @@ void GraphicsContext::clipOut(const IntRect& rect) if (paintingDisabled()) return; - QPainter *p = m_data->p(); - QRectF clipBounds = p->clipPath().boundingRect(); + QPainter* p = m_data->p(); QPainterPath newClip; newClip.setFillRule(Qt::OddEvenFill); - newClip.addRect(clipBounds); - newClip.addRect(QRect(rect)); - - p->setClipPath(newClip, Qt::IntersectClip); + if (p->hasClipping()) { + newClip.addRect(p->clipPath().boundingRect()); + newClip.addRect(QRect(rect)); + p->setClipPath(newClip, Qt::IntersectClip); + } else { + QRect clipOutRect(rect); + QRect window(p->window()); + clipOutRect &= window; + newClip.addRect(window); + newClip.addRect(clipOutRect); + p->setClipPath(newClip); + } } void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) @@ -1076,14 +1150,21 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) if (paintingDisabled()) return; - QPainter *p = m_data->p(); - QRectF clipBounds = p->clipPath().boundingRect(); + QPainter* p = m_data->p(); QPainterPath newClip; newClip.setFillRule(Qt::OddEvenFill); - newClip.addRect(clipBounds); - newClip.addEllipse(QRect(rect)); - - p->setClipPath(newClip, Qt::IntersectClip); + if (p->hasClipping()) { + newClip.addRect(p->clipPath().boundingRect()); + newClip.addEllipse(QRect(rect)); + p->setClipPath(newClip, Qt::IntersectClip); + } else { + QRect clipOutRect(rect); + QRect window(p->window()); + clipOutRect &= window; + newClip.addRect(window); + newClip.addEllipse(clipOutRect); + p->setClipPath(newClip); + } } void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*) @@ -1109,7 +1190,7 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, path.setFillRule(Qt::OddEvenFill); - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); const bool antiAlias = p->testRenderHint(QPainter::Antialiasing); p->setRenderHint(QPainter::Antialiasing, true); @@ -1134,7 +1215,7 @@ void GraphicsContext::concatCTM(const TransformationMatrix& transform) } } -void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) +void GraphicsContext::setURLForRect(const KURL&, const IntRect&) { notImplemented(); } @@ -1143,7 +1224,7 @@ void GraphicsContext::setPlatformStrokeColor(const Color& color) { if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); QPen newPen(p->pen()); newPen.setColor(color); p->setPen(newPen); @@ -1153,7 +1234,7 @@ void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& strokeStyle) { if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); QPen newPen(p->pen()); newPen.setStyle(toQPenStyle(strokeStyle)); p->setPen(newPen); @@ -1163,7 +1244,7 @@ void GraphicsContext::setPlatformStrokeThickness(float thickness) { if (paintingDisabled()) return; - QPainter *p = m_data->p(); + QPainter* p = m_data->p(); QPen newPen(p->pen()); newPen.setWidthF(thickness); p->setPen(newPen); @@ -1184,7 +1265,6 @@ void GraphicsContext::setPlatformShouldAntialias(bool enable) } #ifdef Q_WS_WIN -#include <windows.h> HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) { diff --git a/WebCore/platform/graphics/qt/IconQt.cpp b/WebCore/platform/graphics/qt/IconQt.cpp index 34c3c47..98f4606 100644 --- a/WebCore/platform/graphics/qt/IconQt.cpp +++ b/WebCore/platform/graphics/qt/IconQt.cpp @@ -47,7 +47,7 @@ PassRefPtr<Icon> Icon::createIconForFile(const String& filename) return i.release(); } -PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&) { //FIXME: Implement this return 0; diff --git a/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/WebCore/platform/graphics/qt/ImageBufferQt.cpp index 22a5a43..5255428 100644 --- a/WebCore/platform/graphics/qt/ImageBufferQt.cpp +++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp @@ -68,7 +68,7 @@ ImageBufferData::ImageBufferData(const IntSize& size) painter->setCompositionMode(QPainter::CompositionMode_SourceOver); } -ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, bool& success) +ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace, bool& success) : m_data(size) , m_size(size) { @@ -125,12 +125,13 @@ void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) m_data.m_painter->begin(&m_data.m_pixmap); } -PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const +template <Multiply multiplied> +PassRefPtr<ImageData> getImageData(const IntRect& rect, const ImageBufferData& imageData, const IntSize& size) { PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height()); unsigned char* data = result->data()->data()->data(); - if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > m_size.width() || (rect.y() + rect.height()) > m_size.height()) + if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > size.width() || (rect.y() + rect.height()) > size.height()) memset(data, 0, result->data()->length()); int originx = rect.x(); @@ -140,8 +141,8 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const originx = 0; } int endx = rect.x() + rect.width(); - if (endx > m_size.width()) - endx = m_size.width(); + if (endx > size.width()) + endx = size.width(); int numColumns = endx - originx; int originy = rect.y(); @@ -151,11 +152,16 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const originy = 0; } int endy = rect.y() + rect.height(); - if (endy > m_size.height()) - endy = m_size.height(); + if (endy > size.height()) + endy = size.height(); int numRows = endy - originy; - QImage image = m_data.m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32); + QImage image = imageData.m_pixmap.toImage(); + if (multiplied == Unmultiplied) + image = image.convertToFormat(QImage::Format_ARGB32); + else + image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); + ASSERT(!image.isNull()); unsigned destBytesPerRow = 4 * rect.width(); @@ -176,7 +182,18 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const return result; } -void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const +{ + return getImageData<Unmultiplied>(rect, m_data, m_size); +} + +PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const +{ + return getImageData<Premultiplied>(rect, m_data, m_size); +} + +template <Multiply multiplied> +void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& data, const IntSize& size) { ASSERT(sourceRect.width() > 0); ASSERT(sourceRect.height() > 0); @@ -184,49 +201,65 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, con int originx = sourceRect.x(); int destx = destPoint.x() + sourceRect.x(); ASSERT(destx >= 0); - ASSERT(destx < m_size.width()); + ASSERT(destx < size.width()); ASSERT(originx >= 0); ASSERT(originx <= sourceRect.right()); int endx = destPoint.x() + sourceRect.right(); - ASSERT(endx <= m_size.width()); + ASSERT(endx <= size.width()); int numColumns = endx - destx; int originy = sourceRect.y(); int desty = destPoint.y() + sourceRect.y(); ASSERT(desty >= 0); - ASSERT(desty < m_size.height()); + ASSERT(desty < size.height()); ASSERT(originy >= 0); ASSERT(originy <= sourceRect.bottom()); int endy = destPoint.y() + sourceRect.bottom(); - ASSERT(endy <= m_size.height()); + ASSERT(endy <= size.height()); int numRows = endy - desty; unsigned srcBytesPerRow = 4 * source->width(); - bool isPainting = m_data.m_painter->isActive(); + bool isPainting = data.m_painter->isActive(); if (isPainting) - m_data.m_painter->end(); + data.m_painter->end(); - QImage image = m_data.m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32); + QImage image = data.m_pixmap.toImage(); + if (multiplied == Unmultiplied) + image = image.convertToFormat(QImage::Format_ARGB32); + else + image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4; for (int y = 0; y < numRows; ++y) { quint32* scanLine = reinterpret_cast<quint32*>(image.scanLine(y + desty)); for (int x = 0; x < numColumns; x++) { - int basex = x * 4; - scanLine[x + destx] = reinterpret_cast<quint32*>(srcRows + basex)[0]; + // ImageData stores the pixels in RGBA while QImage is ARGB + quint32 pixel = reinterpret_cast<quint32*>(srcRows + 4 * x)[0]; + pixel = ((pixel << 16) & 0xff0000) | ((pixel >> 16) & 0xff) | (pixel & 0xff00ff00); + scanLine[x + destx] = pixel; } srcRows += srcBytesPerRow; } - m_data.m_pixmap = QPixmap::fromImage(image); + data.m_pixmap = QPixmap::fromImage(image); if (isPainting) - m_data.m_painter->begin(&m_data.m_pixmap); + data.m_painter->begin(&data.m_pixmap); +} + +void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<Unmultiplied>(source, sourceRect, destPoint, m_data, m_size); +} + +void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<Premultiplied>(source, sourceRect, destPoint, m_data, m_size); } // We get a mimeType here but QImageWriter does not support mimetypes but diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp index 7bbdcc0..3a27fe3 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp @@ -35,150 +35,9 @@ #include <QtGui/QImageReader> #include <qdebug.h> -namespace { - const QImage::Format DesiredFormat = QImage::Format_ARGB32; - const bool debugImageDecoderQt = false; -} - namespace WebCore { -ImageDecoderQt::ImageData::ImageData(const QImage& image, ImageState imageState, int duration) : - m_image(image), m_imageState(imageState), m_duration(duration) -{ -} - -// Context, maintains IODevice on a data buffer. -class ImageDecoderQt::ReadContext { -public: - - enum LoadMode { - // Load images incrementally. This is still experimental and - // will cause the image plugins to report errors. - // Also note that as of Qt 4.2.2, the JPEG loader does not return error codes - // on "preliminary end of data". - LoadIncrementally, - // Load images only if all data have been received - LoadComplete }; - - ReadContext(const IncomingData & data, LoadMode loadMode, ImageList &target); - - enum ReadResult { ReadEOF, ReadFailed, ReadPartial, ReadComplete }; - - // Append data and read out all images. Returns the result - // of the last read operation, so, even if ReadPartial is returned, - // a few images might have been read. - ReadResult read(bool allDataReceived); - - QImageReader *reader() { return &m_reader; } -private: - enum IncrementalReadResult { IncrementalReadFailed, IncrementalReadPartial, IncrementalReadComplete }; - // Incrementally read an image - IncrementalReadResult readImageLines(ImageData &); - - const LoadMode m_loadMode; - - QByteArray m_data; - QBuffer m_buffer; - QImageReader m_reader; - - ImageList &m_target; - - // Detected data format of the stream - enum QImage::Format m_dataFormat; - QSize m_size; - -}; - -ImageDecoderQt::ReadContext::ReadContext(const IncomingData & data, LoadMode loadMode, ImageList &target) - : m_loadMode(loadMode) - , m_data(data.data(), data.size()) - , m_buffer(&m_data) - , m_reader(&m_buffer) - , m_target(target) - , m_dataFormat(QImage::Format_Invalid) -{ - m_buffer.open(QIODevice::ReadOnly); -} - - -ImageDecoderQt::ReadContext::ReadResult - ImageDecoderQt::ReadContext::read(bool allDataReceived) -{ - // Complete mode: Read only all all data received - if (m_loadMode == LoadComplete && !allDataReceived) - return ReadPartial; - - // Attempt to read out all images - while (true) { - if (m_target.empty() || m_target.back().m_imageState == ImageComplete) { - // Start a new image. - if (!m_reader.canRead()) - return ReadEOF; - - // Attempt to construct an empty image of the matching size and format - // for efficient reading - QImage newImage = m_dataFormat != QImage::Format_Invalid ? - QImage(m_size, m_dataFormat) : QImage(); - m_target.push_back(ImageData(newImage)); - } - - // read chunks - switch (readImageLines(m_target.back())) { - case IncrementalReadFailed: - m_target.pop_back(); - return ReadFailed; - case IncrementalReadPartial: - return ReadPartial; - case IncrementalReadComplete: - m_target.back().m_imageState = ImageComplete; - //store for next - m_dataFormat = m_target.back().m_image.format(); - m_size = m_target.back().m_image.size(); - const bool supportsAnimation = m_reader.supportsAnimation(); - - if (debugImageDecoderQt) - qDebug() << "readImage(): #" << m_target.size() << " complete, " << m_size - << " format " << m_dataFormat << " supportsAnimation=" << supportsAnimation; - // No point in readinfg further - if (!supportsAnimation) - return ReadComplete; - - break; - } - } - return ReadComplete; -} - - - -ImageDecoderQt::ReadContext::IncrementalReadResult - ImageDecoderQt::ReadContext::readImageLines(ImageData &imageData) -{ - // TODO: Implement incremental reading here, - // set state to reflect complete header, etc. - // For now, we read the whole image. - - const qint64 startPos = m_buffer.pos(); - // Oops, failed. Rewind. - if (!m_reader.read(&imageData.m_image)) { - m_buffer.seek(startPos); - const bool gotHeader = imageData.m_image.size().width(); - - if (debugImageDecoderQt) - qDebug() << "readImageLines(): read() failed: " << m_reader.errorString() - << " got header=" << gotHeader; - // [Experimental] Did we manage to read the header? - if (gotHeader) { - imageData.m_imageState = ImageHeaderValid; - return IncrementalReadPartial; - } - return IncrementalReadFailed; - } - imageData.m_duration = m_reader.nextImageDelay(); - return IncrementalReadComplete; -} - -ImageDecoderQt* ImageDecoderQt::create(const SharedBuffer& data) +ImageDecoder* ImageDecoder::create(const SharedBuffer& data) { // We need at least 4 bytes to figure out what kind of image we're dealing with. if (data.size() < 4) @@ -189,149 +48,196 @@ ImageDecoderQt* ImageDecoderQt::create(const SharedBuffer& data) if (!buffer.open(QBuffer::ReadOnly)) return 0; - QString imageFormat = QString::fromLatin1(QImageReader::imageFormat(&buffer).toLower()); + QByteArray imageFormat = QImageReader::imageFormat(&buffer); if (imageFormat.isEmpty()) return 0; // Image format not supported return new ImageDecoderQt(imageFormat); } -ImageDecoderQt::ImageDecoderQt(const QString &imageFormat) - : m_hasAlphaChannel(false) - , m_imageFormat(imageFormat) +ImageDecoderQt::ImageDecoderQt(const QByteArray& imageFormat) + : m_buffer(0) + , m_reader(0) + , m_repetitionCount(-1) { } ImageDecoderQt::~ImageDecoderQt() { + delete m_reader; + delete m_buffer; } -bool ImageDecoderQt::hasFirstImageHeader() const +void ImageDecoderQt::setData(SharedBuffer* data, bool allDataReceived) { - return !m_imageList.empty() && m_imageList[0].m_imageState >= ImageHeaderValid; -} + if (m_failed) + return; -void ImageDecoderQt::reset() -{ - m_hasAlphaChannel = false; - m_failed = false; - m_imageList.clear(); - m_pixmapCache.clear(); - m_loopCount = cAnimationNone; -} + // Cache our own new data. + ImageDecoder::setData(data, allDataReceived); -void ImageDecoderQt::setData(const IncomingData &data, bool allDataReceived) -{ - reset(); - ReadContext readContext(data, ReadContext::LoadComplete, m_imageList); - - if (debugImageDecoderQt) - qDebug() << " setData " << data.size() << " image bytes, complete=" << allDataReceived; - - const ReadContext::ReadResult readResult = readContext.read(allDataReceived); - - if (hasFirstImageHeader()) - m_hasAlphaChannel = m_imageList[0].m_image.hasAlphaChannel(); - - if (debugImageDecoderQt) - qDebug() << " read returns " << readResult; - - switch (readResult) { - case ReadContext::ReadFailed: - m_failed = true; - break; - case ReadContext::ReadEOF: - case ReadContext::ReadPartial: - case ReadContext::ReadComplete: - // Did we read anything - try to set the size. - if (hasFirstImageHeader()) { - QSize imgSize = m_imageList[0].m_image.size(); - setSize(imgSize.width(), imgSize.height()); - - if (readContext.reader()->supportsAnimation()) { - if (readContext.reader()->loopCount() != -1) - m_loopCount = readContext.reader()->loopCount(); - else - m_loopCount = 0; //loop forever - } - } - break; - } -} + // No progressive loading possible + if (!allDataReceived) + return; + + // We expect to be only called once with allDataReceived + ASSERT(!m_buffer); + ASSERT(!m_reader); + // Attempt to load the data + QByteArray imageData = QByteArray::fromRawData(m_data->data(), m_data->size()); + m_buffer = new QBuffer; + m_buffer->setData(imageData); + m_buffer->open(QBuffer::ReadOnly); + m_reader = new QImageReader(m_buffer); + + if (!m_reader->canRead()) + failRead(); +} bool ImageDecoderQt::isSizeAvailable() { - if (debugImageDecoderQt) - qDebug() << " ImageDecoderQt::isSizeAvailable() returns" << ImageDecoder::isSizeAvailable(); + if (!m_failed && !ImageDecoder::isSizeAvailable() && m_reader) + internalDecodeSize(); + return ImageDecoder::isSizeAvailable(); } -size_t ImageDecoderQt::frameCount() const +size_t ImageDecoderQt::frameCount() { - if (debugImageDecoderQt) - qDebug() << " ImageDecoderQt::frameCount() returns" << m_imageList.size(); - return m_imageList.size(); + if (m_frameBufferCache.isEmpty() && m_reader) { + if (m_reader->supportsAnimation()) { + int imageCount = m_reader->imageCount(); + + // Fixup for Qt decoders... imageCount() is wrong + // and jumpToNextImage does not work either... so + // we will have to parse everything... + if (imageCount == 0) + forceLoadEverything(); + else + m_frameBufferCache.resize(imageCount); + } else { + m_frameBufferCache.resize(1); + } + } + + return m_frameBufferCache.size(); } int ImageDecoderQt::repetitionCount() const { - if (debugImageDecoderQt) - qDebug() << " ImageDecoderQt::repetitionCount() returns" << m_loopCount; - return m_loopCount; + if (m_reader && m_reader->supportsAnimation()) + m_repetitionCount = qMax(0, m_reader->loopCount()); + + return m_repetitionCount; } -bool ImageDecoderQt::supportsAlpha() const +String ImageDecoderQt::filenameExtension() const { - return m_hasAlphaChannel; -} + return m_format; +}; -int ImageDecoderQt::duration(size_t index) const +RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index) { - if (index >= m_imageList.size()) + // this information might not have been set + int count = m_frameBufferCache.size(); + if (count == 0) { + internalDecodeSize(); + count = frameCount(); + } + + if (index >= static_cast<size_t>(count)) return 0; - return m_imageList[index].m_duration; + + RGBA32Buffer& frame = m_frameBufferCache[index]; + if (frame.status() != RGBA32Buffer::FrameComplete && m_reader) + internalReadImage(index); + return &frame; } -String ImageDecoderQt::filenameExtension() const +void ImageDecoderQt::clearFrameBufferCache(size_t index) { - if (debugImageDecoderQt) - qDebug() << " ImageDecoderQt::filenameExtension() returns" << m_imageFormat; - return m_imageFormat; -}; + // Currently QImageReader will be asked to read everything. This + // might change when we read gif images on demand. For now we + // can have a rather simple implementation. + if (index > m_frameBufferCache.size()) + return; -RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index) + for (size_t i = 0; i < index; ++index) + m_frameBufferCache[index].clear(); +} + +void ImageDecoderQt::internalDecodeSize() { - Q_ASSERT("use imageAtIndex instead"); - return 0; + ASSERT(m_reader); + + QSize size = m_reader->size(); + setSize(size.width(), size.height()); } -QPixmap* ImageDecoderQt::imageAtIndex(size_t index) const +void ImageDecoderQt::internalReadImage(size_t frameIndex) { - if (debugImageDecoderQt) - qDebug() << "ImageDecoderQt::imageAtIndex(" << index << ')'; + ASSERT(m_reader); - if (index >= m_imageList.size()) - return 0; + if (m_reader->supportsAnimation()) + m_reader->jumpToImage(frameIndex); + else if (frameIndex != 0) + return failRead(); - if (!m_pixmapCache.contains(index)) { - m_pixmapCache.insert(index, - QPixmap::fromImage(m_imageList[index].m_image)); + internalHandleCurrentImage(frameIndex); - // store null image since the converted pixmap is already in pixmap cache - Q_ASSERT(m_imageList[index].m_imageState == ImageComplete); - m_imageList[index].m_image = QImage(); - } - return &m_pixmapCache[index]; + // Attempt to return some memory + for (int i = 0; i < m_frameBufferCache.size(); ++i) + if (m_frameBufferCache[i].status() != RGBA32Buffer::FrameComplete) + return; + + delete m_reader; + delete m_buffer; + m_buffer = 0; + m_reader = 0; } -void ImageDecoderQt::clearFrame(size_t index) +void ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex) { - if (m_imageList.size() < (int)index) - m_imageList[index].m_image = QImage(); - m_pixmapCache.take(index); + // Now get the QImage from Qt and place it in the RGBA32Buffer + QImage img; + if (!m_reader->read(&img)) + return failRead(); + + // now into the RGBA32Buffer - even if the image is not + QSize imageSize = img.size(); + RGBA32Buffer* const buffer = &m_frameBufferCache[frameIndex]; + buffer->setRect(m_reader->currentImageRect()); + buffer->setStatus(RGBA32Buffer::FrameComplete); + buffer->setDuration(m_reader->nextImageDelay()); + buffer->setDecodedImage(img); } +// We will parse everything and we have no idea how +// many images we have... We will have to find out the +// hard way. +void ImageDecoderQt::forceLoadEverything() +{ + int imageCount = 0; + + do { + m_frameBufferCache.resize(++imageCount); + internalHandleCurrentImage(imageCount - 1); + } while(!m_failed); + + // reset the failed state and resize the vector... + m_frameBufferCache.resize(imageCount - 1); + m_failed = false; +} + +void ImageDecoderQt::failRead() +{ + setFailed(); + delete m_reader; + delete m_buffer; + m_reader = 0; + m_buffer = 0; +} } // vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.h b/WebCore/platform/graphics/qt/ImageDecoderQt.h index fc52479..7b3b686 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.h +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.h @@ -28,10 +28,11 @@ #define ImageDecoderQt_h #include "ImageDecoder.h" -#include <QtGui/QImage> +#include <QtGui/QImageReader> #include <QtGui/QPixmap> #include <QtCore/QList> #include <QtCore/QHash> +#include <QtCore/QBuffer> namespace WebCore { @@ -39,54 +40,35 @@ namespace WebCore { class ImageDecoderQt : public ImageDecoder { public: - static ImageDecoderQt* create(const SharedBuffer& data); + ImageDecoderQt(const QByteArray& imageFormat); ~ImageDecoderQt(); - typedef Vector<char> IncomingData; - - virtual void setData(const IncomingData& data, bool allDataReceived); + virtual void setData(SharedBuffer* data, bool allDataReceived); virtual bool isSizeAvailable(); - virtual size_t frameCount() const; + virtual size_t frameCount(); virtual int repetitionCount() const; virtual RGBA32Buffer* frameBufferAtIndex(size_t index); - QPixmap* imageAtIndex(size_t index) const; - virtual bool supportsAlpha() const; - int duration(size_t index) const; virtual String filenameExtension() const; - void clearFrame(size_t index); + virtual void clearFrameBufferCache(size_t clearBeforeFrame); private: - ImageDecoderQt(const QString &imageFormat); ImageDecoderQt(const ImageDecoderQt&); ImageDecoderQt &operator=(const ImageDecoderQt&); - class ReadContext; - void reset(); - bool hasFirstImageHeader() const; - - enum ImageState { - // Started image reading - ImagePartial, - // Header (size / alpha) are known - ImageHeaderValid, - // Image is complete - ImageComplete }; - - struct ImageData { - ImageData(const QImage& image, ImageState imageState = ImagePartial, int duration=0); - QImage m_image; - ImageState m_imageState; - int m_duration; - }; - - bool m_hasAlphaChannel; - typedef QList<ImageData> ImageList; - mutable ImageList m_imageList; - mutable QHash<int, QPixmap> m_pixmapCache; - int m_loopCount; - QString m_imageFormat; +private: + void internalDecodeSize(); + void internalReadImage(size_t); + void internalHandleCurrentImage(size_t); + void forceLoadEverything(); + void failRead(); + +private: + String m_format; + QBuffer* m_buffer; + QImageReader* m_reader; + mutable int m_repetitionCount; }; diff --git a/WebCore/platform/graphics/qt/ImageQt.cpp b/WebCore/platform/graphics/qt/ImageQt.cpp index 5d40e26..da6ddac 100644 --- a/WebCore/platform/graphics/qt/ImageQt.cpp +++ b/WebCore/platform/graphics/qt/ImageQt.cpp @@ -76,6 +76,7 @@ bool FrameData::clear(bool clearMetadata) m_haveMetadata = false; if (m_frame) { + delete m_frame; m_frame = 0; return true; } diff --git a/WebCore/platform/graphics/qt/ImageSourceQt.cpp b/WebCore/platform/graphics/qt/ImageSourceQt.cpp deleted file mode 100644 index 8ae449c..0000000 --- a/WebCore/platform/graphics/qt/ImageSourceQt.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. - * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) - * - * 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 "ImageSource.h" -#include "ImageDecoderQt.h" -#include "SharedBuffer.h" - -#include <QBuffer> -#include <QImage> -#include <QImageReader> - -namespace WebCore { - -ImageSource::ImageSource() - : m_decoder(0) -{ -} - -ImageSource::~ImageSource() -{ - clear(true); -} - -bool ImageSource::initialized() const -{ - return m_decoder; -} - -void ImageSource::setData(SharedBuffer* data, bool allDataReceived) -{ - // Make the decoder by sniffing the bytes. - // This method will examine the data and instantiate an instance of the appropriate decoder plugin. - // If insufficient bytes are available to determine the image type, no decoder plugin will be - // made. - if (!m_decoder) - m_decoder = ImageDecoderQt::create(*data); - - if (!m_decoder) - return; - - m_decoder->setData(data->buffer(), allDataReceived); -} - -String ImageSource::filenameExtension() const -{ - if (!m_decoder) - return String(); - - return m_decoder->filenameExtension(); -} - -bool ImageSource::isSizeAvailable() -{ - if (!m_decoder) - return false; - - return m_decoder->isSizeAvailable(); -} - -IntSize ImageSource::size() const -{ - if (!m_decoder) - return IntSize(); - - return m_decoder->size(); -} - -IntSize ImageSource::frameSizeAtIndex(size_t index) const -{ - if (!m_decoder) - return IntSize(); - - return m_decoder->frameSizeAtIndex(index); -} - -int ImageSource::repetitionCount() -{ - if (!m_decoder) - return cAnimationNone; - - return m_decoder->repetitionCount(); -} - -size_t ImageSource::frameCount() const -{ - if (!m_decoder) - return 0; - - return m_decoder->frameCount(); -} - -NativeImagePtr ImageSource::createFrameAtIndex(size_t index) -{ - if (!m_decoder) - return 0; - - return m_decoder->imageAtIndex(index); -} - -float ImageSource::frameDurationAtIndex(size_t index) -{ - if (!m_decoder) - return 0; - - // Many annoying ads specify a 0 duration to make an image flash as quickly - // as possible. We follow WinIE's behavior and use a duration of 100 ms - // for any frames that specify a duration of <= 50 ms. See - // <http://bugs.webkit.org/show_bug.cgi?id=14413> or Radar 4051389 for - // more. - const float duration = m_decoder->duration(index) / 1000.0f; - return (duration < 0.051f) ? 0.100f : duration; -} - -bool ImageSource::frameHasAlphaAtIndex(size_t index) -{ - if (!m_decoder || !m_decoder->supportsAlpha()) - return false; - - const QPixmap* source = m_decoder->imageAtIndex(index); - if (!source) - return false; - - return source->hasAlphaChannel(); -} - -bool ImageSource::frameIsCompleteAtIndex(size_t index) -{ - return (m_decoder && m_decoder->imageAtIndex(index)); -} - -void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived) -{ - if (!destroyAll) { - if (m_decoder) - m_decoder->clearFrameBufferCache(clearBeforeFrame); - return; - } - - delete m_decoder; - m_decoder = 0; - if (data) - setData(data, allDataReceived); -} - -} - -// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp index 76b1494..7078d16 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp @@ -27,6 +27,7 @@ #include "FrameView.h" #include "GraphicsContext.h" #include "NotImplemented.h" +#include "TimeRanges.h" #include "Widget.h" #include <wtf/HashSet.h> @@ -37,9 +38,9 @@ #include <QUrl> #include <QEvent> -#include <Phonon/AudioOutput> -#include <Phonon/MediaObject> -#include <Phonon/VideoWidget> +#include <audiooutput.h> +#include <mediaobject.h> +#include <videowidget.h> using namespace Phonon; @@ -146,7 +147,7 @@ void MediaPlayerPrivate::getSupportedTypes(HashSet<String>&) notImplemented(); } -MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs) +MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String&, const String&) { // FIXME: do the real thing notImplemented(); @@ -160,6 +161,14 @@ bool MediaPlayerPrivate::hasVideo() const return hasVideo; } +bool MediaPlayerPrivate::hasAudio() const +{ + // FIXME: Phonon::MediaObject does not have such a hasAudio() function + bool hasAudio = true; + LOG(Media, "MediaPlayerPrivatePhonon::hasAudio() -> %s", hasAudio ? "true" : "false"); + return hasAudio; +} + void MediaPlayerPrivate::load(const String& url) { LOG(Media, "MediaPlayerPrivatePhonon::load(\"%s\")", url.utf8().data()); @@ -247,15 +256,15 @@ float MediaPlayerPrivate::currentTime() const return currentTime; } -void MediaPlayerPrivate::setEndTime(float endTime) +void MediaPlayerPrivate::setEndTime(float) { notImplemented(); } -float MediaPlayerPrivate::maxTimeBuffered() const +PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const { notImplemented(); - return 0.0f; + return TimeRanges::create(); } float MediaPlayerPrivate::maxTimeSeekable() const diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h index 9572d61..e1193b6 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h @@ -80,6 +80,7 @@ namespace WebCore { IntSize naturalSize() const; bool hasVideo() const; + bool hasAudio() const; void load(const String &url); void cancelLoad(); @@ -104,7 +105,7 @@ namespace WebCore { MediaPlayer::NetworkState networkState() const; MediaPlayer::ReadyState readyState() const; - float maxTimeBuffered() const; + PassRefPtr<TimeRanges> buffered() const; float maxTimeSeekable() const; unsigned bytesLoaded() const; bool totalBytesKnown() const; diff --git a/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp index f823f84..f093d7d 100644 --- a/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp +++ b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp @@ -33,7 +33,7 @@ void SimpleFontData::determinePitch() m_treatAsFixedPitch = m_platformData.font().fixedPitch(); } -bool SimpleFontData::containsCharacters(const UChar*, int length) const +bool SimpleFontData::containsCharacters(const UChar*, int) const { return true; } diff --git a/WebCore/platform/graphics/qt/StillImageQt.h b/WebCore/platform/graphics/qt/StillImageQt.h index 2b2c1f7..6c417b1 100644 --- a/WebCore/platform/graphics/qt/StillImageQt.h +++ b/WebCore/platform/graphics/qt/StillImageQt.h @@ -41,7 +41,7 @@ namespace WebCore { // FIXME: StillImages are underreporting decoded sizes and will be unable // to prune because these functions are not implemented yet. - virtual void destroyDecodedData(bool destroyAll = true) { } + virtual void destroyDecodedData(bool destroyAll = true) { Q_UNUSED(destroyAll); } virtual unsigned decodedSize() const { return 0; } virtual IntSize size() const; diff --git a/WebCore/platform/graphics/skia/GradientSkia.cpp b/WebCore/platform/graphics/skia/GradientSkia.cpp index 3bdddb2..268b17e 100644 --- a/WebCore/platform/graphics/skia/GradientSkia.cpp +++ b/WebCore/platform/graphics/skia/GradientSkia.cpp @@ -152,19 +152,21 @@ SkShader* Gradient::platformGradient() } if (m_radial) { - // FIXME: CSS radial Gradients allow an offset focal point (the - // "start circle"), but skia doesn't seem to support that, so this just - // ignores m_p0/m_r0 and draws the gradient centered in the "end - // circle" (m_p1/m_r1). - // See http://webkit.org/blog/175/introducing-css-gradients/ for a - // description of the expected behavior. - - // The radius we give to Skia must be positive (and non-zero). If - // we're given a zero radius, just ask for a very small radius so - // Skia will still return an object. - SkScalar radius = m_r1 > 0 ? WebCoreFloatToSkScalar(m_r1) : SK_ScalarMin; - m_gradient = SkGradientShader::CreateRadial(m_p1, - radius, colors, pos, static_cast<int>(countUsed), tile); + // Since the two-point radial gradient is slower than the plain radial, + // only use it if we have to. + if (m_p0 != m_p1) { + // The radii we give to Skia must be positive. If we're given a + // negative radius, ask for zero instead. + SkScalar radius0 = m_r0 >= 0.0f ? WebCoreFloatToSkScalar(m_r0) : 0; + SkScalar radius1 = m_r1 >= 0.0f ? WebCoreFloatToSkScalar(m_r1) : 0; + m_gradient = SkGradientShader::CreateTwoPointRadial(m_p0, radius0, m_p1, radius1, colors, pos, static_cast<int>(countUsed), tile); + } else { + // The radius we give to Skia must be positive (and non-zero). If + // we're given a zero radius, just ask for a very small radius so + // Skia will still return an object. + SkScalar radius = m_r1 > 0 ? WebCoreFloatToSkScalar(m_r1) : SK_ScalarMin; + m_gradient = SkGradientShader::CreateRadial(m_p1, radius, colors, pos, static_cast<int>(countUsed), tile); + } } else { SkPoint pts[2] = { m_p0, m_p1 }; m_gradient = SkGradientShader::CreateLinear(pts, colors, pos, diff --git a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp index bbb42c9..c9f1349 100644 --- a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp +++ b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp @@ -31,11 +31,11 @@ #include "config.h" #include "GraphicsContext.h" -#include "GraphicsContextPlatformPrivate.h" -#include "GraphicsContextPrivate.h" #include "Color.h" #include "FloatRect.h" #include "Gradient.h" +#include "GraphicsContextPlatformPrivate.h" +#include "GraphicsContextPrivate.h" #include "ImageBuffer.h" #include "IntRect.h" #include "NativeImageSkia.h" @@ -46,9 +46,9 @@ #include "SkBitmap.h" #include "SkBlurDrawLooper.h" #include "SkCornerPathEffect.h" -#include "skia/ext/platform_canvas.h" -#include "SkiaUtils.h" #include "SkShader.h" +#include "SkiaUtils.h" +#include "skia/ext/platform_canvas.h" #include <math.h> #include <wtf/Assertions.h> @@ -60,6 +60,23 @@ namespace WebCore { namespace { +inline int fastMod(int value, int max) +{ + int sign = SkExtractSign(value); + + value = SkApplySign(value, sign); + if (value >= max) + value %= max; + return SkApplySign(value, sign); +} + +inline float square(float n) +{ + return n * n; +} + +} // namespace + // "Seatbelt" functions ------------------------------------------------------ // // These functions check certain graphics primitives for being "safe". @@ -195,23 +212,6 @@ void addCornerArc(SkPath* path, const SkRect& rect, const IntSize& size, int sta path->arcTo(r, SkIntToScalar(startAngle), SkIntToScalar(90), false); } -inline int fastMod(int value, int max) -{ - int sign = SkExtractSign(value); - - value = SkApplySign(value, sign); - if (value >= max) - value %= max; - return SkApplySign(value, sign); -} - -inline float square(float n) -{ - return n * n; -} - -} // namespace - // ----------------------------------------------------------------------------- // This may be called with a NULL pointer to create a graphics context that has @@ -293,7 +293,7 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness path.addOval(r, SkPath::kCW_Direction); // only perform the inset if we won't invert r if (2 * thickness < rect.width() && 2 * thickness < rect.height()) { - r.inset(SkIntToScalar(thickness) ,SkIntToScalar(thickness)); + r.inset(SkIntToScalar(thickness), SkIntToScalar(thickness)); path.addOval(r, SkPath::kCCW_Direction); } platformContext()->canvas()->clipPath(path); @@ -403,6 +403,9 @@ void GraphicsContext::clipPath(WindRule clipRule) return; SkPath path = platformContext()->currentPathInLocalCoordinates(); + if (!isPathSkiaSafe(getCTM(), path)) + return; + path.setFillType(clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType); platformContext()->canvas()->clipPath(path); } @@ -487,7 +490,7 @@ void GraphicsContext::drawFocusRing(const Color& color) const Vector<IntRect>& rects = focusRingRects(); unsigned rectCount = rects.size(); - if (0 == rectCount) + if (!rectCount) return; SkRegion focusRingRegion; @@ -521,26 +524,28 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) return; SkPaint paint; - SkPoint pts[2] = { (SkPoint)point1, (SkPoint)point2 }; - if (!isPointSkiaSafe(getCTM(), pts[0]) || !isPointSkiaSafe(getCTM(), pts[1])) + if (!isPointSkiaSafe(getCTM(), point1) || !isPointSkiaSafe(getCTM(), point2)) return; + FloatPoint p1 = point1; + FloatPoint p2 = point2; + bool isVerticalLine = (p1.x() == p2.x()); + int width = roundf(strokeThickness()); + // We know these are vertical or horizontal lines, so the length will just // be the sum of the displacement component vectors give or take 1 - // probably worth the speed up of no square root, which also won't be exact. - SkPoint disp = pts[1] - pts[0]; - int length = SkScalarRound(disp.fX + disp.fY); + FloatSize disp = p2 - p1; + int length = SkScalarRound(disp.width() + disp.height()); platformContext()->setupPaintForStroking(&paint, 0, length); - int width = roundf(strokeThickness()); - bool isVerticalLine = pts[0].fX == pts[1].fX; if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) { // Do a rect fill of our endpoints. This ensures we always have the // appearance of being a border. We then draw the actual dotted/dashed line. SkRect r1, r2; - r1.set(pts[0].fX, pts[0].fY, pts[0].fX + width, pts[0].fY + width); - r2.set(pts[1].fX, pts[1].fY, pts[1].fX + width, pts[1].fY + width); + r1.set(p1.x(), p1.y(), p1.x() + width, p1.y() + width); + r2.set(p2.x(), p2.y(), p2.x() + width, p2.y() + width); if (isVerticalLine) { r1.offset(-width / 2, 0); @@ -553,35 +558,11 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) fillPaint.setColor(paint.getColor()); platformContext()->canvas()->drawRect(r1, fillPaint); platformContext()->canvas()->drawRect(r2, fillPaint); - - // Since we've already rendered the endcaps, adjust the endpoints to - // exclude them from the line itself. - if (isVerticalLine) { - pts[0].fY += width; - pts[1].fY -= width; - } else { - pts[0].fX += width; - pts[1].fX -= width; - } } - // "Borrowed" this comment and idea from GraphicsContextCG.cpp - // - // For odd widths, we add in 0.5 to the appropriate x/y so that the float - // arithmetic works out. For example, with a border width of 3, KHTML will - // pass us (y1+y2)/2, e.g., (50+53)/2 = 103/2 = 51 when we want 51.5. It is - // always true that an even width gave us a perfect position, but an odd - // width gave us a position that is off by exactly 0.5. + adjustLineToPixelBoundaries(p1, p2, width, penStyle); + SkPoint pts[2] = { (SkPoint)p1, (SkPoint)p2 }; - if (width & 1) { // Odd. - if (isVerticalLine) { - pts[0].fX = pts[0].fX + SK_ScalarHalf; - pts[1].fX = pts[0].fX; - } else { // Horizontal line - pts[0].fY = pts[0].fY + SK_ScalarHalf; - pts[1].fY = pts[0].fY; - } - } platformContext()->canvas()->drawPoints(SkCanvas::kLines_PointMode, 2, pts, paint); } @@ -844,9 +825,9 @@ FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) deviceLowerRight.setY(roundf(deviceLowerRight.y())); // Don't let the height or width round to 0 unless either was originally 0 - if (deviceOrigin.y() == deviceLowerRight.y() && rect.height() != 0) + if (deviceOrigin.y() == deviceLowerRight.y() && rect.height()) deviceLowerRight.move(0, 1); - if (deviceOrigin.x() == deviceLowerRight.x() && rect.width() != 0) + if (deviceOrigin.x() == deviceLowerRight.x() && rect.width()) deviceLowerRight.move(1, 0); FloatPoint roundedOrigin(deviceOrigin.x() / deviceScaleX, @@ -919,7 +900,7 @@ void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) return; } - size_t count = (dashLength % 2) == 0 ? dashLength : dashLength * 2; + size_t count = !(dashLength % 2) ? dashLength : dashLength * 2; SkScalar* intervals = new SkScalar[count]; for (unsigned int i = 0; i < count; i++) @@ -990,8 +971,8 @@ void GraphicsContext::setPlatformShadow(const IntSize& size, return; // Detect when there's no effective shadow and clear the looper. - if (size.width() == 0 && size.height() == 0 && blurInt == 0) { - platformContext()->setDrawLooper(NULL); + if (!size.width() && !size.height() && !blurInt) { + platformContext()->setDrawLooper(0); return; } diff --git a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp index 7935ff1..a5c8926 100644 --- a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp @@ -39,6 +39,7 @@ #include "ImageData.h" #include "PlatformContextSkia.h" #include "PNGImageEncoder.h" +#include "SkColorPriv.h" #include "SkiaUtils.h" using namespace std; @@ -118,16 +119,16 @@ void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable) } } -PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const +template <Multiply multiplied> +PassRefPtr<ImageData> getImageData(const IntRect& rect, const SkBitmap& bitmap, + const IntSize& size) { - ASSERT(context()); - RefPtr<ImageData> result = ImageData::create(rect.width(), rect.height()); unsigned char* data = result->data()->data()->data(); if (rect.x() < 0 || rect.y() < 0 || - (rect.x() + rect.width()) > m_size.width() || - (rect.y() + rect.height()) > m_size.height()) + (rect.x() + rect.width()) > size.width() || + (rect.y() + rect.height()) > size.height()) memset(data, 0, result->data()->length()); int originX = rect.x(); @@ -137,8 +138,8 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const originX = 0; } int endX = rect.x() + rect.width(); - if (endX > m_size.width()) - endX = m_size.width(); + if (endX > size.width()) + endX = size.width(); int numColumns = endX - originX; int originY = rect.y(); @@ -148,11 +149,10 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const originY = 0; } int endY = rect.y() + rect.height(); - if (endY > m_size.height()) - endY = m_size.height(); + if (endY > size.height()) + endY = size.height(); int numRows = endY - originY; - const SkBitmap& bitmap = *context()->platformContext()->bitmap(); ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); SkAutoLockPixels bitmapLock(bitmap); @@ -162,12 +162,21 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const for (int y = 0; y < numRows; ++y) { uint32_t* srcRow = bitmap.getAddr32(originX, originY + y); for (int x = 0; x < numColumns; ++x) { - SkColor color = SkPMColorToColor(srcRow[x]); unsigned char* destPixel = &destRow[x * 4]; - destPixel[0] = SkColorGetR(color); - destPixel[1] = SkColorGetG(color); - destPixel[2] = SkColorGetB(color); - destPixel[3] = SkColorGetA(color); + if (multiplied == Unmultiplied) { + SkColor color = SkPMColorToColor(srcRow[x]); + destPixel[0] = SkColorGetR(color); + destPixel[1] = SkColorGetG(color); + destPixel[2] = SkColorGetB(color); + destPixel[3] = SkColorGetA(color); + } else { + // Input and output are both pre-multiplied, we just need to re-arrange the + // bytes from the bitmap format to RGBA. + destPixel[0] = SkGetPackedR32(srcRow[x]); + destPixel[1] = SkGetPackedG32(srcRow[x]); + destPixel[2] = SkGetPackedB32(srcRow[x]); + destPixel[3] = SkGetPackedA32(srcRow[x]); + } } destRow += destBytesPerRow; } @@ -175,8 +184,19 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const return result; } -void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, - const IntPoint& destPoint) +PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const +{ + return getImageData<Unmultiplied>(rect, *context()->platformContext()->bitmap(), m_size); +} + +PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const +{ + return getImageData<Premultiplied>(rect, *context()->platformContext()->bitmap(), m_size); +} + +template <Multiply multiplied> +void putImageData(ImageData*& source, const IntRect& sourceRect, const IntPoint& destPoint, + const SkBitmap& bitmap, const IntSize& size) { ASSERT(sourceRect.width() > 0); ASSERT(sourceRect.height() > 0); @@ -184,27 +204,26 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, int originX = sourceRect.x(); int destX = destPoint.x() + sourceRect.x(); ASSERT(destX >= 0); - ASSERT(destX < m_size.width()); + ASSERT(destX < size.width()); ASSERT(originX >= 0); ASSERT(originX < sourceRect.right()); int endX = destPoint.x() + sourceRect.right(); - ASSERT(endX <= m_size.width()); + ASSERT(endX <= size.width()); int numColumns = endX - destX; int originY = sourceRect.y(); int destY = destPoint.y() + sourceRect.y(); ASSERT(destY >= 0); - ASSERT(destY < m_size.height()); + ASSERT(destY < size.height()); ASSERT(originY >= 0); ASSERT(originY < sourceRect.bottom()); int endY = destPoint.y() + sourceRect.bottom(); - ASSERT(endY <= m_size.height()); + ASSERT(endY <= size.height()); int numRows = endY - destY; - const SkBitmap& bitmap = *context()->platformContext()->bitmap(); ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); SkAutoLockPixels bitmapLock(bitmap); @@ -216,13 +235,27 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, uint32_t* destRow = bitmap.getAddr32(destX, destY + y); for (int x = 0; x < numColumns; ++x) { const unsigned char* srcPixel = &srcRow[x * 4]; - destRow[x] = SkPreMultiplyARGB(srcPixel[3], srcPixel[0], - srcPixel[1], srcPixel[2]); + if (multiplied == Unmultiplied) + destRow[x] = SkPreMultiplyARGB(srcPixel[3], srcPixel[0], + srcPixel[1], srcPixel[2]); + else + destRow[x] = SkPackARGB32(srcPixel[3], srcPixel[0], + srcPixel[1], srcPixel[2]); } srcRow += srcBytesPerRow; } } +void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<Unmultiplied>(source, sourceRect, destPoint, *context()->platformContext()->bitmap(), m_size); +} + +void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<Premultiplied>(source, sourceRect, destPoint, *context()->platformContext()->bitmap(), m_size); +} + String ImageBuffer::toDataURL(const String&) const { // Encode the image into a vector. diff --git a/WebCore/platform/graphics/skia/ImageSkia.cpp b/WebCore/platform/graphics/skia/ImageSkia.cpp index 45c3dcd..ecab364 100644 --- a/WebCore/platform/graphics/skia/ImageSkia.cpp +++ b/WebCore/platform/graphics/skia/ImageSkia.cpp @@ -41,6 +41,7 @@ #include "PlatformContextSkia.h" #include "PlatformString.h" #include "SkiaUtils.h" +#include "SkRect.h" #include "SkShader.h" #include "TransformationMatrix.h" @@ -158,8 +159,8 @@ static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeIm // We will always draw in integer sizes, so round the destination rect. SkIRect destRectRounded; destRect.round(&destRectRounded); - SkIRect resizedImageRect; // Represents the size of the resized image. - resizedImageRect.set(0, 0, destRectRounded.width(), destRectRounded.height()); + SkIRect resizedImageRect = // Represents the size of the resized image. + { 0, 0, destRectRounded.width(), destRectRounded.height() }; if (srcIsFull && bitmap.hasResizedBitmap(destRectRounded.width(), destRectRounded.height())) { // Yay, this bitmap frame already has a resized version. @@ -196,25 +197,19 @@ static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeIm } else { // We should only resize the exposed part of the bitmap to do the // minimal possible work. - gfx::Rect destBitmapSubset(destBitmapSubsetSkI.fLeft, - destBitmapSubsetSkI.fTop, - destBitmapSubsetSkI.width(), - destBitmapSubsetSkI.height()); // Resample the needed part of the image. SkBitmap resampled = skia::ImageOperations::Resize(subset, skia::ImageOperations::RESIZE_LANCZOS3, destRectRounded.width(), destRectRounded.height(), - destBitmapSubset); + destBitmapSubsetSkI); // Compute where the new bitmap should be drawn. Since our new bitmap // may be smaller than the original, we have to shift it over by the // same amount that we cut off the top and left. - SkRect offsetDestRect = { - destBitmapSubset.x() + destRect.fLeft, - destBitmapSubset.y() + destRect.fTop, - destBitmapSubset.right() + destRect.fLeft, - destBitmapSubset.bottom() + destRect.fTop }; + destBitmapSubsetSkI.offset(destRect.fLeft, destRect.fTop); + SkRect offsetDestRect; + offsetDestRect.set(destBitmapSubsetSkI); canvas.drawBitmapRect(resampled, 0, offsetDestRect, &paint); } diff --git a/WebCore/platform/graphics/skia/ImageSourceSkia.cpp b/WebCore/platform/graphics/skia/ImageSourceSkia.cpp deleted file mode 100644 index 1647b86..0000000 --- a/WebCore/platform/graphics/skia/ImageSourceSkia.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (c) 2008, Google 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: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT - * OWNER 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 "ImageSource.h" -#include "SharedBuffer.h" - -#include "GIFImageDecoder.h" -#include "ICOImageDecoder.h" -#include "JPEGImageDecoder.h" -#include "PNGImageDecoder.h" -#include "BMPImageDecoder.h" -#include "XBMImageDecoder.h" - -#include "SkBitmap.h" - -namespace WebCore { - -ImageDecoder* createDecoder(const Vector<char>& data) -{ - // We need at least 4 bytes to figure out what kind of image we're dealing with. - int length = data.size(); - if (length < 4) - return 0; - - const unsigned char* uContents = (const unsigned char*)data.data(); - const char* contents = data.data(); - - // GIFs begin with GIF8(7 or 9). - if (strncmp(contents, "GIF8", 4) == 0) - return new GIFImageDecoder(); - - // Test for PNG. - if (uContents[0]==0x89 && - uContents[1]==0x50 && - uContents[2]==0x4E && - uContents[3]==0x47) - return new PNGImageDecoder(); - - // JPEG - if (uContents[0]==0xFF && - uContents[1]==0xD8 && - uContents[2]==0xFF) - return new JPEGImageDecoder(); - - // BMP - if (strncmp(contents, "BM", 2) == 0) - return new BMPImageDecoder(); - - // ICOs always begin with a 2-byte 0 followed by a 2-byte 1. - // CURs begin with 2-byte 0 followed by 2-byte 2. - if (!memcmp(contents, "\000\000\001\000", 4) || - !memcmp(contents, "\000\000\002\000", 4)) - return new ICOImageDecoder(); - - // XBMs require 8 bytes of info. - if (length >= 8 && strncmp(contents, "#define ", 8) == 0) - return new XBMImageDecoder(); - - // Give up. We don't know what the heck this is. - return 0; -} - -ImageSource::ImageSource() - : m_decoder(0) -{} - -ImageSource::~ImageSource() -{ - clear(true); -} - -void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived) -{ - if (!destroyAll) { - if (m_decoder) - m_decoder->clearFrameBufferCache(clearBeforeFrame); - return; - } - - delete m_decoder; - m_decoder = 0; - if (data) - setData(data, allDataReceived); -} - -bool ImageSource::initialized() const -{ - return m_decoder; -} - -void ImageSource::setData(SharedBuffer* data, bool allDataReceived) -{ - // Make the decoder by sniffing the bytes. - // This method will examine the data and instantiate an instance of the appropriate decoder plugin. - // If insufficient bytes are available to determine the image type, no decoder plugin will be - // made. - if (!m_decoder) - m_decoder = createDecoder(data->buffer()); - - // CreateDecoder will return NULL if the decoder could not be created. Plus, - // we should not send more data to a decoder which has already decided it - // has failed. - if (!m_decoder || m_decoder->failed()) - return; - m_decoder->setData(data, allDataReceived); -} - -bool ImageSource::isSizeAvailable() -{ - if (!m_decoder) - return false; - - return m_decoder->isSizeAvailable(); -} - -IntSize ImageSource::size() const -{ - if (!m_decoder) - return IntSize(); - - return m_decoder->size(); -} - -IntSize ImageSource::frameSizeAtIndex(size_t index) const -{ - if (!m_decoder) - return IntSize(); - - return m_decoder->frameSizeAtIndex(index); -} - -int ImageSource::repetitionCount() -{ - if (!m_decoder) - return cAnimationNone; - - return m_decoder->repetitionCount(); -} - -size_t ImageSource::frameCount() const -{ - if (!m_decoder) - return 0; - return m_decoder->failed() ? 0 : m_decoder->frameCount(); -} - -NativeImagePtr ImageSource::createFrameAtIndex(size_t index) -{ - if (!m_decoder) - return 0; - - // Note that the buffer can have NULL bytes even when it is marked as - // non-empty. It seems "FrameEmpty" is only set before the frame has been - // initialized. If it is decoded and it happens to be empty, it will be - // marked as "FrameComplete" but will still have NULL bytes. - RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); - if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) - return 0; - - // Copy the bitmap. The pixel data is refcounted internally by SkBitmap, so - // this doesn't cost much. - return buffer->asNewNativeImage(); -} - -bool ImageSource::frameIsCompleteAtIndex(size_t index) -{ - if (!m_decoder) - return false; - - RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); - return buffer && buffer->status() == RGBA32Buffer::FrameComplete; -} - -float ImageSource::frameDurationAtIndex(size_t index) -{ - if (!m_decoder) - return 0; - - RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); - if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) - return 0; - - // Many annoying ads specify a 0 duration to make an image flash as quickly - // as possible. We follow WinIE's behavior and use a duration of 100 ms - // for any frames that specify a duration of <= 50 ms. See - // <http://bugs.webkit.org/show_bug.cgi?id=14413> or Radar 4051389 for - // more. - const float duration = buffer->duration() / 1000.0f; - return (duration < 0.051f) ? 0.100f : duration; -} - -bool ImageSource::frameHasAlphaAtIndex(size_t index) -{ - if (!m_decoder || !m_decoder->supportsAlpha()) - return false; - - RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); - if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) - return false; - - return buffer->hasAlpha(); -} - -String ImageSource::filenameExtension() const -{ - return m_decoder ? m_decoder->filenameExtension() : String(); -} - -} diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp index e0a292c..1fb62fc 100644 --- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -46,6 +46,11 @@ #include <wtf/MathExtras.h> +namespace WebCore +{ +extern bool isPathSkiaSafe(const SkMatrix& transform, const SkPath& path); +} + // State ----------------------------------------------------------------------- // Encapsulates the additional painting state information we store for each @@ -278,6 +283,7 @@ void PlatformContextSkia::drawRect(SkRect rect) SkShader* oldFillShader = m_state->m_fillShader; oldFillShader->safeRef(); setFillColor(m_state->m_strokeColor); + paint.reset(); setupPaintForFilling(&paint); SkRect topBorder = { rect.fLeft, rect.fTop, rect.fRight, rect.fTop + 1 }; canvas()->drawRect(topBorder, paint); @@ -295,7 +301,7 @@ void PlatformContextSkia::drawRect(SkRect rect) void PlatformContextSkia::setupPaintCommon(SkPaint* paint) const { -#ifdef SK_DEBUGx +#if defined(SK_DEBUG) { SkPaint defaultPaint; SkASSERT(*paint == defaultPaint); diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp index 803f5db..e2ed130 100644 --- a/WebCore/platform/graphics/win/FontCGWin.cpp +++ b/WebCore/platform/graphics/win/FontCGWin.cpp @@ -297,6 +297,30 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo CGContextRef cgContext = graphicsContext->platformContext(); bool shouldUseFontSmoothing = WebCoreShouldUseFontSmoothing(); + switch(fontDescription().fontSmoothing()) { + case Antialiased: { + graphicsContext->setShouldAntialias(true); + shouldUseFontSmoothing = false; + break; + } + case SubpixelAntialiased: { + graphicsContext->setShouldAntialias(true); + shouldUseFontSmoothing = true; + break; + } + case NoSmoothing: { + graphicsContext->setShouldAntialias(false); + shouldUseFontSmoothing = false; + break; + } + case AutoSmoothing: { + // For the AutoSmooth case, don't do anything! Keep the default settings. + break; + } + default: + ASSERT_NOT_REACHED(); + } + if (font->platformData().useGDI()) { if (!shouldUseFontSmoothing || (graphicsContext->textDrawingMode() & cTextStroke)) { drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point); diff --git a/WebCore/platform/graphics/win/FontCacheWin.cpp b/WebCore/platform/graphics/win/FontCacheWin.cpp index 887bf79..8663623 100644 --- a/WebCore/platform/graphics/win/FontCacheWin.cpp +++ b/WebCore/platform/graphics/win/FontCacheWin.cpp @@ -33,8 +33,9 @@ #include "SimpleFontData.h" #include "StringHash.h" #include "UnicodeRange.h" -#include <windows.h> #include <mlang.h> +#include <windows.h> +#include <wtf/StdLibExtras.h> #if PLATFORM(CG) #include <ApplicationServices/ApplicationServices.h> #include <WebKitSystemInterface/WebKitSystemInterface.h> @@ -305,7 +306,17 @@ FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fo // FIXME: Would be even better to somehow get the user's default font here. For now we'll pick // the default that the user would get without changing any prefs. static AtomicString timesStr("Times New Roman"); - return getCachedFontPlatformData(fontDescription, timesStr); + if (FontPlatformData* platformFont = getCachedFontPlatformData(fontDescription, timesStr)) + return platformFont; + + DEFINE_STATIC_LOCAL(String, defaultGUIFontFamily, ()); + if (defaultGUIFontFamily.isEmpty()) { + HFONT defaultGUIFont = static_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT)); + LOGFONT logFont; + GetObject(defaultGUIFont, sizeof(logFont), &logFont); + defaultGUIFontFamily = String(logFont.lfFaceName, wcsnlen(logFont.lfFaceName, LF_FACESIZE)); + } + return getCachedFontPlatformData(fontDescription, defaultGUIFontFamily); } static LONG toGDIFontWeight(FontWeight fontWeight) diff --git a/WebCore/platform/graphics/win/FontDatabase.cpp b/WebCore/platform/graphics/win/FontDatabase.cpp index 1308ff0..d0773ea 100644 --- a/WebCore/platform/graphics/win/FontDatabase.cpp +++ b/WebCore/platform/graphics/win/FontDatabase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -99,17 +99,12 @@ static RetainPtr<CFPropertyListRef> readFontPlist() return plist; } -static bool populateFontDatabaseFromPlist() +static bool populateFontDatabaseFromPlist(CFPropertyListRef plist) { - RetainPtr<CFPropertyListRef> plist = readFontPlist(); if (!plist) return false; - RetainPtr<CFDataRef> data(AdoptCF, CFPropertyListCreateXMLData(0, plist.get())); - if (!data) - return false; - - wkAddFontsFromPlistRepresentation(data.get()); + wkAddFontsFromPlist(plist); return true; } @@ -123,15 +118,69 @@ static bool populateFontDatabaseFromFileSystem() return true; } -static void writeFontDatabaseToPlist() +static CFStringRef fontFilenamesFromRegistryKey() +{ + static CFStringRef key = CFSTR("WebKitFontFilenamesFromRegistry"); + return key; +} + +static void writeFontDatabaseToPlist(CFPropertyListRef cgFontDBPropertyList, CFPropertyListRef filenamesFromRegistry) { - RetainPtr<CFDataRef> data(AdoptCF, wkCreateFontsPlistRepresentation()); + if (!cgFontDBPropertyList) + return; + + RetainPtr<CFDataRef> data; + + if (!filenamesFromRegistry || CFGetTypeID(cgFontDBPropertyList) != CFDictionaryGetTypeID()) + data.adoptCF(CFPropertyListCreateXMLData(kCFAllocatorDefault, cgFontDBPropertyList)); + else { + RetainPtr<CFMutableDictionaryRef> dictionary(AdoptCF, CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 2, static_cast<CFDictionaryRef>(cgFontDBPropertyList))); + CFDictionarySetValue(dictionary.get(), fontFilenamesFromRegistryKey(), filenamesFromRegistry); + data.adoptCF(CFPropertyListCreateXMLData(kCFAllocatorDefault, dictionary.get())); + } + if (!data) return; safeCreateFile(fontsPlistPath(), data.get()); } +static RetainPtr<CFArrayRef> fontFilenamesFromRegistry() +{ + RetainPtr<CFMutableArrayRef> filenames(AdoptCF, CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks)); + + HKEY key; + if (FAILED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"), 0, KEY_READ, &key))) + return filenames; + + DWORD valueCount; + DWORD maxNameLength; + DWORD maxValueLength; + if (FAILED(RegQueryInfoKey(key, 0, 0, 0, 0, 0, 0, &valueCount, &maxNameLength, &maxValueLength, 0, 0))) { + RegCloseKey(key); + return filenames; + } + + Vector<TCHAR> name(maxNameLength + 1); + Vector<BYTE> value(maxValueLength + 1); + + for (size_t i = 0; i < valueCount; ++i) { + DWORD nameLength = name.size(); + DWORD valueLength = value.size(); + DWORD type; + if (FAILED(RegEnumValue(key, i, name.data(), &nameLength, 0, &type, value.data(), &valueLength))) + continue; + if (type != REG_SZ) + continue; + + RetainPtr<CFDataRef> filename(AdoptCF, CFDataCreate(kCFAllocatorDefault, value.data(), valueLength)); + CFArrayAppendValue(filenames.get(), filename.get()); + } + + RegCloseKey(key); + return filenames; +} + void populateFontDatabase() { static bool initialized; @@ -139,12 +188,27 @@ void populateFontDatabase() return; initialized = true; - if (!systemHasFontsNewerThanFontsPlist()) - if (populateFontDatabaseFromPlist()) + RetainPtr<CFPropertyListRef> propertyList = readFontPlist(); + RetainPtr<CFArrayRef> lastFilenamesFromRegistry; + if (propertyList && CFGetTypeID(propertyList.get()) == CFDictionaryGetTypeID()) { + CFDictionaryRef dictionary = static_cast<CFDictionaryRef>(propertyList.get()); + CFArrayRef array = static_cast<CFArrayRef>(CFDictionaryGetValue(dictionary, fontFilenamesFromRegistryKey())); + if (array && CFGetTypeID(array) == CFArrayGetTypeID()) + lastFilenamesFromRegistry = array; + } + RetainPtr<CFArrayRef> currentFilenamesFromRegistry = fontFilenamesFromRegistry(); + bool registryChanged = !lastFilenamesFromRegistry || !CFEqual(lastFilenamesFromRegistry.get(), currentFilenamesFromRegistry.get()); + + if (!registryChanged && !systemHasFontsNewerThanFontsPlist()) { + if (populateFontDatabaseFromPlist(propertyList.get())) return; + } - if (populateFontDatabaseFromFileSystem()) - writeFontDatabaseToPlist(); + if (populateFontDatabaseFromFileSystem()) { + wkAddFontsFromRegistry(); + RetainPtr<CFPropertyListRef> cgFontDBPropertyList(AdoptCF, wkCreateFontsPlist()); + writeFontDatabaseToPlist(cgFontDBPropertyList.get(), currentFilenamesFromRegistry.get()); + } } } // namespace WebCore diff --git a/WebCore/platform/graphics/win/FontPlatformData.h b/WebCore/platform/graphics/win/FontPlatformData.h index 0660d90..5084469 100644 --- a/WebCore/platform/graphics/win/FontPlatformData.h +++ b/WebCore/platform/graphics/win/FontPlatformData.h @@ -78,7 +78,6 @@ public: #if PLATFORM(CG) CGFontRef cgFont() const { return m_cgFont.get(); } #elif PLATFORM(CAIRO) - void setFont(cairo_t* ft) const; cairo_font_face_t* fontFace() const { return m_fontFace; } cairo_scaled_font_t* scaledFont() const { return m_scaledFont; } #endif diff --git a/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp index b56a71c..9fce68a 100644 --- a/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp +++ b/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp @@ -96,12 +96,6 @@ FontPlatformData::FontPlatformData(const FontPlatformData& source) m_scaledFont = cairo_scaled_font_reference(source.m_scaledFont); } -void FontPlatformData::setFont(cairo_t* cr) const -{ - ASSERT(m_scaledFont); - - cairo_set_scaled_font(cr, m_scaledFont); -} FontPlatformData::~FontPlatformData() { diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp index 9eaf54b..1923ecc 100644 --- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp @@ -65,7 +65,7 @@ GraphicsContext::GraphicsContext(HDC hdc, bool hasAlpha) : m_common(createGraphicsContextPrivate()) , m_data(new GraphicsContextPlatformPrivate(CGContextWithHDC(hdc, hasAlpha))) { - CGContextRelease(m_data->m_cgContext); + CGContextRelease(m_data->m_cgContext.get()); m_data->m_hdc = hdc; setPaintingDisabled(!m_data->m_cgContext); if (m_data->m_cgContext) { @@ -98,7 +98,7 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo CGColorSpaceRelease(deviceRGB); CGImageRef image = CGBitmapContextCreateImage(bitmapContext); - CGContextDrawImage(m_data->m_cgContext, dstRect, image); + CGContextDrawImage(m_data->m_cgContext.get(), dstRect, image); // Delete all our junk. CGImageRelease(image); @@ -121,7 +121,7 @@ void GraphicsContext::drawWindowsBitmap(WindowsBitmap* image, const IntPoint& po RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(imageData.get())); RetainPtr<CGImageRef> cgImage(AdoptCF, CGImageCreate(image->size().width(), image->size().height(), 8, 32, image->bytesPerRow(), deviceRGB.get(), kCGBitmapByteOrder32Little | kCGImageAlphaFirst, dataProvider.get(), 0, true, kCGRenderingIntentDefault)); - CGContextDrawImage(m_data->m_cgContext, CGRectMake(point.x(), point.y(), image->size().width(), image->size().height()), cgImage.get()); + CGContextDrawImage(m_data->m_cgContext.get(), CGRectMake(point.x(), point.y(), image->size().width(), image->size().height()), cgImage.get()); } void GraphicsContext::drawFocusRing(const Color& color) @@ -243,7 +243,7 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& point, void GraphicsContextPlatformPrivate::flush() { - CGContextFlush(m_cgContext); + CGContextFlush(m_cgContext.get()); } } diff --git a/WebCore/platform/graphics/win/ImageCGWin.cpp b/WebCore/platform/graphics/win/ImageCGWin.cpp index 8a8e943..285fb71 100644 --- a/WebCore/platform/graphics/win/ImageCGWin.cpp +++ b/WebCore/platform/graphics/win/ImageCGWin.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "Image.h" #include "BitmapImage.h" +#include "BitmapInfo.h" #include "GraphicsContext.h" #include <ApplicationServices/ApplicationServices.h> @@ -34,6 +35,30 @@ namespace WebCore { +PassRefPtr<BitmapImage> BitmapImage::create(HBITMAP hBitmap) +{ + DIBSECTION dibSection; + if (!GetObject(hBitmap, sizeof(DIBSECTION), &dibSection)) + return 0; + + ASSERT(dibSection.dsBm.bmBitsPixel == 32); + if (dibSection.dsBm.bmBitsPixel != 32) + return 0; + + ASSERT(dibSection.dsBm.bmBits); + if (!dibSection.dsBm.bmBits) + return 0; + + RetainPtr<CGColorSpaceRef> deviceRGB(AdoptCF, CGColorSpaceCreateDeviceRGB()); + RetainPtr<CGContextRef> bitmapContext(AdoptCF, CGBitmapContextCreate(dibSection.dsBm.bmBits, dibSection.dsBm.bmWidth, dibSection.dsBm.bmHeight, 8, + dibSection.dsBm.bmWidthBytes, deviceRGB.get(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst)); + + // The BitmapImage takes ownership of this. + CGImageRef cgImage = CGBitmapContextCreateImage(bitmapContext.get()); + + return adoptRef(new BitmapImage(cgImage)); +} + bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) { ASSERT(bmp); diff --git a/WebCore/platform/graphics/win/ImageCairoWin.cpp b/WebCore/platform/graphics/win/ImageCairoWin.cpp index 591375f..0b27438 100644 --- a/WebCore/platform/graphics/win/ImageCairoWin.cpp +++ b/WebCore/platform/graphics/win/ImageCairoWin.cpp @@ -28,12 +28,33 @@ #include "BitmapImage.h" #include "GraphicsContext.h" #include <cairo.h> +#include <cairo-win32.h> #include <windows.h> #include "PlatformString.h" namespace WebCore { +PassRefPtr<BitmapImage> BitmapImage::create(HBITMAP hBitmap) +{ + DIBSECTION dibSection; + if (!GetObject(hBitmap, sizeof(DIBSECTION), &dibSection)) + return 0; + + ASSERT(dibSection.dsBm.bmBitsPixel == 32); + if (dibSection.dsBm.bmBitsPixel != 32) + return 0; + + ASSERT(dibSection.dsBm.bmBits); + if (!dibSection.dsBm.bmBits) + return 0; + + cairo_surface_t* image = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, dibSection.dsBm.bmWidth, dibSection.dsBm.bmHeight); + + // The BitmapImage object takes over ownership of the cairo_surface_t*, so no need to destroy here. + return adoptRef(new BitmapImage(image)); +} + bool BitmapImage::getHBITMAPOfSize(HBITMAP bmp, LPSIZE size) { ASSERT(bmp); diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp index eb7334e..15e1001 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp @@ -33,6 +33,8 @@ #include "QTMovieWin.h" #include "ScrollView.h" #include "StringHash.h" +#include "TimeRanges.h" +#include "Timer.h" #include <wtf/HashSet.h> #include <wtf/MathExtras.h> #include <wtf/StdLibExtras.h> @@ -86,6 +88,50 @@ MediaPlayerPrivate::~MediaPlayerPrivate() { } +class TaskTimer : TimerBase { +public: + static void initialize(); + +private: + static void setTaskTimerDelay(double); + static void stopTaskTimer(); + + void fired(); + + static TaskTimer* s_timer; +}; + +TaskTimer* TaskTimer::s_timer = 0; + +void TaskTimer::initialize() +{ + if (s_timer) + return; + + s_timer = new TaskTimer; + + QTMovieWin::setTaskTimerFuncs(setTaskTimerDelay, stopTaskTimer); +} + +void TaskTimer::setTaskTimerDelay(double delayInSeconds) +{ + ASSERT(s_timer); + + s_timer->startOneShot(delayInSeconds); +} + +void TaskTimer::stopTaskTimer() +{ + ASSERT(s_timer); + + s_timer->stop(); +} + +void TaskTimer::fired() +{ + QTMovieWin::taskTimerFired(); +} + void MediaPlayerPrivate::load(const String& url) { if (!QTMovieWin::initializeQuickTime()) { @@ -95,6 +141,9 @@ void MediaPlayerPrivate::load(const String& url) return; } + // Initialize the task timer. + TaskTimer::initialize(); + if (m_networkState != MediaPlayer::Loading) { m_networkState = MediaPlayer::Loading; m_player->networkStateChanged(); @@ -241,6 +290,13 @@ bool MediaPlayerPrivate::hasVideo() const return m_qtMovie->hasVideo(); } +bool MediaPlayerPrivate::hasAudio() const +{ + if (!m_qtMovie) + return false; + return m_qtMovie->hasAudio(); +} + void MediaPlayerPrivate::setVolume(float volume) { if (!m_qtMovie) @@ -268,10 +324,14 @@ int MediaPlayerPrivate::dataRate() const return 0; } -float MediaPlayerPrivate::maxTimeBuffered() const +PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const { + RefPtr<TimeRanges> timeRanges = TimeRanges::create(); + float loaded = maxTimeLoaded(); // rtsp streams are not buffered - return m_isStreaming ? 0 : maxTimeLoaded(); + if (!m_isStreaming && loaded > 0) + timeRanges->add(0, loaded); + return timeRanges.release(); } float MediaPlayerPrivate::maxTimeSeekable() const @@ -575,4 +635,3 @@ bool MediaPlayerPrivate::hasSingleSecurityOrigin() const } #endif - diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h index f584148..4a3a28e 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h @@ -52,7 +52,8 @@ public: IntSize naturalSize() const; bool hasVideo() const; - + bool hasAudio() const; + void load(const String& url); void cancelLoad(); @@ -76,7 +77,7 @@ public: MediaPlayer::NetworkState networkState() const { return m_networkState; } MediaPlayer::ReadyState readyState() const { return m_readyState; } - float maxTimeBuffered() const; + PassRefPtr<TimeRanges> buffered() const; float maxTimeSeekable() const; unsigned bytesLoaded() const; bool totalBytesKnown() const; diff --git a/WebCore/platform/graphics/win/QTMovieWin.cpp b/WebCore/platform/graphics/win/QTMovieWin.cpp index aaa61f1..56f3d0b 100644 --- a/WebCore/platform/graphics/win/QTMovieWin.cpp +++ b/WebCore/platform/graphics/win/QTMovieWin.cpp @@ -62,10 +62,13 @@ static HashSet<QTMovieWinPrivate*>* gTaskList; static Vector<CFStringRef>* gSupportedTypes = 0; static SInt32 quickTimeVersion = 0; +static QTMovieWin::SetTaskTimerDelayFunc gSetTaskTimerDelay = 0; +static QTMovieWin::StopTaskTimerFunc gStopTaskTimer = 0; + static void updateTaskTimer(int maxInterval = 1000) { if (!gTaskList->size()) { - stopSharedTimer(); + gStopTaskTimer(); return; } @@ -73,7 +76,7 @@ static void updateTaskTimer(int maxInterval = 1000) QTGetTimeUntilNextTask(&intervalInMS, 1000); if (intervalInMS > maxInterval) intervalInMS = maxInterval; - setSharedTimerFireDelay(static_cast<float>(intervalInMS) / 1000); + gSetTaskTimerDelay(static_cast<float>(intervalInMS) / 1000); } class QTMovieWinPrivate : public Noncopyable { @@ -166,7 +169,7 @@ QTMovieWinPrivate::~QTMovieWinPrivate() CFRelease(m_currentURL); } -static void taskTimerFired() +void QTMovieWin::taskTimerFired() { // The hash content might change during task() Vector<QTMovieWinPrivate*> tasks; @@ -867,6 +870,13 @@ bool QTMovieWin::hasVideo() const return (GetMovieIndTrackType(m_private->m_movie, 1, VisualMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly)); } +bool QTMovieWin::hasAudio() const +{ + if (!m_private->m_movie) + return false; + return (GetMovieIndTrackType(m_private->m_movie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly)); +} + pascal OSErr movieDrawingCompleteProc(Movie movie, long data) { UppParam param; @@ -990,6 +1000,12 @@ void QTMovieWin::getSupportedType(unsigned index, const UChar*& str, unsigned& l } +void QTMovieWin::setTaskTimerFuncs(SetTaskTimerDelayFunc setTaskTimerDelay, StopTaskTimerFunc stopTaskTimer) +{ + gSetTaskTimerDelay = setTaskTimerDelay; + gStopTaskTimer = stopTaskTimer; +} + bool QTMovieWin::initializeQuickTime() { static bool initialized = false; @@ -1009,7 +1025,6 @@ bool QTMovieWin::initializeQuickTime() return false; } EnterMovies(); - setSharedTimerFiredFunction(taskTimerFired); gMovieDrawingCompleteUPP = NewMovieDrawingCompleteUPP(movieDrawingCompleteProc); initializationSucceeded = true; } @@ -1020,7 +1035,6 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH: - setSharedTimerInstanceHandle(hinstDLL); return TRUE; case DLL_PROCESS_DETACH: case DLL_THREAD_ATTACH: diff --git a/WebCore/platform/graphics/win/QTMovieWin.h b/WebCore/platform/graphics/win/QTMovieWin.h index f46efd3..d178eb8 100644 --- a/WebCore/platform/graphics/win/QTMovieWin.h +++ b/WebCore/platform/graphics/win/QTMovieWin.h @@ -59,6 +59,11 @@ class QTMOVIEWIN_API QTMovieWin { public: static bool initializeQuickTime(); + typedef void (*SetTaskTimerDelayFunc)(double); + typedef void (*StopTaskTimerFunc)(); + static void setTaskTimerFuncs(SetTaskTimerDelayFunc, StopTaskTimerFunc); + static void taskTimerFired(); + QTMovieWin(QTMovieWinClient*); ~QTMovieWin(); @@ -91,6 +96,7 @@ public: void setDisabled(bool); bool hasVideo() const; + bool hasAudio() const; static unsigned countSupportedTypes(); static void getSupportedType(unsigned index, const UChar*& str, unsigned& len); diff --git a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp index 0343007..26b22af 100644 --- a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp +++ b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp @@ -119,10 +119,4 @@ float SimpleFontData::platformWidthForGlyph(Glyph glyph) const return width * metricsMultiplier; } -void SimpleFontData::setFont(cairo_t* cr) const -{ - ASSERT(cr); - m_platformData.setFont(cr); -} - } diff --git a/WebCore/platform/graphics/wince/ColorWince.cpp b/WebCore/platform/graphics/wince/ColorWince.cpp new file mode 100644 index 0000000..820b9d2 --- /dev/null +++ b/WebCore/platform/graphics/wince/ColorWince.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2007-2008 Torch Mobile, 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 "Color.h" + +#include "NotImplemented.h" + +namespace WebCore { + +Color focusRingColor() +{ + return Color(0, 0, 0); +} + +void setFocusRingColorChangeFunction(void (*)()) +{ + notImplemented(); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp b/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp index 7c6853c..699ff25 100644 --- a/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/wince/FontCustomPlatformData.cpp @@ -33,6 +33,11 @@ static CustomFontCache* g_customFontCache = 0; bool renameFont(SharedBuffer* fontData, const String& fontName); +void setCustomFontCache(CustomFontCache* cache) +{ + g_customFontCache = cache; +} + FontCustomPlatformData::~FontCustomPlatformData() { if (g_customFontCache && !m_name.isEmpty()) @@ -66,11 +71,12 @@ static String createUniqueFontName() return fontName.replace('/', '_'); } -FontCustomPlatformData* createFontCustomPlatformData(CachedFont* cachedFont) +FontCustomPlatformData* createFontCustomPlatformData(const SharedBuffer* buffer) { - if (g_customFontCache && cachedFont->CachedResource::data()) { + if (g_customFontCache) { String fontName = createUniqueFontName(); - if (renameFont(cachedFont->CachedResource::data(), fontName) && g_customFontCache->registerFont(fontName, cachedFont)) + RefPtr<SharedBuffer> localBuffer = SharedBuffer::create(buffer->data(), buffer->size()); + if (renameFont(localBuffer.get(), fontName) && g_customFontCache->registerFont(fontName, localBuffer.get())) return new FontCustomPlatformData(fontName); } return 0; diff --git a/WebCore/platform/graphics/wince/FontCustomPlatformData.h b/WebCore/platform/graphics/wince/FontCustomPlatformData.h index b1f64a0..89d1fdd 100644 --- a/WebCore/platform/graphics/wince/FontCustomPlatformData.h +++ b/WebCore/platform/graphics/wince/FontCustomPlatformData.h @@ -32,7 +32,7 @@ namespace WebCore { class CustomFontCache { public: - virtual bool registerFont(const String& fontName, CachedFont*) = 0; + virtual bool registerFont(const String& fontName, const SharedBuffer*) = 0; virtual void unregisterFont(const String& fontName) = 0; }; @@ -48,8 +48,8 @@ namespace WebCore { String m_name; }; - FontCustomPlatformData* createFontCustomPlatformData(CachedFont*); - + FontCustomPlatformData* createFontCustomPlatformData(const SharedBuffer*); + void setCustomFontCache(CustomFontCache*); } #endif diff --git a/WebCore/platform/graphics/wince/GradientWince.cpp b/WebCore/platform/graphics/wince/GradientWince.cpp new file mode 100644 index 0000000..49fa970 --- /dev/null +++ b/WebCore/platform/graphics/wince/GradientWince.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#include "config.h" +#include "Gradient.h" + +#include "GraphicsContext.h" + +namespace WebCore { + +void Gradient::platformDestroy() +{ +} + +static inline bool compareStops(const Gradient::ColorStop& a, const Gradient::ColorStop& b) +{ + return a.stop < b.stop; +} + +const Vector<Gradient::ColorStop>& Gradient::getStops() const +{ + if (!m_stopsSorted) { + if (m_stops.size()) + std::stable_sort(m_stops.begin(), m_stops.end(), compareStops); + m_stopsSorted = true; + } + return m_stops; +} + +void Gradient::fill(GraphicsContext* c, const FloatRect& r) +{ + c->fillRect(r, this); +} + +} diff --git a/WebCore/platform/graphics/wince/ImageBufferData.h b/WebCore/platform/graphics/wince/ImageBufferData.h new file mode 100644 index 0000000..01b7d06 --- /dev/null +++ b/WebCore/platform/graphics/wince/ImageBufferData.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef ImageBufferData_h +#define ImageBufferData_h + +namespace WebCore { + + class IntSize; + class ImageBufferData { + public: + ImageBufferData(const IntSize& size); + RefPtr<SharedBitmap> m_bitmap; + }; + +} // namespace WebCore + +#endif // ImageBufferData_h diff --git a/WebCore/platform/graphics/wince/ImageBufferWince.cpp b/WebCore/platform/graphics/wince/ImageBufferWince.cpp new file mode 100644 index 0000000..3417f5f --- /dev/null +++ b/WebCore/platform/graphics/wince/ImageBufferWince.cpp @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "ImageBuffer.h" + +#include "Base64.h" +#include "GraphicsContext.h" +#include "Image.h" +#include "ImageData.h" +#include "JPEGEncoder.h" +#include "PNGEncoder.h" +#include "SharedBitmap.h" + +namespace WebCore { + +class BufferedImage: public Image { + +public: + BufferedImage(const ImageBufferData* data) + : m_data(data) + { + } + + virtual IntSize size() const { return IntSize(m_data->m_bitmap->width(), m_data->m_bitmap->height()); } + virtual void destroyDecodedData(bool destroyAll = true) {} + virtual unsigned decodedSize() const { return 0; } + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); + virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, + const FloatPoint& phase, CompositeOperator, const FloatRect& destRect); + + const ImageBufferData* m_data; +}; + +void BufferedImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp) +{ + IntRect intDstRect = enclosingIntRect(dstRect); + IntRect intSrcRect(srcRect); + m_data->m_bitmap->draw(ctxt, intDstRect, intSrcRect, compositeOp); +} + +void BufferedImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRectIn, const TransformationMatrix& patternTransform, + const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) +{ + m_data->m_bitmap->drawPattern(ctxt, tileRectIn, patternTransform, phase, op, destRect, size()); +} + +ImageBufferData::ImageBufferData(const IntSize& size) +: m_bitmap(SharedBitmap::createInstance(false, size.width(), size.height(), false)) +{ + // http://www.w3.org/TR/2009/WD-html5-20090212/the-canvas-element.html#canvaspixelarray + // "When the canvas is initialized it must be set to fully transparent black." + m_bitmap->resetPixels(true); + m_bitmap->setHasAlpha(true); +} + +ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace colorSpace, bool& success) + : m_data(size) + , m_size(size) +{ + // FIXME: colorSpace is not used + UNUSED_PARAM(colorSpace); + + m_context.set(new GraphicsContext(0)); + m_context->setBitmap(m_data.m_bitmap); + success = true; +} + +ImageBuffer::~ImageBuffer() +{ +} + +GraphicsContext* ImageBuffer::context() const +{ + return m_context.get(); +} + +Image* ImageBuffer::image() const +{ + if (!m_image) + m_image = adoptRef(new BufferedImage(&m_data)); + + return m_image.get(); +} + +template <bool premultiplied> PassRefPtr<ImageData> +static getImageData(const IntRect& rect, const SharedBitmap* bitmap) +{ + PassRefPtr<ImageData> imageData = ImageData::create(rect.width(), rect.height()); + + const unsigned char* src = static_cast<const unsigned char*>(bitmap->bytes()); + if (!src) + return imageData; + + IntRect sourceRect(0, 0, bitmap->width(), bitmap->height()); + sourceRect.intersect(rect); + if (sourceRect.isEmpty()) + return imageData; + + unsigned char* dst = imageData->data()->data()->data(); + memset(dst, 0, imageData->data()->data()->length()); + src += (sourceRect.y() * bitmap->width() + sourceRect.x()) * 4; + dst += ((sourceRect.y() - rect.y()) * imageData->width() + sourceRect.x() - rect.x()) * 4; + int bytesToCopy = sourceRect.width() * 4; + int srcSkip = (bitmap->width() - sourceRect.width()) * 4; + int dstSkip = (imageData->width() - sourceRect.width()) * 4; + const unsigned char* dstEnd = dst + sourceRect.height() * imageData->width() * 4; + while (dst < dstEnd) { + const unsigned char* dstRowEnd = dst + bytesToCopy; + while (dst < dstRowEnd) { + // Convert ARGB little endian to RGBA big endian + int blue = *src++; + int green = *src++; + int red = *src++; + int alpha = *src++; + if (premultiplied) { + *dst++ = static_cast<unsigned char>((red * alpha + 254) / 255); + *dst++ = static_cast<unsigned char>((green * alpha + 254) / 255); + *dst++ = static_cast<unsigned char>((blue * alpha + 254) / 255); + *dst++ = static_cast<unsigned char>(alpha); + } else { + *dst++ = static_cast<unsigned char>(red); + *dst++ = static_cast<unsigned char>(green); + *dst++ = static_cast<unsigned char>(blue); + *dst++ = static_cast<unsigned char>(alpha); + ++src; + } + } + src += srcSkip; + dst += dstSkip; + } + + return imageData; +} + +PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const +{ + return getImageData<false>(rect, m_data.m_bitmap.get()); +} + +PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const +{ + return getImageData<true>(rect, m_data.m_bitmap.get()); +} + +template <bool premultiplied> +static void putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint, SharedBitmap* bitmap) +{ + unsigned char* dst = (unsigned char*)bitmap->bytes(); + if (!dst) + return; + + IntRect destRect(destPoint, sourceRect.size()); + destRect.intersect(IntRect(0, 0, bitmap->width(), bitmap->height())); + + if (destRect.isEmpty()) + return; + + const unsigned char* src = source->data()->data()->data(); + dst += (destRect.y() * bitmap->width() + destRect.x()) * 4; + src += (sourceRect.y() * source->width() + sourceRect.x()) * 4; + int bytesToCopy = destRect.width() * 4; + int dstSkip = (bitmap->width() - destRect.width()) * 4; + int srcSkip = (source->width() - destRect.width()) * 4; + const unsigned char* dstEnd = dst + destRect.height() * bitmap->width() * 4; + while (dst < dstEnd) { + const unsigned char* dstRowEnd = dst + bytesToCopy; + while (dst < dstRowEnd) { + // Convert RGBA big endian to ARGB little endian + int red = *src++; + int green = *src++; + int blue = *src++; + int alpha = *src++; + if (premultiplied) { + *dst++ = static_cast<unsigned char>(blue * 255 / alpha); + *dst++ = static_cast<unsigned char>(green * 255 / alpha); + *dst++ = static_cast<unsigned char>(red * 255 / alpha); + *dst++ = static_cast<unsigned char>(alpha); + } else { + *dst++ = static_cast<unsigned char>(blue); + *dst++ = static_cast<unsigned char>(green); + *dst++ = static_cast<unsigned char>(red); + *dst++ = static_cast<unsigned char>(alpha); + } + } + src += srcSkip; + dst += dstSkip; + } +} + +void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<false>(source, sourceRect, destPoint, m_data.m_bitmap.get()); +} + +void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + putImageData<true>(source, sourceRect, destPoint, m_data.m_bitmap.get()); +} + +String ImageBuffer::toDataURL(const String& mimeType) const +{ + if (!m_data.m_bitmap->bytes()) + return "data:,"; + + Vector<char> output; + const char* header; + if (mimeType.lower() == "image/png") { + if (!compressBitmapToPng(m_data.m_bitmap.get(), output)) + return "data:,"; + header = "data:image/png;base64,"; + } else { + if (!compressBitmapToJpeg(m_data.m_bitmap.get(), output)) + return "data:,"; + header = "data:image/jpeg;base64,"; + } + + Vector<char> base64; + base64Encode(output, base64); + + output.clear(); + + Vector<char> url; + url.append(header, strlen(header)); + url.append(base64); + + return String(url.data(), url.size()); +} + +} diff --git a/WebCore/platform/graphics/wince/MediaPlayerPrivateWince.h b/WebCore/platform/graphics/wince/MediaPlayerPrivateWince.h new file mode 100644 index 0000000..2d6c358 --- /dev/null +++ b/WebCore/platform/graphics/wince/MediaPlayerPrivateWince.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Torch Mobile 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 MediaPlayerPrivateWince_h +#define MediaPlayerPrivateWince_h + +#if ENABLE(VIDEO) + +#include "MediaPlayerPrivate.h" +#include "Timer.h" +#include <wtf/OwnPtr.h> + +namespace WebCore { + + class GraphicsContext; + class IntSize; + class IntRect; + class String; + + class MediaPlayerPrivate : public MediaPlayerPrivateInterface { + public: + static void registerMediaEngine(MediaEngineRegistrar); + + ~MediaPlayerPrivate(); + + IntSize naturalSize() const; + bool hasVideo() const; + + void load(const String& url); + void cancelLoad(); + + void play(); + void pause(); + + bool paused() const; + bool seeking() const; + + float duration() const; + float currentTime() const; + void seek(float time); + void setEndTime(float); + + void setRate(float); + void setVolume(float); + + int dataRate() const; + + MediaPlayer::NetworkState networkState() const { return m_networkState; } + MediaPlayer::ReadyState readyState() const { return m_readyState; } + + PassRefPtr<TimeRanges> buffered() const; + float maxTimeSeekable() const; + unsigned bytesLoaded() const; + bool totalBytesKnown() const; + unsigned totalBytes() const; + + void setVisible(bool); + void setSize(const IntSize&); + + void loadStateChanged(); + void didEnd(); + + void paint(GraphicsContext*, const IntRect&); + + private: + MediaPlayerPrivate(MediaPlayer*); + + void updateStates(); + void doSeek(); + void cancelSeek(); + void seekTimerFired(Timer<MediaPlayerPrivate>*); + float maxTimeLoaded() const; + void sawUnsupportedTracks(); +#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) + void setMediaPlayerProxy(WebMediaPlayerProxy*); + void setPoster(const String& url); + void deliverNotification(MediaPlayerProxyNotificationType); +#endif + + // engine support + static MediaPlayerPrivateInterface* create(MediaPlayer*); + static void getSupportedTypes(HashSet<String>& types); + static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); + static bool isAvailable(); + + MediaPlayer* m_player; + float m_seekTo; + float m_endTime; + Timer<MediaPlayerPrivate> m_seekTimer; + MediaPlayer::NetworkState m_networkState; + MediaPlayer::ReadyState m_readyState; + unsigned m_enabledTrackCount; + unsigned m_totalTrackCount; + bool m_hasUnsupportedTracks; + bool m_startedPlaying; + bool m_isStreaming; +#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) + WebMediaPlayerProxy* m_proxy; +#endif + }; + +} + +#endif + +#endif diff --git a/WebCore/platform/graphics/wince/MediaPlayerProxy.cpp b/WebCore/platform/graphics/wince/MediaPlayerProxy.cpp new file mode 100644 index 0000000..9673d18 --- /dev/null +++ b/WebCore/platform/graphics/wince/MediaPlayerProxy.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#if ENABLE(VIDEO) + +#include "config.h" +#include "MediaPlayerProxy.h" + +#include "c_class.h" +#include "c_instance.h" +#include "c_runtime.h" +#include "DocumentLoader.h" +#include "HTMLPlugInElement.h" +#include "HTMLVideoElement.h" +#include "JSDOMBinding.h" +#include "JSPluginElementFunctions.h" +#include "MediaPlayer.h" +#include "Node.h" +#include "npruntime_impl.h" +#include "PlatformString.h" +#include "PluginView.h" +#include "RenderPartObject.h" +#include "RenderWidget.h" +#include "runtime.h" +#include <runtime/Identifier.h> +#include "Widget.h" + +using namespace JSC; + +namespace WebCore { + +using namespace Bindings; +using namespace HTMLNames; + +WebMediaPlayerProxy::WebMediaPlayerProxy(MediaPlayer* player) + : m_mediaPlayer(player) + , m_init(false) + , m_hasSentResponseToPlugin(false) +{ + if (!m_init) + initEngine(); +} + +WebMediaPlayerProxy::~WebMediaPlayerProxy() +{ + m_instance.release(); +} + +ScriptInstance WebMediaPlayerProxy::pluginInstance() +{ + if (!m_instance) { + RenderObject* r = element()->renderer(); + if (!r || !r->isWidget()) + return 0; + + Frame* frame = element()->document()->frame(); + + RenderWidget* renderWidget = static_cast<RenderWidget*>(element()->renderer()); + if (renderWidget && renderWidget->widget()) + m_instance = frame->script()->createScriptInstanceForWidget(renderWidget->widget()); + } + + return m_instance; +} + +void WebMediaPlayerProxy::load(const String& url) +{ + if (!m_init) + initEngine(); + if (m_init) + invokeMethod("play"); +} + +void WebMediaPlayerProxy::initEngine() +{ + HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_mediaPlayer->mediaPlayerClient()); + String url = element->initialURL(); + + if (url.isEmpty()) + return; + + Frame* frame = element->document()->frame(); + Vector<String> paramNames; + Vector<String> paramValues; + String serviceType; + + // add all attributes set on the embed object + if (NamedNodeMap* attributes = element->attributes()) { + for (unsigned i = 0; i < attributes->length(); ++i) { + Attribute* it = attributes->attributeItem(i); + paramNames.append(it->name().localName().string()); + paramValues.append(it->value().string()); + } + } + serviceType = "application/x-mplayer2"; + frame->loader()->requestObject(static_cast<RenderPartObject*>(element->renderer()), url, nullAtom, serviceType, paramNames, paramValues); + m_init = true; + +} + +HTMLMediaElement* WebMediaPlayerProxy::element() +{ + return static_cast<HTMLMediaElement*>(m_mediaPlayer->mediaPlayerClient()); + +} + +void WebMediaPlayerProxy::invokeMethod(const String& methodName) +{ + Frame* frame = element()->document()->frame(); + RootObject *root = frame->script()->bindingRootObject(); + if (!root) + return; + ExecState *exec = root->globalObject()->globalExec(); + Instance* instance = pluginInstance().get(); + if (!instance) + return; + + instance->begin(); + Class *aClass = instance->getClass(); + Identifier iden(exec, methodName); + MethodList methodList = aClass->methodsNamed(iden, instance); + ArgList args; + instance->invokeMethod(exec, methodList , args); + instance->end(); +} + +} + +#endif diff --git a/WebCore/platform/graphics/wince/MediaPlayerProxy.h b/WebCore/platform/graphics/wince/MediaPlayerProxy.h new file mode 100644 index 0000000..05f9b21 --- /dev/null +++ b/WebCore/platform/graphics/wince/MediaPlayerProxy.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef MediaPlayerProxy_h +#define MediaPlayerProxy_h + +#if ENABLE(VIDEO) + +#include "ScriptInstance.h" + +namespace WebCore { + + class IntRect; + class IntSize; + class String; + class MediaPlayer; + class PluginView; + class HTMLMediaElement; + + enum MediaPlayerProxyNotificationType { + MediaPlayerNotificationPlayPauseButtonPressed, + Idle, + Loading, + Loaded, + FormatError, + NetworkError, + DecodeError + }; + + class WebMediaPlayerProxy { + public: + WebMediaPlayerProxy(MediaPlayer* player); + ~WebMediaPlayerProxy(); + + MediaPlayer* mediaPlayer() {return m_mediaPlayer;} + void initEngine(); + void load(const String& url); + HTMLMediaElement* element(); + void invokeMethod(const String& methodName); + ScriptInstance pluginInstance(); + + private: + MediaPlayer* m_mediaPlayer; + bool m_init; + WebCore::PluginView* m_pluginView; + bool m_hasSentResponseToPlugin; + ScriptInstance m_instance; + }; + +} +#endif // ENABLE(VIDEO) + +#endif diff --git a/WebCore/platform/graphics/wince/PathWince.cpp b/WebCore/platform/graphics/wince/PathWince.cpp new file mode 100644 index 0000000..7589ccb --- /dev/null +++ b/WebCore/platform/graphics/wince/PathWince.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2007-2009 Torch Mobile, 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 "Path.h" + +#include "FloatRect.h" +#include "NotImplemented.h" +#include "PlatformPathWince.h" +#include "PlatformString.h" +#include "TransformationMatrix.h" +#include <wtf/OwnPtr.h> + +namespace WebCore { + +Path::Path() + : m_path(new PlatformPath()) +{ +} + +Path::Path(const Path& other) + : m_path(new PlatformPath(*other.m_path)) +{ +} + +Path::~Path() +{ + delete m_path; +} + +Path& Path::operator=(const Path& other) +{ + if (&other != this) { + delete m_path; + m_path = new PlatformPath(*other.m_path); + } + return *this; +} + +bool Path::contains(const FloatPoint& point, WindRule rule) const +{ + return m_path->contains(point, rule); +} + +void Path::translate(const FloatSize& size) +{ + m_path->translate(size); +} + +FloatRect Path::boundingRect() const +{ + return m_path->boundingRect(); +} + +void Path::moveTo(const FloatPoint& point) +{ + m_path->moveTo(point); +} + +void Path::addLineTo(const FloatPoint& point) +{ + m_path->addLineTo(point); +} + +void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p) +{ + m_path->addQuadCurveTo(cp, p); +} + +void Path::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p) +{ + m_path->addBezierCurveTo(cp1, cp2, p); +} + +void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius) +{ + m_path->addArcTo(p1, p2, radius); +} + +void Path::closeSubpath() +{ + m_path->closeSubpath(); +} + +void Path::addArc(const FloatPoint& p, float r, float sar, float ear, bool anticlockwise) +{ + m_path->addEllipse(p, r, r, sar, ear, anticlockwise); +} + +void Path::addRect(const FloatRect& r) +{ + m_path->addRect(r); +} + +void Path::addEllipse(const FloatRect& r) +{ + m_path->addEllipse(r); +} + +void Path::clear() +{ + m_path->clear(); +} + +bool Path::isEmpty() const +{ + return m_path->isEmpty(); +} + +String Path::debugString() const +{ + return m_path->debugString(); +} + +void Path::apply(void* info, PathApplierFunction function) const +{ + m_path->apply(info, function); +} + +void Path::transform(const TransformationMatrix& t) +{ + m_path->transform(t); +} + +FloatRect Path::strokeBoundingRect(StrokeStyleApplier *) +{ + notImplemented(); + return FloatRect(); +} + +bool Path::strokeContains(StrokeStyleApplier*, const FloatPoint&) const +{ + notImplemented(); + return false; +} + +bool Path::hasCurrentPoint() const +{ + // Not sure if this is correct. At the meantime, we do what other ports + // do. + // See https://bugs.webkit.org/show_bug.cgi?id=27266, + // https://bugs.webkit.org/show_bug.cgi?id=27187, and + // http://trac.webkit.org/changeset/45873 + return !isEmpty(); +} + +} diff --git a/WebCore/platform/graphics/wince/PlatformPathWince.cpp b/WebCore/platform/graphics/wince/PlatformPathWince.cpp new file mode 100644 index 0000000..66fad50 --- /dev/null +++ b/WebCore/platform/graphics/wince/PlatformPathWince.cpp @@ -0,0 +1,810 @@ +/* + * Copyright (C) 2007-2009 Torch Mobile, 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 "PlatformPathWince.h" + +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "Path.h" +#include "PlatformString.h" +#include "TransformationMatrix.h" +#include "WinceGraphicsExtras.h" +#include <wtf/MathExtras.h> +#include <wtf/OwnPtr.h> + +#include <windows.h> + +namespace WebCore { + +// Implemented in GraphicsContextWince.cpp +void getEllipsePointByAngle(double angle, double a, double b, float& x, float& y); + +static void quadCurve(int segments, Vector<PathPoint>& pts, const PathPoint* control) +{ + const float step = 1.0 / segments; + register float tA = 0.0; + register float tB = 1.0; + + float c1x = control[0].x(); + float c1y = control[0].y(); + float c2x = control[1].x(); + float c2y = control[1].y(); + float c3x = control[2].x(); + float c3y = control[2].y(); + + const int offset = pts.size(); + pts.resize(offset + segments); + PathPoint pp; + pp.m_x = c1x; + pp.m_y = c1y; + + for (int i = 1; i < segments; ++i) { + tA += step; + tB -= step; + + const float a = tB * tB; + const float b = 2.0 * tA * tB; + const float c = tA * tA; + + pp.m_x = c1x * a + c2x * b + c3x * c; + pp.m_y = c1y * a + c2y * b + c3y * c; + + pts[offset + i - 1] = pp; + } + + pp.m_x = c3x; + pp.m_y = c3y; + pts[offset + segments - 1] = pp; +} + +static inline void bezier(int segments, Vector<PathPoint>& pts, const PathPoint* control) +{ + const float step = 1.0 / segments; + register float tA = 0.0; + register float tB = 1.0; + + float c1x = control[0].x(); + float c1y = control[0].y(); + float c2x = control[1].x(); + float c2y = control[1].y(); + float c3x = control[2].x(); + float c3y = control[2].y(); + float c4x = control[3].x(); + float c4y = control[3].y(); + + const int offset = pts.size(); + pts.resize(offset + segments); + PathPoint pp; + pp.m_x = c1x; + pp.m_y = c1y; + + for (int i = 1; i < segments; ++i) { + tA += step; + tB -= step; + const float tAsq = tA * tA; + const float tBsq = tB * tB; + + const float a = tBsq * tB; + const float b = 3.0 * tA * tBsq; + const float c = 3.0 * tB * tAsq; + const float d = tAsq * tA; + + pp.m_x = c1x * a + c2x * b + c3x * c + c4x * d; + pp.m_y = c1y * a + c2y * b + c3y * c + c4y * d; + + pts[offset + i - 1] = pp; + } + + pp.m_x = c4x; + pp.m_y = c4y; + pts[offset + segments - 1] = pp; +} + +static bool containsPoint(const FloatRect& r, const FloatPoint& p) +{ + return p.x() >= r.x() && p.y() >= r.y() && p.x() < r.right() && p.y() < r.bottom(); +} + +static void normalizeAngle(float& angle) +{ + angle = fmod(angle, 2 * piFloat); + if (angle < 0) + angle += 2 * piFloat; + if (angle < 0.00001f) + angle = 0; +} + +static void transformArcPoint(float& x, float& y, const FloatPoint& c) +{ + x += c.x(); + y += c.y(); +} + +static void inflateRectToContainPoint(FloatRect& r, float x, float y) +{ + if (r.isEmpty()) { + r.setX(x); + r.setY(y); + r.setSize(FloatSize(1, 1)); + return; + } + if (x < r.x()) { + r.setWidth(r.right() - x); + r.setX(x); + } else { + float w = x - r.x() + 1; + if (w > r.width()) + r.setWidth(w); + } + if (y < r.y()) { + r.setHeight(r.bottom() - y); + r.setY(y); + } else { + float h = y - r.y() + 1; + if (h > r.height()) + r.setHeight(h); + } +} + +// return 0-based value: 0 - first Quadrant ( 0 - 90 degree) +static inline int quadrant(const PathPoint& point, const PathPoint& origin) +{ + return point.m_x < origin.m_x ? + (point.m_y < origin.m_y ? 2 : 1) + : (point.m_y < origin.m_y ? 3 : 0); +} + +static inline bool isQuadrantOnLeft(int q) { return q == 1 || q == 2; } +static inline bool isQuadrantOnRight(int q) { return q == 0 || q == 3; } +static inline bool isQuadrantOnTop(int q) { return q == 2 || q == 3; } +static inline bool isQuadrantOnBottom(int q) { return q == 0 || q == 1; } + +static inline int nextQuadrant(int q) { return q == 3 ? 0 : q + 1; } +static inline int quadrantDiff(int q1, int q2) +{ + int d = q1 - q2; + while (d < 0) + d += 4; + return d; +} + +struct PathVector { + float m_x; + float m_y; + + PathVector() : m_x(0), m_y(0) {} + PathVector(float x, float y) : m_x(x), m_y(y) {} + double angle() const { return atan2(m_y, m_x); } + operator double () const { return angle(); } + double length() const { return _hypot(m_x, m_y); } +}; + +PathVector operator-(const PathPoint& p1, const PathPoint& p2) +{ + return PathVector(p1.m_x - p2.m_x, p1.m_y - p2.m_y); +} + +static void addArcPoint(PathPolygon& poly, const PathPoint& center, const PathPoint& radius, double angle) +{ + PathPoint p; + getEllipsePointByAngle(angle, radius.m_x, radius.m_y, p.m_x, p.m_y); + transformArcPoint(p.m_x, p.m_y, center); + if (poly.isEmpty() || poly.last() != p) + poly.append(p); +} + +static void addArcPoints(PathPolygon& poly, const PlatformPathElement::ArcTo& data) +{ + const PathPoint& startPoint = poly.last(); + double curAngle = startPoint - data.m_center; + double endAngle = data.m_end - data.m_center; + double angleStep = 2. / std::max(data.m_radius.m_x, data.m_radius.m_y); + if (data.m_clockwise) { + if (endAngle <= curAngle || startPoint == data.m_end) + endAngle += 2 * piDouble; + } else { + angleStep = -angleStep; + if (endAngle >= curAngle || startPoint == data.m_end) + endAngle -= 2 * piDouble; + } + + for (curAngle += angleStep; data.m_clockwise ? curAngle < endAngle : curAngle > endAngle; curAngle += angleStep) + addArcPoint(poly, data.m_center, data.m_radius, curAngle); + + if (poly.isEmpty() || poly.last() != data.m_end) + poly.append(data.m_end); +} + +static void drawPolygons(HDC dc, const Vector<PathPolygon>& polygons, bool fill, const TransformationMatrix* transformation) +{ + MemoryAllocationCanFail canFail; + for (Vector<PathPolygon>::const_iterator i = polygons.begin(); i != polygons.end(); ++i) { + int npoints = i->size(); + if (!npoints) + continue; + + POINT* winPoints = 0; + if (fill) { + if (npoints > 2) + winPoints = new POINT[npoints + 1]; + } else + winPoints = new POINT[npoints]; + + if (winPoints) { + if (transformation) { + for (int i2 = 0; i2 < npoints; ++i2) { + FloatPoint trPoint = transformation->mapPoint(i->at(i2)); + winPoints[i2].x = stableRound(trPoint.x()); + winPoints[i2].y = stableRound(trPoint.y()); + } + } else { + for (int i2 = 0; i2 < npoints; ++i2) { + winPoints[i2].x = stableRound(i->at(i2).x()); + winPoints[i2].y = stableRound(i->at(i2).y()); + } + } + + if (fill && winPoints[npoints - 1] != winPoints[0]) { + winPoints[npoints].x = winPoints[0].x; + winPoints[npoints].y = winPoints[0].y; + ++npoints; + } + + if (fill) + ::Polygon(dc, winPoints, npoints); + else + ::Polyline(dc, winPoints, npoints); + delete[] winPoints; + } + } +} + + +int PlatformPathElement::numControlPoints() const +{ + switch (m_type) { + case PathMoveTo: + case PathLineTo: + return 1; + case PathQuadCurveTo: + case PathArcTo: + return 2; + case PathBezierCurveTo: + return 3; + default: + ASSERT(m_type == PathCloseSubpath); + return 0; + } +} + +int PlatformPathElement::numPoints() const +{ + switch (m_type) { + case PathMoveTo: + case PathLineTo: + case PathArcTo: + return 1; + case PathQuadCurveTo: + return 2; + case PathBezierCurveTo: + return 3; + default: + ASSERT(m_type == PathCloseSubpath); + return 0; + } +} + +void PathPolygon::move(const FloatSize& offset) +{ + for (Vector<PathPoint>::iterator i = begin(); i < end(); ++i) + i->move(offset); +} + +void PathPolygon::transform(const TransformationMatrix& t) +{ + for (Vector<PathPoint>::iterator i = begin(); i < end(); ++i) + *i = t.mapPoint(*i); +} + +bool PathPolygon::contains(const FloatPoint& point) const +{ + if (size() < 3) + return false; + + // Test intersections between the polygon and the vertical line: x = point.x() + + int intersected = 0; + const PathPoint* point1 = &last(); + Vector<PathPoint>::const_iterator last = end(); + // wasNegative: -1 means unknown, 0 means false, 1 means true. + int wasNegative = -1; + for (Vector<PathPoint>::const_iterator i = begin(); i != last; ++i) { + const PathPoint& point2 = *i; + if (point1->x() != point.x()) { + if (point2.x() == point.x()) { + // We are getting on the vertical line + wasNegative = point1->x() < point.x() ? 1 : 0; + } else if (point2.x() < point.x() != point1->x() < point.x()) { + float y = (point2.y() - point1->y()) / (point2.x() - point1->x()) * (point.x() - point1->x()) + point1->y(); + if (y >= point.y()) + ++intersected; + } + } else { + // We were on the vertical line + + // handle special case + if (point1->y() == point.y()) + return true; + + if (point1->y() > point.y()) { + if (point2.x() == point.x()) { + // see if the point is on this segment + if (point2.y() <= point.y()) + return true; + + // We are still on the line + } else { + // We are leaving the line now. + // We have to get back to see which side we come from. If we come from + // the same side we are leaving, no intersection should be counted + if (wasNegative < 0) { + Vector<PathPoint>::const_iterator jLast = i; + Vector<PathPoint>::const_iterator j = i; + do { + if (j == begin()) + j = last; + else + --j; + if (j->x() != point.x()) { + if (j->x() > point.x()) + wasNegative = 0; + else + wasNegative = 1; + break; + } + } while (j != jLast); + + if (wasNegative < 0) + return false; + } + if (wasNegative ? point2.x() > point.x() : point2.x() < point.x()) + ++intersected; + } + } else if (point2.x() == point.x() && point2.y() >= point.y()) + return true; + } + point1 = &point2; + } + + return intersected & 1; +} + +void PlatformPathElement::move(const FloatSize& offset) +{ + int n = numControlPoints(); + for (int i = 0; i < n; ++i) + m_data.m_points[i].move(offset); +} + +void PlatformPathElement::transform(const TransformationMatrix& t) +{ + int n = numControlPoints(); + for (int i = 0; i < n; ++i) { + FloatPoint p = t.mapPoint(m_data.m_points[i]); + m_data.m_points[i].set(p.x(), p.y()); + } +} + +void PlatformPathElement::inflateRectToContainMe(FloatRect& r, const FloatPoint& lastPoint) const +{ + if (m_type == PathArcTo) { + const ArcTo& data = m_data.m_arcToData; + PathPoint startPoint; + startPoint = lastPoint; + PathPoint endPoint = data.m_end; + if (!data.m_clockwise) + std::swap(startPoint, endPoint); + + int q0 = quadrant(startPoint, data.m_center); + int q1 = quadrant(endPoint, data.m_center); + bool containsExtremes[4] = { false }; // bottom, left, top, right + static const PathPoint extremeVectors[4] = { { 0, 1 }, { -1, 0 }, { 0, -1 }, { 1, 0 } }; + if (q0 == q1) { + if (startPoint.m_x == endPoint.m_x || isQuadrantOnBottom(q0) != startPoint.m_x > endPoint.m_x) { + for (int i = 0; i < 4; ++i) + containsExtremes[i] = true; + } + } else { + int extreme = q0; + int diff = quadrantDiff(q1, q0); + for (int i = 0; i < diff; ++i) { + containsExtremes[extreme] = true; + extreme = nextQuadrant(extreme); + } + } + + inflateRectToContainPoint(r, startPoint.m_x, startPoint.m_y); + inflateRectToContainPoint(r, endPoint.m_x, endPoint.m_y); + for (int i = 0; i < 4; ++i) { + if (containsExtremes[i]) + inflateRectToContainPoint(r, data.m_center.m_x + data.m_radius.m_x * extremeVectors[i].m_x, data.m_center.m_y + data.m_radius.m_y * extremeVectors[i].m_y); + } + } else { + int n = numPoints(); + for (int i = 0; i < n; ++i) + inflateRectToContainPoint(r, m_data.m_points[i].m_x, m_data.m_points[i].m_y); + } +} + +PathElementType PlatformPathElement::type() const +{ + switch (m_type) { + case PathMoveTo: + return PathElementMoveToPoint; + case PathLineTo: + return PathElementAddLineToPoint; + case PathArcTo: + // FIXME: there's no arcTo type for PathElement + return PathElementAddLineToPoint; + // return PathElementAddQuadCurveToPoint; + case PathQuadCurveTo: + return PathElementAddQuadCurveToPoint; + case PathBezierCurveTo: + return PathElementAddCurveToPoint; + default: + ASSERT(m_type == PathCloseSubpath); + return PathElementCloseSubpath; + } +} + +PlatformPath::PlatformPath() + : m_penLifted(true) +{ + m_currentPoint.clear(); +} + +void PlatformPath::ensureSubpath() +{ + if (m_penLifted) { + m_penLifted = false; + m_subpaths.append(PathPolygon()); + m_subpaths.last().append(m_currentPoint); + } else + ASSERT(!m_subpaths.isEmpty()); +} + +void PlatformPath::addToSubpath(const PlatformPathElement& e) +{ + if (e.platformType() == PlatformPathElement::PathMoveTo) { + m_penLifted = true; + m_currentPoint = e.pointAt(0); + } else if (e.platformType() == PlatformPathElement::PathCloseSubpath) { + m_penLifted = true; + if (!m_subpaths.isEmpty()) { + if (m_currentPoint != m_subpaths.last()[0]) { + // According to W3C, we have to draw a line from current point to the initial point + m_subpaths.last().append(m_subpaths.last()[0]); + m_currentPoint = m_subpaths.last()[0]; + } + } else + m_currentPoint.clear(); + } else { + ensureSubpath(); + switch (e.platformType()) { + case PlatformPathElement::PathLineTo: + m_subpaths.last().append(e.pointAt(0)); + break; + case PlatformPathElement::PathArcTo: + addArcPoints(m_subpaths.last(), e.arcTo()); + break; + case PlatformPathElement::PathQuadCurveTo: + { + PathPoint control[] = { + m_currentPoint, + e.pointAt(0), + e.pointAt(1), + }; + // FIXME: magic number? + quadCurve(50, m_subpaths.last(), control); + } + break; + case PlatformPathElement::PathBezierCurveTo: + { + PathPoint control[] = { + m_currentPoint, + e.pointAt(0), + e.pointAt(1), + e.pointAt(2), + }; + // FIXME: magic number? + bezier(100, m_subpaths.last(), control); + } + break; + default: + ASSERT_NOT_REACHED(); + break; + } + m_currentPoint = m_subpaths.last().last(); + } +} + +void PlatformPath::append(const PlatformPathElement& e) +{ + e.inflateRectToContainMe(m_boundingRect, lastPoint()); + addToSubpath(e); + m_elements.append(e); +} + +void PlatformPath::append(const PlatformPath& p) +{ + const PlatformPathElements& e = p.elements(); + for (PlatformPathElements::const_iterator it(e.begin()); it != e.end(); ++it) { + addToSubpath(*it); + it->inflateRectToContainMe(m_boundingRect, lastPoint()); + m_elements.append(*it); + } +} + +void PlatformPath::clear() +{ + m_elements.clear(); + m_boundingRect = FloatRect(); + m_subpaths.clear(); + m_currentPoint.clear(); + m_penLifted = true; +} + +void PlatformPath::strokePath(HDC dc, const TransformationMatrix* transformation) const +{ + drawPolygons(dc, m_subpaths, false, transformation); +} + +void PlatformPath::fillPath(HDC dc, const TransformationMatrix* transformation) const +{ + HGDIOBJ oldPen = SelectObject(dc, GetStockObject(NULL_PEN)); + drawPolygons(dc, m_subpaths, true, transformation); + SelectObject(dc, oldPen); +} + +void PlatformPath::translate(const FloatSize& size) +{ + for (PlatformPathElements::iterator it(m_elements.begin()); it != m_elements.end(); ++it) + it->move(size); + + m_boundingRect.move(size); + for (Vector<PathPolygon>::iterator it = m_subpaths.begin(); it != m_subpaths.end(); ++it) + it->move(size); +} + +void PlatformPath::transform(const TransformationMatrix& t) +{ + for (PlatformPathElements::iterator it(m_elements.begin()); it != m_elements.end(); ++it) + it->transform(t); + + m_boundingRect = t.mapRect(m_boundingRect); + for (Vector<PathPolygon>::iterator it = m_subpaths.begin(); it != m_subpaths.end(); ++it) + it->transform(t); +} + +bool PlatformPath::contains(const FloatPoint& point, WindRule rule) const +{ + // optimization: check the bounding rect first + if (!containsPoint(m_boundingRect, point)) + return false; + + for (Vector<PathPolygon>::const_iterator i = m_subpaths.begin(); i != m_subpaths.end(); ++i) { + if (i->contains(point)) + return true; + } + + return false; +} + +void PlatformPath::moveTo(const FloatPoint& point) +{ + PlatformPathElement::MoveTo data = { { point.x(), point.y() } }; + PlatformPathElement pe(data); + append(pe); +} + +void PlatformPath::addLineTo(const FloatPoint& point) +{ + PlatformPathElement::LineTo data = { { point.x(), point.y() } }; + PlatformPathElement pe(data); + append(pe); +} + +void PlatformPath::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p) +{ + PlatformPathElement::QuadCurveTo data = { { cp.x(), cp.y() }, { p.x(), p.y() } }; + PlatformPathElement pe(data); + append(pe); +} + +void PlatformPath::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p) +{ + PlatformPathElement::BezierCurveTo data = { { cp1.x(), cp1.y() }, { cp2.x(), cp2.y() }, { p.x(), p.y() } }; + PlatformPathElement pe(data); + append(pe); +} + +void PlatformPath::addArcTo(const FloatPoint& fp1, const FloatPoint& fp2, float radius) +{ + const PathPoint& p0 = m_currentPoint; + PathPoint p1; + p1 = fp1; + PathPoint p2; + p2 = fp2; + if (!radius || p0 == p1 || p1 == p2) { + addLineTo(p1); + return; + } + + PathVector v01 = p0 - p1; + PathVector v21 = p2 - p1; + + // sin(A - B) = sin(A) * cos(B) - sin(B) * cos(A) + double cross = v01.m_x * v21.m_y - v01.m_y * v21.m_x; + + if (fabs(cross) < 1E-10) { + // on one line + addLineTo(p1); + return; + } + + double d01 = v01.length(); + double d21 = v21.length(); + double angle = (piDouble - abs(asin(cross / (d01 * d21)))) * 0.5; + double span = radius * tan(angle); + double rate = span / d01; + PathPoint startPoint; + startPoint.m_x = p1.m_x + v01.m_x * rate; + startPoint.m_y = p1.m_y + v01.m_y * rate; + + addLineTo(startPoint); + + PathPoint endPoint; + rate = span / d21; + endPoint.m_x = p1.m_x + v21.m_x * rate; + endPoint.m_y = p1.m_y + v21.m_y * rate; + + PathPoint midPoint; + midPoint.m_x = (startPoint.m_x + endPoint.m_x) * 0.5; + midPoint.m_y = (startPoint.m_y + endPoint.m_y) * 0.5; + + PathVector vm1 = midPoint - p1; + double dm1 = vm1.length(); + double d = _hypot(radius, span); + + PathPoint centerPoint; + rate = d / dm1; + centerPoint.m_x = p1.m_x + vm1.m_x * rate; + centerPoint.m_y = p1.m_y + vm1.m_y * rate; + + PlatformPathElement::ArcTo data = { + endPoint, + centerPoint, + { radius, radius }, + cross < 0 + }; + PlatformPathElement pe(data); + append(pe); +} + +void PlatformPath::closeSubpath() +{ + PlatformPathElement pe; + append(pe); +} + +// add a circular arc centred at p with radius r from start angle sar (radians) to end angle ear +void PlatformPath::addEllipse(const FloatPoint& p, float a, float b, float sar, float ear, bool anticlockwise) +{ + float startX, startY, endX, endY; + + normalizeAngle(sar); + normalizeAngle(ear); + + getEllipsePointByAngle(sar, a, b, startX, startY); + getEllipsePointByAngle(ear, a, b, endX, endY); + + transformArcPoint(startX, startY, p); + transformArcPoint(endX, endY, p); + + FloatPoint start(startX, startY); + moveTo(start); + + PlatformPathElement::ArcTo data = { { endX, endY }, { p.x(), p.y() }, { a, b }, !anticlockwise }; + PlatformPathElement pe(data); + append(pe); +} + + +void PlatformPath::addRect(const FloatRect& r) +{ + moveTo(r.location()); + + float right = r.right() - 1; + float bottom = r.bottom() - 1; + addLineTo(FloatPoint(right, r.y())); + addLineTo(FloatPoint(right, bottom)); + addLineTo(FloatPoint(r.x(), bottom)); + addLineTo(r.location()); +} + +void PlatformPath::addEllipse(const FloatRect& r) +{ + FloatSize radius(r.width() * 0.5, r.height() * 0.5); + addEllipse(r.location() + radius, radius.width(), radius.height(), 0, 0, true); +} + +String PlatformPath::debugString() const +{ + String ret; + for (PlatformPathElements::const_iterator i(m_elements.begin()); i != m_elements.end(); ++i) { + switch (i->platformType()) { + case PlatformPathElement::PathMoveTo: + case PlatformPathElement::PathLineTo: + ret += String::format("M %f %f\n", i->pointAt(0).m_x, i->pointAt(0).m_y); + break; + case PlatformPathElement::PathArcTo: + ret += String::format("A %f %f %f %f %f %f %c\n" + , i->arcTo().m_end.m_x, i->arcTo().m_end.m_y + , i->arcTo().m_center.m_x, i->arcTo().m_center.m_y + , i->arcTo().m_radius.m_x, i->arcTo().m_radius.m_y + , i->arcTo().m_clockwise? 'Y' : 'N'); + break; + case PlatformPathElement::PathQuadCurveTo: + ret += String::format("Q %f %f %f %f\n" + , i->pointAt(0).m_x, i->pointAt(0).m_y + , i->pointAt(1).m_x, i->pointAt(1).m_y); + break; + case PlatformPathElement::PathBezierCurveTo: + ret += String::format("B %f %f %f %f %f %f\n" + , i->pointAt(0).m_x, i->pointAt(0).m_y + , i->pointAt(1).m_x, i->pointAt(1).m_y + , i->pointAt(2).m_x, i->pointAt(2).m_y); + break; + default: + ASSERT(i->platformType() == PlatformPathElement::PathCloseSubpath); + ret += "S\n"; + break; + } + } + + return ret; +} + +void PlatformPath::apply(void* info, PathApplierFunction function) const +{ + PathElement pelement; + FloatPoint points[3]; + pelement.points = points; + + for (PlatformPathElements::const_iterator it(m_elements.begin()); it != m_elements.end(); ++it) { + pelement.type = it->type(); + int n = it->numPoints(); + for (int i = 0; i < n; ++i) + points[i] = it->pointAt(i); + function(info, &pelement); + } +} + +} // namespace Webcore diff --git a/WebCore/platform/graphics/wince/PlatformPathWince.h b/WebCore/platform/graphics/wince/PlatformPathWince.h new file mode 100644 index 0000000..fca00a7 --- /dev/null +++ b/WebCore/platform/graphics/wince/PlatformPathWince.h @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2007-2009 Torch Mobile, 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. + */ + +#ifndef PlatformPathWince_h +#define PlatformPathWince_h + +namespace WebCore { + + class GraphicsContext; + + struct PathPoint { + float m_x; + float m_y; + const float& x() const { return m_x; } + const float& y() const { return m_y; } + void set(float x, float y) + { + m_x = x; + m_y = y; + }; + operator FloatPoint() const { return FloatPoint(m_x, m_y); } + void move(const FloatSize& offset) + { + m_x += offset.width(); + m_y += offset.height(); + } + PathPoint& operator=(const FloatPoint& p) + { + m_x = p.x(); + m_y = p.y(); + return *this; + } + void clear() { m_x = m_y = 0; } + }; + + struct PathPolygon: public Vector<PathPoint> { + void move(const FloatSize& offset); + void transform(const TransformationMatrix& t); + bool contains(const FloatPoint& point) const; + }; + + class PlatformPathElement { + public: + enum PlaformPathElementType { + PathMoveTo, + PathLineTo, + PathArcTo, + PathQuadCurveTo, + PathBezierCurveTo, + PathCloseSubpath, + }; + + struct MoveTo { + PathPoint m_end; + }; + + struct LineTo { + PathPoint m_end; + }; + + struct ArcTo { + PathPoint m_end; + PathPoint m_center; + PathPoint m_radius; + bool m_clockwise; + }; + + struct QuadCurveTo { + PathPoint m_point0; + PathPoint m_point1; + }; + + struct BezierCurveTo { + PathPoint m_point0; + PathPoint m_point1; + PathPoint m_point2; + }; + + PlatformPathElement(): m_type(PathCloseSubpath) { m_data.m_points[0].set(0, 0); } + PlatformPathElement(const MoveTo& data): m_type(PathMoveTo) { m_data.m_moveToData = data; } + PlatformPathElement(const LineTo& data): m_type(PathLineTo) { m_data.m_lineToData = data; } + PlatformPathElement(const ArcTo& data): m_type(PathArcTo) { m_data.m_arcToData = data; } + PlatformPathElement(const QuadCurveTo& data): m_type(PathQuadCurveTo) { m_data.m_quadCurveToData = data; } + PlatformPathElement(const BezierCurveTo& data): m_type(PathBezierCurveTo) { m_data.m_bezierCurveToData = data; } + + const MoveTo& moveTo() const { return m_data.m_moveToData; } + const LineTo& lineTo() const { return m_data.m_lineToData; } + const ArcTo& arcTo() const { return m_data.m_arcToData; } + const QuadCurveTo& quadCurveTo() const { return m_data.m_quadCurveToData; } + const BezierCurveTo& bezierCurveTo() const { return m_data.m_bezierCurveToData; } + const PathPoint& lastPoint() const + { + int n = numPoints(); + return n > 1 ? m_data.m_points[n - 1] : m_data.m_points[0]; + } + const PathPoint& pointAt(int index) const { return m_data.m_points[index]; } + int numPoints() const; + int numControlPoints() const; + void move(const FloatSize& offset); + void transform(const TransformationMatrix& t); + PathElementType type() const; + PlaformPathElementType platformType() const { return m_type; } + void inflateRectToContainMe(FloatRect& r, const FloatPoint& lastPoint) const; + + private: + PlaformPathElementType m_type; + union { + MoveTo m_moveToData; + LineTo m_lineToData; + ArcTo m_arcToData; + QuadCurveTo m_quadCurveToData; + BezierCurveTo m_bezierCurveToData; + PathPoint m_points[4]; + } m_data; + }; + + typedef Vector<PlatformPathElement> PlatformPathElements; + + class PlatformPath { + public: + PlatformPath(); + const PlatformPathElements& elements() const { return m_elements; } + void append(const PlatformPathElement& e); + void append(const PlatformPath& p); + void clear(); + bool isEmpty() const { return m_elements.isEmpty(); } + + void strokePath(HDC, const TransformationMatrix* tr) const; + void fillPath(HDC, const TransformationMatrix* tr) const; + FloatPoint lastPoint() const { return m_elements.isEmpty() ? FloatPoint(0, 0) : m_elements.last().lastPoint(); } + + const FloatRect& boundingRect() const { return m_boundingRect; } + bool contains(const FloatPoint& point, WindRule rule) const; + void translate(const FloatSize& size); + void transform(const TransformationMatrix& t); + + void moveTo(const FloatPoint&); + void addLineTo(const FloatPoint&); + void addQuadCurveTo(const FloatPoint& controlPoint, const FloatPoint& point); + void addBezierCurveTo(const FloatPoint& controlPoint1, const FloatPoint& controlPoint2, const FloatPoint&); + void addArcTo(const FloatPoint&, const FloatPoint&, float radius); + void closeSubpath(); + void addEllipse(const FloatPoint& p, float a, float b, float sar, float ear, bool anticlockwise); + void addRect(const FloatRect& r); + void addEllipse(const FloatRect& r); + String debugString() const; + void apply(void* info, PathApplierFunction function) const; + + private: + void ensureSubpath(); + void addToSubpath(const PlatformPathElement& e); + + PlatformPathElements m_elements; + FloatRect m_boundingRect; + Vector<PathPolygon> m_subpaths; + PathPoint m_currentPoint; + bool m_penLifted; + }; + +} + +#endif // PlatformPathWince_h diff --git a/WebCore/platform/graphics/wince/WinceGraphicsExtras.h b/WebCore/platform/graphics/wince/WinceGraphicsExtras.h new file mode 100644 index 0000000..2a6fae1 --- /dev/null +++ b/WebCore/platform/graphics/wince/WinceGraphicsExtras.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2007-2009 Torch Mobile, 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. + */ + +#ifndef WinceGraphicsExtras_h +#define WinceGraphicsExtras_h + +// This file is used to contain small utilities used by WINCE graphics code. + +namespace WebCore { + // Always round to same direction. 0.5 is rounded to 1, + // and -0.5 (0.5 - 1) is rounded to 0 (1 - 1), so that it + // is consistent when transformation shifts. + static inline int stableRound(double d) + { + if (d > 0) + return static_cast<int>(d + 0.5); + + int i = static_cast<int>(d); + return i - d > 0.5 ? i - 1 : i; + } +} + +#endif WinceGraphicsExtras_h diff --git a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp index 59e388e..686fb07 100644 --- a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp +++ b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp @@ -506,4 +506,59 @@ void GraphicsContext::fillRect(const FloatRect& rect) return; } +void GraphicsContext::setPlatformShadow(IntSize const&,int,Color const&) +{ + notImplemented(); +} + +void GraphicsContext::clearPlatformShadow() +{ + notImplemented(); +} + +void GraphicsContext::beginTransparencyLayer(float) +{ + notImplemented(); +} + +void GraphicsContext::endTransparencyLayer() +{ + notImplemented(); +} + +void GraphicsContext::clearRect(const FloatRect&) +{ + notImplemented(); +} + +void GraphicsContext::strokeRect(const FloatRect&, float) +{ + notImplemented(); +} + +void GraphicsContext::setLineCap(LineCap) +{ + notImplemented(); +} + +void GraphicsContext::setLineJoin(LineJoin) +{ + notImplemented(); +} + +void GraphicsContext::setMiterLimit(float) +{ + notImplemented(); +} + +void GraphicsContext::setAlpha(float) +{ + notImplemented(); +} + +void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) +{ + notImplemented(); +} + } diff --git a/WebCore/platform/graphics/wx/IconWx.cpp b/WebCore/platform/graphics/wx/IconWx.cpp new file mode 100644 index 0000000..e82091e --- /dev/null +++ b/WebCore/platform/graphics/wx/IconWx.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "Icon.h" + +#include "GraphicsContext.h" +#include "PlatformString.h" +#include "IntRect.h" +#include "NotImplemented.h" + +namespace WebCore { + +Icon::~Icon() +{ +} + +PassRefPtr<Icon> Icon::createIconForFile(const String& filename) +{ + notImplemented(); + return 0; +} + +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) +{ + notImplemented(); + return 0; +} + +void Icon::paint(GraphicsContext* ctx, const IntRect& rect) +{ + notImplemented(); +} + +} + diff --git a/WebCore/platform/graphics/wx/ImageBufferWx.cpp b/WebCore/platform/graphics/wx/ImageBufferWx.cpp index e71dbde..49f3f3b 100644 --- a/WebCore/platform/graphics/wx/ImageBufferWx.cpp +++ b/WebCore/platform/graphics/wx/ImageBufferWx.cpp @@ -53,13 +53,24 @@ GraphicsContext* ImageBuffer::context() const return 0; } -PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect&) const +PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const { notImplemented(); return 0; } -void ImageBuffer::putImageData(ImageData*, const IntRect&, const IntPoint&) +PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const +{ + notImplemented(); + return 0; +} + +void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) +{ + notImplemented(); +} + +void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint) { notImplemented(); } diff --git a/WebCore/platform/graphics/wx/ImageSourceWx.cpp b/WebCore/platform/graphics/wx/ImageSourceWx.cpp deleted file mode 100644 index 06c165d..0000000 --- a/WebCore/platform/graphics/wx/ImageSourceWx.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (C) 2006, 2007 Apple Computer, Kevin Ollivier. 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 "ImageSource.h" - -#include "BMPImageDecoder.h" -#include "GIFImageDecoder.h" -#include "ICOImageDecoder.h" -#include "JPEGImageDecoder.h" -#include "NotImplemented.h" -#include "PNGImageDecoder.h" -#include "SharedBuffer.h" -#include "XBMImageDecoder.h" - -#include <wx/defs.h> -#include <wx/bitmap.h> -#if USE(WXGC) -#include <wx/graphics.h> -#endif -#include <wx/image.h> -#include <wx/rawbmp.h> - -namespace WebCore { - -ImageDecoder* createDecoder(const SharedBuffer& data) -{ - // We need at least 4 bytes to figure out what kind of image we're dealing with. - int length = data.size(); - if (length < 4) - return 0; - - const unsigned char* uContents = (const unsigned char*)data.data(); - const char* contents = data.data(); - - // GIFs begin with GIF8(7 or 9). - if (strncmp(contents, "GIF8", 4) == 0) - return new GIFImageDecoder(); - - // Test for PNG. - if (uContents[0]==0x89 && - uContents[1]==0x50 && - uContents[2]==0x4E && - uContents[3]==0x47) - return new PNGImageDecoder(); - - // JPEG - if (uContents[0]==0xFF && - uContents[1]==0xD8 && - uContents[2]==0xFF) - return new JPEGImageDecoder(); - - // BMP - if (strncmp(contents, "BM", 2) == 0) - return new BMPImageDecoder(); - - // ICOs always begin with a 2-byte 0 followed by a 2-byte 1. - // CURs begin with 2-byte 0 followed by 2-byte 2. - if (!memcmp(contents, "\000\000\001\000", 4) || - !memcmp(contents, "\000\000\002\000", 4)) - return new ICOImageDecoder(); - - // XBMs require 8 bytes of info. - if (length >= 8 && strncmp(contents, "#define ", 8) == 0) - return new XBMImageDecoder(); - - // Give up. We don't know what the heck this is. - return 0; -} - -ImageSource::ImageSource() - : m_decoder(0) -{} - -ImageSource::~ImageSource() -{ - clear(true); -} - -bool ImageSource::initialized() const -{ - return m_decoder; -} - -void ImageSource::setData(SharedBuffer* data, bool allDataReceived) -{ - // Make the decoder by sniffing the bytes. - // This method will examine the data and instantiate an instance of the appropriate decoder plugin. - // If insufficient bytes are available to determine the image type, no decoder plugin will be - // made. - if (m_decoder) - delete m_decoder; - m_decoder = createDecoder(*data); - if (!m_decoder) - return; - m_decoder->setData(data, allDataReceived); -} - -bool ImageSource::isSizeAvailable() -{ - if (!m_decoder) - return false; - - return m_decoder->isSizeAvailable(); -} - -IntSize ImageSource::size() const -{ - if (!m_decoder) - return IntSize(); - - return m_decoder->size(); -} - -IntSize ImageSource::frameSizeAtIndex(size_t index) const -{ - if (!m_decoder) - return IntSize(); - - return m_decoder->frameSizeAtIndex(index); -} - -int ImageSource::repetitionCount() -{ - if (!m_decoder) - return cAnimationNone; - - return m_decoder->repetitionCount(); -} - -String ImageSource::filenameExtension() const -{ - notImplemented(); - return String(); -} - -size_t ImageSource::frameCount() const -{ - return m_decoder ? m_decoder->frameCount() : 0; -} - -bool ImageSource::frameIsCompleteAtIndex(size_t index) -{ - // FIXME: should we be testing the RGBA32Buffer's status as well? - return (m_decoder && m_decoder->frameBufferAtIndex(index) != 0); -} - -void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived) -{ - if (!destroyAll) { - if (m_decoder) - m_decoder->clearFrameBufferCache(clearBeforeFrame); - return; - } - - delete m_decoder; - m_decoder = 0; - if (data) - setData(data, allDataReceived); -} - -NativeImagePtr ImageSource::createFrameAtIndex(size_t index) -{ - if (!m_decoder) - return 0; - - RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); - if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) - return 0; - - return buffer->asNewNativeImage(); -} - -float ImageSource::frameDurationAtIndex(size_t index) -{ - if (!m_decoder) - return 0; - - RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); - if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) - return 0; - - float duration = buffer->duration() / 1000.0f; - - // Follow other ports (and WinIE's) behavior to slow annoying ads that - // specify a 0 duration. - if (duration < 0.051f) - return 0.100f; - return duration; -} - -bool ImageSource::frameHasAlphaAtIndex(size_t index) -{ - if (!m_decoder || !m_decoder->supportsAlpha()) - return false; - - RGBA32Buffer* buffer = m_decoder->frameBufferAtIndex(index); - if (!buffer || buffer->status() == RGBA32Buffer::FrameEmpty) - return false; - - return buffer->hasAlpha(); -} - -} diff --git a/WebCore/platform/graphics/wx/ImageWx.cpp b/WebCore/platform/graphics/wx/ImageWx.cpp index b0a993e..bd129cf 100644 --- a/WebCore/platform/graphics/wx/ImageWx.cpp +++ b/WebCore/platform/graphics/wx/ImageWx.cpp @@ -31,6 +31,7 @@ #include "FloatRect.h" #include "GraphicsContext.h" #include "ImageObserver.h" +#include "NotImplemented.h" #include "TransformationMatrix.h" #include <math.h> @@ -45,9 +46,6 @@ #include <wx/image.h> #include <wx/thread.h> -// This function loads resources from WebKit -Vector<char> loadResourceIntoArray(const char*); - namespace WebCore { // this is in GraphicsContextWx.cpp @@ -72,7 +70,9 @@ bool FrameData::clear(bool clearMetadata) PassRefPtr<Image> Image::loadPlatformResource(const char *name) { - Vector<char> arr = loadResourceIntoArray(name); + // FIXME: We need to have some 'placeholder' graphics for things like missing + // plugins or broken images. + Vector<char> arr; RefPtr<Image> img = BitmapImage::create(); RefPtr<SharedBuffer> buffer = SharedBuffer::create(arr.data(), arr.size()); img->setData(buffer, true); @@ -261,4 +261,9 @@ void BitmapImage::invalidatePlatformData() } +void Image::drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator, const FloatRect& destRect) +{ + notImplemented(); +} + } diff --git a/WebCore/platform/graphics/wx/IntSizeWx.cpp b/WebCore/platform/graphics/wx/IntSizeWx.cpp new file mode 100644 index 0000000..8c82854 --- /dev/null +++ b/WebCore/platform/graphics/wx/IntSizeWx.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2009 Kevin Watters. 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 "IntSize.h" + +#include <wx/defs.h> +#include <wx/gdicmn.h> + +namespace WebCore { + +IntSize::IntSize(const wxSize& s) + : m_width(s.x) + , m_height(s.y) +{ +} + +IntSize::operator wxSize() const +{ + return wxSize(m_width, m_height); +} + +} diff --git a/WebCore/platform/gtk/ClipboardGtk.cpp b/WebCore/platform/gtk/ClipboardGtk.cpp index 8cbf590..450966e 100644 --- a/WebCore/platform/gtk/ClipboardGtk.cpp +++ b/WebCore/platform/gtk/ClipboardGtk.cpp @@ -17,11 +17,18 @@ #include "config.h" #include "ClipboardGtk.h" +#include "CachedImage.h" +#include "CString.h" +#include "Editor.h" +#include "Element.h" #include "FileList.h" +#include "Frame.h" +#include "markup.h" #include "NotImplemented.h" +#include "RenderImage.h" #include "StringHash.h" -#include "Editor.h" +#include <gtk/gtk.h> namespace WebCore { @@ -33,12 +40,10 @@ PassRefPtr<Clipboard> Editor::newGeneralClipboard(ClipboardAccessPolicy policy) ClipboardGtk::ClipboardGtk(ClipboardAccessPolicy policy, bool forDragging) : Clipboard(policy, forDragging) { - notImplemented(); } ClipboardGtk::~ClipboardGtk() { - notImplemented(); } void ClipboardGtk::clearData(const String&) @@ -110,19 +115,65 @@ DragImageRef ClipboardGtk::createDragImage(IntPoint&) const return 0; } -void ClipboardGtk::declareAndWriteDragImage(Element*, const KURL&, const String&, Frame*) +static CachedImage* getCachedImage(Element* element) { - notImplemented(); + // Attempt to pull CachedImage from element + ASSERT(element); + RenderObject* renderer = element->renderer(); + if (!renderer || !renderer->isImage()) + return 0; + + RenderImage* image = static_cast<RenderImage*>(renderer); + if (image->cachedImage() && !image->cachedImage()->errorOccurred()) + return image->cachedImage(); + + return 0; } -void ClipboardGtk::writeURL(const KURL&, const String&, Frame*) +void ClipboardGtk::declareAndWriteDragImage(Element* element, const KURL& url, const String& label, Frame*) { - notImplemented(); + CachedImage* cachedImage = getCachedImage(element); + if (!cachedImage || !cachedImage->isLoaded()) + return; + + GdkPixbuf* pixbuf = cachedImage->image()->getGdkPixbuf(); + if (!pixbuf) + return; + + GtkClipboard* imageClipboard = gtk_clipboard_get(gdk_atom_intern_static_string("WebKitClipboardImage")); + gtk_clipboard_clear(imageClipboard); + + gtk_clipboard_set_image(imageClipboard, pixbuf); + g_object_unref(pixbuf); + + writeURL(url, label, 0); } -void ClipboardGtk::writeRange(Range*, Frame*) +void ClipboardGtk::writeURL(const KURL& url, const String& label, Frame*) { - notImplemented(); + GtkClipboard* textClipboard = gtk_clipboard_get(gdk_atom_intern_static_string("WebKitClipboardText")); + GtkClipboard* urlClipboard = gtk_clipboard_get(gdk_atom_intern_static_string("WebKitClipboardUrl")); + GtkClipboard* urlLabelClipboard = gtk_clipboard_get(gdk_atom_intern_static_string("WebKitClipboardUrlLabel")); + + gtk_clipboard_clear(textClipboard); + gtk_clipboard_clear(urlClipboard); + gtk_clipboard_clear(urlLabelClipboard); + + gtk_clipboard_set_text(textClipboard, url.string().utf8().data(), -1); + gtk_clipboard_set_text(urlClipboard, url.string().utf8().data(), -1); + gtk_clipboard_set_text(urlLabelClipboard, label.utf8().data(), -1); +} + +void ClipboardGtk::writeRange(Range* range, Frame* frame) +{ + GtkClipboard* textClipboard = gtk_clipboard_get(gdk_atom_intern_static_string("WebKitClipboardText")); + GtkClipboard* htmlClipboard = gtk_clipboard_get(gdk_atom_intern_static_string("WebKitClipboardHtml")); + + gtk_clipboard_clear(textClipboard); + gtk_clipboard_clear(htmlClipboard); + + gtk_clipboard_set_text(textClipboard, frame->selectedText().utf8().data(), -1); + gtk_clipboard_set_text(htmlClipboard, createMarkup(range, 0, AnnotateForInterchange).utf8().data(), -1); } bool ClipboardGtk::hasData() diff --git a/WebCore/platform/gtk/ClipboardGtk.h b/WebCore/platform/gtk/ClipboardGtk.h index 7314ae4..bb21d92 100644 --- a/WebCore/platform/gtk/ClipboardGtk.h +++ b/WebCore/platform/gtk/ClipboardGtk.h @@ -24,8 +24,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ClipboardGdk_h -#define ClipboardGdk_h +#ifndef ClipboardGtk_h +#define ClipboardGtk_h #include "Clipboard.h" diff --git a/WebCore/platform/gtk/CursorGtk.cpp b/WebCore/platform/gtk/CursorGtk.cpp index 115760e..1c669f3 100644 --- a/WebCore/platform/gtk/CursorGtk.cpp +++ b/WebCore/platform/gtk/CursorGtk.cpp @@ -28,6 +28,9 @@ #include "config.h" #include "CursorGtk.h" +#include "Image.h" +#include "IntPoint.h" + #include <wtf/Assertions.h> #include <gdk/gdk.h> @@ -60,15 +63,11 @@ Cursor::Cursor(const Cursor& other) gdk_cursor_ref(m_impl); } -Cursor::Cursor(Image*, const IntPoint&) +Cursor::Cursor(Image* image, const IntPoint& hotSpot) { - // FIXME: We don't support images for cursors yet. - // This is just a placeholder to avoid crashes. - Cursor other(crossCursor()); - m_impl = other.m_impl; - - if (m_impl) - gdk_cursor_ref(m_impl); + GdkPixbuf* pixbuf = image->getGdkPixbuf(); + m_impl = gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pixbuf, hotSpot.x(), hotSpot.y()); + g_object_unref(pixbuf); } Cursor::~Cursor() diff --git a/WebCore/platform/gtk/GeolocationServiceGtk.cpp b/WebCore/platform/gtk/GeolocationServiceGtk.cpp index fc15833..cf35346 100644 --- a/WebCore/platform/gtk/GeolocationServiceGtk.cpp +++ b/WebCore/platform/gtk/GeolocationServiceGtk.cpp @@ -37,11 +37,13 @@ namespace WTF { namespace WebCore { -GeolocationService* GeolocationService::create(GeolocationServiceClient* client) +GeolocationService* GeolocationServiceGtk::create(GeolocationServiceClient* client) { return new GeolocationServiceGtk(client); } +GeolocationService::FactoryFunction* GeolocationService::s_factoryFunction = &GeolocationServiceGtk::create; + GeolocationServiceGtk::GeolocationServiceGtk(GeolocationServiceClient* client) : GeolocationService(client) , m_geoclueClient(0) diff --git a/WebCore/platform/gtk/GeolocationServiceGtk.h b/WebCore/platform/gtk/GeolocationServiceGtk.h index 90699ad..a198dc0 100644 --- a/WebCore/platform/gtk/GeolocationServiceGtk.h +++ b/WebCore/platform/gtk/GeolocationServiceGtk.h @@ -31,7 +31,7 @@ namespace WebCore { class GeolocationServiceGtk : public GeolocationService { public: - GeolocationServiceGtk(GeolocationServiceClient*); + static GeolocationService* create(GeolocationServiceClient*); ~GeolocationServiceGtk(); virtual bool startUpdating(PositionOptions*); @@ -44,6 +44,8 @@ namespace WebCore { PositionError* lastError() const; private: + GeolocationServiceGtk(GeolocationServiceClient*); + void updateLocationInformation(); void setError(PositionError::ErrorCode, const char* message); void updatePosition(); diff --git a/WebCore/platform/gtk/KeyEventGtk.cpp b/WebCore/platform/gtk/KeyEventGtk.cpp index 5875547..4186c2f 100644 --- a/WebCore/platform/gtk/KeyEventGtk.cpp +++ b/WebCore/platform/gtk/KeyEventGtk.cpp @@ -136,6 +136,8 @@ static String keyIdentifierForGdkKeyCode(guint keyCode) // Standard says that DEL becomes U+007F. case GDK_Delete: return "U+007F"; + case GDK_BackSpace: + return "U+0008"; case GDK_ISO_Left_Tab: case GDK_3270_BackTab: case GDK_Tab: @@ -503,6 +505,8 @@ static String singleCharacterString(guint val) case GDK_KP_Enter: case GDK_Return: return String("\r"); + case GDK_BackSpace: + return String("\x8"); default: gunichar c = gdk_keyval_to_unicode(val); glong nwc; diff --git a/WebCore/platform/gtk/LocalizedStringsGtk.cpp b/WebCore/platform/gtk/LocalizedStringsGtk.cpp index 2ba4fbb..85e071b 100644 --- a/WebCore/platform/gtk/LocalizedStringsGtk.cpp +++ b/WebCore/platform/gtk/LocalizedStringsGtk.cpp @@ -345,6 +345,9 @@ String imageTitle(const String& filename, const IntSize& size) return String::fromUTF8(string.get()); } + +#if ENABLE(VIDEO) + String mediaElementLoadingStateText() { return String::fromUTF8(_("Loading...")); @@ -355,4 +358,113 @@ String mediaElementLiveBroadcastStateText() return String::fromUTF8(_("Live Broadcast")); } +String localizedMediaControlElementString(const String& name) +{ + if (name == "AudioElement") + return String::fromUTF8(_("audio element controller")); + if (name == "VideoElement") + return String::fromUTF8(_("video element controller")); + if (name == "MuteButton") + return String::fromUTF8(_("mute")); + if (name == "UnMuteButton") + return String::fromUTF8(_("unmute")); + if (name == "PlayButton") + return String::fromUTF8(_("play")); + if (name == "PauseButton") + return String::fromUTF8(_("pause")); + if (name == "Slider") + return String::fromUTF8(_("movie time")); + if (name == "SliderThumb") + return String::fromUTF8(_("timeline slider thumb")); + if (name == "RewindButton") + return String::fromUTF8(_("back 30 seconds")); + if (name == "ReturnToRealtimeButton") + return String::fromUTF8(_("return to realtime")); + if (name == "CurrentTimeDisplay") + return String::fromUTF8(_("elapsed time")); + if (name == "TimeRemainingDisplay") + return String::fromUTF8(_("remaining time")); + if (name == "StatusDisplay") + return String::fromUTF8(_("status")); + if (name == "FullscreenButton") + return String::fromUTF8(_("fullscreen")); + if (name == "SeekForwardButton") + return String::fromUTF8(_("fast forward")); + if (name == "SeekBackButton") + return String::fromUTF8(_("fast reverse")); + + ASSERT_NOT_REACHED(); + return String(); +} + +String localizedMediaControlElementHelpText(const String& name) +{ + if (name == "AudioElement") + return String::fromUTF8(_("audio element playback controls and status display")); + if (name == "VideoElement") + return String::fromUTF8(_("video element playback controls and status display")); + if (name == "MuteButton") + return String::fromUTF8(_("mute audio tracks")); + if (name == "UnMuteButton") + return String::fromUTF8(_("unmute audio tracks")); + if (name == "PlayButton") + return String::fromUTF8(_("begin playback")); + if (name == "PauseButton") + return String::fromUTF8(_("pause playback")); + if (name == "Slider") + return String::fromUTF8(_("movie time scrubber")); + if (name == "SliderThumb") + return String::fromUTF8(_("movie time scrubber thumb")); + if (name == "RewindButton") + return String::fromUTF8(_("seek movie back 30 seconds")); + if (name == "ReturnToRealtimeButton") + return String::fromUTF8(_("return streaming movie to real time")); + if (name == "CurrentTimeDisplay") + return String::fromUTF8(_("current movie time in seconds")); + if (name == "TimeRemainingDisplay") + return String::fromUTF8(_("number of seconds of movie remaining")); + if (name == "StatusDisplay") + return String::fromUTF8(_("current movie status")); + if (name == "SeekBackButton") + return String::fromUTF8(_("seek quickly back")); + if (name == "SeekForwardButton") + return String::fromUTF8(_("seek quickly forward")); + if (name == "FullscreenButton") + return String::fromUTF8(_("Play movie in fullscreen mode")); + + ASSERT_NOT_REACHED(); + return String(); +} + +String localizedMediaTimeDescription(float time) +{ + if (!isfinite(time)) + return String::fromUTF8(_("indefinite time")); + + int seconds = (int)fabsf(time); + int days = seconds / (60 * 60 * 24); + int hours = seconds / (60 * 60); + int minutes = (seconds / 60) % 60; + seconds %= 60; + + if (days) { + GOwnPtr<gchar> string(g_strdup_printf("%d days %d hours %d minutes %d seconds", days, hours, minutes, seconds)); + return String::fromUTF8(string.get()); + } + + if (hours) { + GOwnPtr<gchar> string(g_strdup_printf("%d hours %d minutes %d seconds", hours, minutes, seconds)); + return String::fromUTF8(string.get()); + } + + if (minutes) { + GOwnPtr<gchar> string(g_strdup_printf("%d minutes %d seconds", minutes, seconds)); + return String::fromUTF8(string.get()); + } + + GOwnPtr<gchar> string(g_strdup_printf("%d seconds", seconds)); + return String::fromUTF8(string.get()); +} +#endif // ENABLE(VIDEO) + } diff --git a/WebCore/platform/gtk/PasteboardGtk.cpp b/WebCore/platform/gtk/PasteboardGtk.cpp index 9f72923..0ff26f7 100644 --- a/WebCore/platform/gtk/PasteboardGtk.cpp +++ b/WebCore/platform/gtk/PasteboardGtk.cpp @@ -35,13 +35,6 @@ namespace WebCore { -/* FIXME: we must get rid of this and use the enum in webkitwebview.h someway */ -typedef enum -{ - WEBKIT_WEB_VIEW_TARGET_INFO_HTML = - 1, - WEBKIT_WEB_VIEW_TARGET_INFO_TEXT = - 2 -} WebKitWebViewTargetInfo; - class PasteboardSelectionData { public: PasteboardSelectionData(gchar* text, gchar* markup) @@ -65,11 +58,11 @@ static void clipboard_get_contents_cb(GtkClipboard *clipboard, GtkSelectionData guint info, gpointer data) { PasteboardSelectionData* clipboardData = reinterpret_cast<PasteboardSelectionData*>(data); ASSERT(clipboardData); - if ((gint)info == WEBKIT_WEB_VIEW_TARGET_INFO_HTML) { + if ((gint)info == Pasteboard::generalPasteboard()->m_helper->getWebViewTargetInfoHtml()) gtk_selection_data_set(selection_data, selection_data->target, 8, reinterpret_cast<const guchar*>(clipboardData->markup()), g_utf8_strlen(clipboardData->markup(), -1)); - } else + else gtk_selection_data_set_text(selection_data, clipboardData->text(), -1); } @@ -115,6 +108,13 @@ void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, gtk_target_table_free(targets, n_targets); } +void Pasteboard::writePlainText(const String& text) +{ + CString utf8 = text.utf8(); + GtkClipboard* clipboard = gtk_clipboard_get_for_display(gdk_display_get_default(), GDK_SELECTION_CLIPBOARD); + gtk_clipboard_set_text(clipboard, utf8.data(), utf8.length()); +} + void Pasteboard::writeURL(const KURL& url, const String&, Frame* frame) { if (url.isEmpty()) @@ -122,8 +122,9 @@ void Pasteboard::writeURL(const KURL& url, const String&, Frame* frame) GtkClipboard* clipboard = m_helper->getClipboard(frame); GtkClipboard* primary = m_helper->getPrimary(frame); - gtk_clipboard_set_text(clipboard, url.string().utf8().data(), url.string().utf8().length()); - gtk_clipboard_set_text(primary, url.string().utf8().data(), url.string().utf8().length()); + CString utf8 = url.string().utf8(); + gtk_clipboard_set_text(clipboard, utf8.data(), utf8.length()); + gtk_clipboard_set_text(primary, utf8.data(), utf8.length()); } void Pasteboard::writeImage(Node* node, const KURL&, const String&) diff --git a/WebCore/platform/gtk/PasteboardHelper.h b/WebCore/platform/gtk/PasteboardHelper.h index 9943a2d..8e67127 100644 --- a/WebCore/platform/gtk/PasteboardHelper.h +++ b/WebCore/platform/gtk/PasteboardHelper.h @@ -43,6 +43,7 @@ public: virtual GtkClipboard* getPrimary(Frame*) const = 0; virtual GtkTargetList* getCopyTargetList(Frame*) const = 0; virtual GtkTargetList* getPasteTargetList(Frame*) const = 0; + virtual gint getWebViewTargetInfoHtml() const = 0; }; } diff --git a/WebCore/platform/gtk/PlatformScreenGtk.cpp b/WebCore/platform/gtk/PlatformScreenGtk.cpp index 4ba6d43..a6ff954 100644 --- a/WebCore/platform/gtk/PlatformScreenGtk.cpp +++ b/WebCore/platform/gtk/PlatformScreenGtk.cpp @@ -49,7 +49,7 @@ static GdkVisual* getVisual(Widget* widget) if (!widget) return 0; - GtkWidget* container = GTK_WIDGET(widget->root()->hostWindow()->platformWindow()); + GtkWidget* container = GTK_WIDGET(widget->root()->hostWindow()->platformPageClient()); if (!container) return 0; @@ -93,7 +93,7 @@ FloatRect screenRect(Widget* widget) if (!widget) return FloatRect(); - GtkWidget* container = gtk_widget_get_toplevel(GTK_WIDGET(widget->root()->hostWindow()->platformWindow())); + GtkWidget* container = gtk_widget_get_toplevel(GTK_WIDGET(widget->root()->hostWindow()->platformPageClient())); if (!GTK_WIDGET_TOPLEVEL(container)) return FloatRect(); @@ -114,7 +114,7 @@ FloatRect screenAvailableRect(Widget* widget) return FloatRect(); #if PLATFORM(X11) - GtkWidget* container = GTK_WIDGET(widget->root()->hostWindow()->platformWindow()); + GtkWidget* container = GTK_WIDGET(widget->root()->hostWindow()->platformPageClient()); if (!container) return FloatRect(); diff --git a/WebCore/platform/gtk/PopupMenuGtk.cpp b/WebCore/platform/gtk/PopupMenuGtk.cpp index 121d7b0..3f6b02a 100644 --- a/WebCore/platform/gtk/PopupMenuGtk.cpp +++ b/WebCore/platform/gtk/PopupMenuGtk.cpp @@ -60,7 +60,7 @@ void PopupMenu::show(const IntRect& rect, FrameView* view, int index) gtk_container_foreach(GTK_CONTAINER(m_popup), reinterpret_cast<GtkCallback>(menuRemoveItem), this); int x, y; - gdk_window_get_origin(GTK_WIDGET(view->hostWindow()->platformWindow())->window, &x, &y); + gdk_window_get_origin(GTK_WIDGET(view->hostWindow()->platformPageClient())->window, &x, &y); m_menuPosition = view->contentsToWindow(rect.location()); m_menuPosition = IntPoint(m_menuPosition.x() + x, m_menuPosition.y() + y + rect.height()); m_indexMap.clear(); @@ -137,7 +137,7 @@ void PopupMenu::menuItemActivated(GtkMenuItem* item, PopupMenu* that) void PopupMenu::menuUnmapped(GtkWidget*, PopupMenu* that) { ASSERT(that->client()); - that->client()->hidePopup(); + that->client()->popupDidHide(); } void PopupMenu::menuPositionFunction(GtkMenu*, gint* x, gint* y, gboolean* pushIn, PopupMenu* that) diff --git a/WebCore/platform/gtk/ScrollViewGtk.cpp b/WebCore/platform/gtk/ScrollViewGtk.cpp index 0e811ef..a1ed8c3 100644 --- a/WebCore/platform/gtk/ScrollViewGtk.cpp +++ b/WebCore/platform/gtk/ScrollViewGtk.cpp @@ -31,10 +31,14 @@ #include "config.h" #include "ScrollView.h" +#include "ChromeClient.h" #include "FloatRect.h" +#include "Frame.h" +#include "FrameView.h" #include "GraphicsContext.h" #include "HostWindow.h" #include "IntRect.h" +#include "Page.h" #include "PlatformMouseEvent.h" #include "PlatformWheelEvent.h" #include "ScrollbarGtk.h" @@ -103,7 +107,7 @@ void ScrollView::setGtkAdjustments(GtkAdjustment* hadj, GtkAdjustment* vadj) void ScrollView::platformAddChild(Widget* child) { if (!GTK_IS_SOCKET(child->platformWidget())) - gtk_container_add(GTK_CONTAINER(hostWindow()->platformWindow()), child->platformWidget()); + gtk_container_add(GTK_CONTAINER(hostWindow()->platformPageClient()), child->platformWidget()); } void ScrollView::platformRemoveChild(Widget* child) @@ -113,7 +117,7 @@ void ScrollView::platformRemoveChild(Widget* child) // HostWindow can be NULL here. If that's the case // let's grab the child's parent instead. if (hostWindow()) - parent = GTK_WIDGET(hostWindow()->platformWindow()); + parent = GTK_WIDGET(hostWindow()->platformPageClient()); else parent = GTK_WIDGET(child->platformWidget()->parent); @@ -129,7 +133,7 @@ IntRect ScrollView::visibleContentRect(bool includeScrollbars) const max(0, height() - (horizontalScrollbar() && !includeScrollbars ? horizontalScrollbar()->height() : 0)))); // Main frame. - GtkWidget* measuredWidget = hostWindow()->platformWindow(); + GtkWidget* measuredWidget = hostWindow()->platformPageClient(); GtkWidget* parent = gtk_widget_get_parent(measuredWidget); // We may not be in a widget that displays scrollbars, but we may @@ -142,4 +146,29 @@ IntRect ScrollView::visibleContentRect(bool includeScrollbars) const measuredWidget->allocation.height)); } +void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode) +{ + if (horizontalMode == m_horizontalScrollbarMode && verticalMode == m_verticalScrollbarMode) + return; + + m_horizontalScrollbarMode = horizontalMode; + m_verticalScrollbarMode = verticalMode; + + // We don't really care about reporting policy changes on frames + // that have no adjustments attached to them. + if (!m_horizontalAdjustment) { + updateScrollbars(scrollOffset()); + return; + } + + if (!isFrameView()) + return; + + // For frames that do have adjustments attached, we want to report + // policy changes, so that they may be applied to the widget to + // which the WebView has been added, for instance. + if (hostWindow()) + hostWindow()->scrollbarsModeDidChange(); +} + } diff --git a/WebCore/platform/gtk/WidgetGtk.cpp b/WebCore/platform/gtk/WidgetGtk.cpp index 007f2ee..53c10f1 100644 --- a/WebCore/platform/gtk/WidgetGtk.cpp +++ b/WebCore/platform/gtk/WidgetGtk.cpp @@ -55,7 +55,7 @@ Widget::~Widget() void Widget::setFocus() { - gtk_widget_grab_focus(platformWidget() ? platformWidget() : GTK_WIDGET(root()->hostWindow()->platformWindow())); + gtk_widget_grab_focus(platformWidget() ? platformWidget() : GTK_WIDGET(root()->hostWindow()->platformPageClient())); } static GdkDrawable* gdkDrawable(PlatformWidget widget) @@ -76,7 +76,7 @@ void Widget::setCursor(const Cursor& cursor) if (platformCursor == lastSetCursor) return; - gdk_window_set_cursor(gdkDrawable(platformWidget()) ? GDK_WINDOW(gdkDrawable(platformWidget())) : GTK_WIDGET(root()->hostWindow()->platformWindow())->window, platformCursor); + gdk_window_set_cursor(gdkDrawable(platformWidget()) ? GDK_WINDOW(gdkDrawable(platformWidget())) : GTK_WIDGET(root()->hostWindow()->platformPageClient())->window, platformCursor); lastSetCursor = platformCursor; } diff --git a/WebCore/platform/haiku/ClipboardHaiku.cpp b/WebCore/platform/haiku/ClipboardHaiku.cpp index 845c08c..a62c30c 100644 --- a/WebCore/platform/haiku/ClipboardHaiku.cpp +++ b/WebCore/platform/haiku/ClipboardHaiku.cpp @@ -27,8 +27,8 @@ #include "config.h" #include "ClipboardHaiku.h" -#include "IntPoint.h" #include "FileList.h" +#include "IntPoint.h" #include "NotImplemented.h" #include "PlatformString.h" #include "StringHash.h" @@ -42,7 +42,7 @@ namespace WebCore { -ClipboardHaiku::ClipboardHaiku(ClipboardAccessPolicy policy, bool forDragging) +ClipboardHaiku::ClipboardHaiku(ClipboardAccessPolicy policy, bool forDragging) : Clipboard(policy, forDragging) { } @@ -61,7 +61,7 @@ void ClipboardHaiku::clearData(const String& type) } } -void ClipboardHaiku::clearAllData() +void ClipboardHaiku::clearAllData() { if (be_clipboard->Lock()) { be_clipboard->Clear(); @@ -70,7 +70,7 @@ void ClipboardHaiku::clearAllData() } } -String ClipboardHaiku::getData(const String& type, bool& success) const +String ClipboardHaiku::getData(const String& type, bool& success) const { BString result; success = false; @@ -88,7 +88,7 @@ String ClipboardHaiku::getData(const String& type, bool& success) const return result; } -bool ClipboardHaiku::setData(const String& type, const String& data) +bool ClipboardHaiku::setData(const String& type, const String& data) { bool result = false; @@ -110,7 +110,7 @@ bool ClipboardHaiku::setData(const String& type, const String& data) } // Extensions beyond IE's API. -HashSet<String> ClipboardHaiku::types() const +HashSet<String> ClipboardHaiku::types() const { HashSet<String> result; @@ -138,27 +138,27 @@ PassRefPtr<FileList> ClipboardHaiku::files() const return 0; } -IntPoint ClipboardHaiku::dragLocation() const -{ +IntPoint ClipboardHaiku::dragLocation() const +{ notImplemented(); return IntPoint(0, 0); } -CachedImage* ClipboardHaiku::dragImage() const +CachedImage* ClipboardHaiku::dragImage() const { notImplemented(); - return 0; + return 0; } -void ClipboardHaiku::setDragImage(CachedImage*, const IntPoint&) +void ClipboardHaiku::setDragImage(CachedImage*, const IntPoint&) { notImplemented(); } -Node* ClipboardHaiku::dragImageElement() +Node* ClipboardHaiku::dragImageElement() { notImplemented(); - return 0; + return 0; } void ClipboardHaiku::setDragImageElement(Node*, const IntPoint&) @@ -167,27 +167,27 @@ void ClipboardHaiku::setDragImageElement(Node*, const IntPoint&) } DragImageRef ClipboardHaiku::createDragImage(IntPoint& dragLocation) const -{ +{ notImplemented(); return 0; } -void ClipboardHaiku::declareAndWriteDragImage(Element*, const KURL&, const String&, Frame*) +void ClipboardHaiku::declareAndWriteDragImage(Element*, const KURL&, const String&, Frame*) { notImplemented(); } -void ClipboardHaiku::writeURL(const KURL&, const String&, Frame*) +void ClipboardHaiku::writeURL(const KURL&, const String&, Frame*) { notImplemented(); } -void ClipboardHaiku::writeRange(Range*, Frame*) +void ClipboardHaiku::writeRange(Range*, Frame*) { notImplemented(); } -bool ClipboardHaiku::hasData() +bool ClipboardHaiku::hasData() { bool result = false; diff --git a/WebCore/platform/haiku/ContextMenuHaiku.cpp b/WebCore/platform/haiku/ContextMenuHaiku.cpp index 03b8978..b978433 100644 --- a/WebCore/platform/haiku/ContextMenuHaiku.cpp +++ b/WebCore/platform/haiku/ContextMenuHaiku.cpp @@ -27,30 +27,27 @@ #include "config.h" #include "ContextMenu.h" -#include "ContextMenuItem.h" #include "ContextMenuController.h" +#include "ContextMenuItem.h" +#include "Document.h" #include "Frame.h" #include "FrameView.h" -#include "Document.h" - -#include <wtf/Assertions.h> - #include <Looper.h> #include <Menu.h> #include <Message.h> +#include <wtf/Assertions.h> namespace WebCore { // FIXME: This class isn't used yet -class ContextMenuReceiver : public BLooper -{ +class ContextMenuReceiver : public BLooper { public: ContextMenuReceiver(ContextMenu* menu) : BLooper("context_menu_receiver") , m_menu(menu) + , m_result(-1) { - m_result = -1; } void HandleMessage(BMessage* msg) @@ -80,21 +77,8 @@ private: ContextMenu::ContextMenu(const HitTestResult& result) : m_hitTestResult(result) - , m_platformDescription(NULL) + , m_platformDescription(new BMenu("context_menu")) { - /* Get position */ - if (result.innerNode() && result.innerNode()->document()) { - BView* view = result.innerNode()->document()->frame()->view()->platformWidget(); - int child = 0; - while (view->ChildAt(child)) { - if (view->ChildAt(child)->Name() == "scroll_view_canvas") { - m_point = view->ChildAt(child)->ConvertToScreen(BPoint(result.point().x(), result.point().y())); - break; - } - child++; - } - } - m_platformDescription = new BMenu("context_menu"); } ContextMenu::~ContextMenu() @@ -106,9 +90,9 @@ void ContextMenu::appendItem(ContextMenuItem& item) { checkOrEnableIfNeeded(item); - BMenuItem* bItem = item.releasePlatformDescription(); - if (bItem) - m_platformDescription->AddItem(bItem); + BMenuItem* menuItem = item.releasePlatformDescription(); + if (menuItem) + m_platformDescription->AddItem(menuItem); } unsigned ContextMenu::itemCount() const @@ -120,9 +104,9 @@ void ContextMenu::insertItem(unsigned position, ContextMenuItem& item) { checkOrEnableIfNeeded(item); - BMenuItem* bItem = item.releasePlatformDescription(); - if (bItem) - m_platformDescription->AddItem(bItem, position); + BMenuItem* menuItem = item.releasePlatformDescription(); + if (menuItem) + m_platformDescription->AddItem(menuItem, position); } PlatformMenuDescription ContextMenu::platformDescription() const diff --git a/WebCore/platform/haiku/CookieJarHaiku.cpp b/WebCore/platform/haiku/CookieJarHaiku.cpp index 73519d7..831b379 100644 --- a/WebCore/platform/haiku/CookieJarHaiku.cpp +++ b/WebCore/platform/haiku/CookieJarHaiku.cpp @@ -29,6 +29,7 @@ #include "config.h" #include "CookieJar.h" +#include "Cookie.h" #include "KURL.h" #include "PlatformString.h" #include "StringHash.h" @@ -41,21 +42,33 @@ namespace WebCore { // FIXME: Shouldn't this be saved to and restored from disk too? static HashMap<String, String> cookieJar; -void setCookies(const KURL& url, const KURL& /*policyURL*/, const String& value) +void setCookies(Document*, const KURL& url, const String& value) { cookieJar.set(url.string(), value); } -String cookies(const KURL& url) +String cookies(const Document*, const KURL& url) { return cookieJar.get(url.string()); } -bool cookiesEnabled() +bool cookiesEnabled(const Document*) { // FIXME: This should probably be a setting return true; } +bool getRawCookies(const Document*, const KURL&, Vector<Cookie>& rawCookies) +{ + // FIXME: Not yet implemented + rawCookies.clear(); + return false; // return true when implemented +} + +void deleteCookie(const Document*, const KURL&, const String&) +{ + // FIXME: Not yet implemented +} + } // namespace WebCore diff --git a/WebCore/platform/haiku/DragDataHaiku.cpp b/WebCore/platform/haiku/DragDataHaiku.cpp index b42b311..4a20147 100644 --- a/WebCore/platform/haiku/DragDataHaiku.cpp +++ b/WebCore/platform/haiku/DragDataHaiku.cpp @@ -27,10 +27,9 @@ #include "config.h" #include "DragData.h" +#include "ClipboardHaiku.h" #include "Document.h" #include "DocumentFragment.h" -#include "ClipboardHaiku.h" - #include "NotImplemented.h" @@ -79,7 +78,7 @@ Color DragData::asColor() const WTF::PassRefPtr<Clipboard> DragData::createClipboard(ClipboardAccessPolicy policy) const { - return new ClipboardHaiku(policy, true); + return ClipboardHaiku::create(policy, true); } bool DragData::containsCompatibleContent() const @@ -104,6 +103,6 @@ PassRefPtr<DocumentFragment> DragData::asFragment(Document*) const notImplemented(); return 0; } - + } // namespace WebCore diff --git a/WebCore/platform/haiku/LocalizedStringsHaiku.cpp b/WebCore/platform/haiku/LocalizedStringsHaiku.cpp new file mode 100644 index 0000000..a37ffcc --- /dev/null +++ b/WebCore/platform/haiku/LocalizedStringsHaiku.cpp @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "LocalizedStrings.h" + +#include "PlatformString.h" + + +namespace WebCore { +String submitButtonDefaultLabel() +{ + return "Submit"; +} + +String inputElementAltText() +{ + return String(); +} + +String resetButtonDefaultLabel() +{ + return "Reset"; +} + +String defaultLanguage() +{ + return "en"; +} + +String searchableIndexIntroduction() +{ + return "Searchable Index"; +} + +String fileButtonChooseFileLabel() +{ + return "Choose File"; +} + +String fileButtonNoFileSelectedLabel() +{ + return "No file selected"; +} + +String contextMenuItemTagOpenLinkInNewWindow() +{ + return "Open in new tab"; +} + +String contextMenuItemTagDownloadLinkToDisk() +{ + return "Download link to disk"; +} + +String contextMenuItemTagCopyLinkToClipboard() +{ + return "Copy link to clipboard"; +} + +String contextMenuItemTagOpenImageInNewWindow() +{ + return "Open image in new window"; +} + +String contextMenuItemTagDownloadImageToDisk() +{ + return "Download image to disk"; +} + +String contextMenuItemTagCopyImageToClipboard() +{ + return "Copy image to clipboard"; +} + +String contextMenuItemTagOpenFrameInNewWindow() +{ + return "Open frame in new window"; +} + +String contextMenuItemTagCopy() +{ + return "Copy"; +} + +String contextMenuItemTagGoBack() +{ + return "Go back"; +} + +String contextMenuItemTagGoForward() +{ + return "Go forward"; +} + +String contextMenuItemTagStop() +{ + return "Stop"; +} + +String contextMenuItemTagReload() +{ + return "Reload"; +} + +String contextMenuItemTagCut() +{ + return "Cut"; +} + +String contextMenuItemTagPaste() +{ + return "Paste"; +} + +String contextMenuItemTagNoGuessesFound() +{ + return "No guesses found"; +} + +String contextMenuItemTagIgnoreSpelling() +{ + return "Ignore spelling"; +} + +String contextMenuItemTagLearnSpelling() +{ + return "Learn spelling"; +} + +String contextMenuItemTagSearchWeb() +{ + return "Search web"; +} + +String contextMenuItemTagLookUpInDictionary() +{ + return "Lookup in dictionary"; +} + +String contextMenuItemTagOpenLink() +{ + return "Open link"; +} + +String contextMenuItemTagIgnoreGrammar() +{ + return "Ignore grammar"; +} + +String contextMenuItemTagSpellingMenu() +{ + return "Spelling menu"; +} + +String contextMenuItemTagShowSpellingPanel(bool show) +{ + return "Show spelling panel"; +} + +String contextMenuItemTagCheckSpelling() +{ + return "Check spelling"; +} + +String contextMenuItemTagCheckSpellingWhileTyping() +{ + return "Check spelling while typing"; +} + +String contextMenuItemTagCheckGrammarWithSpelling() +{ + return "Check for grammar with spelling"; +} + +String contextMenuItemTagFontMenu() +{ + return "Font menu"; +} + +String contextMenuItemTagBold() +{ + return "Bold"; +} + +String contextMenuItemTagItalic() +{ + return "Italic"; +} + +String contextMenuItemTagUnderline() +{ + return "Underline"; +} + +String contextMenuItemTagOutline() +{ + return "Outline"; +} + +String contextMenuItemTagWritingDirectionMenu() +{ + return "Writing direction menu"; +} + +String contextMenuItemTagDefaultDirection() +{ + return "Default direction"; +} + +String contextMenuItemTagLeftToRight() +{ + return "Left to right"; +} + +String contextMenuItemTagRightToLeft() +{ + return "Right to left"; +} + +String contextMenuItemTagInspectElement() +{ + return "Inspect"; +} + +String searchMenuNoRecentSearchesText() +{ + return "No recent text searches"; +} + +String searchMenuRecentSearchesText() +{ + return "Recent text searches"; +} + +String searchMenuClearRecentSearchesText() +{ + return "Clear recent text searches"; +} + +String unknownFileSizeText() +{ + return "Unknown"; +} + +String AXWebAreaText() +{ + return String(); +} + +String AXLinkText() +{ + return String(); +} + +String AXListMarkerText() +{ + return String(); +} + +String AXImageMapText() +{ + return String(); +} + +String AXHeadingText() +{ + return String(); +} + +String imageTitle(const String& filename, const IntSize& size) +{ + return String(filename); +} + +String contextMenuItemTagTextDirectionMenu() +{ + return String(); +} + +String AXButtonActionVerb() +{ + return String(); +} + +String AXTextFieldActionVerb() +{ + return String(); +} + +String AXRadioButtonActionVerb() +{ + return String(); +} + +String AXCheckedCheckBoxActionVerb() +{ + return String(); +} + +String AXUncheckedCheckBoxActionVerb() +{ + return String(); +} + +String AXLinkActionVerb() +{ + return String(); +} + +String AXDefinitionListTermText() +{ + return String(); +} + +String AXDefinitionListDefinitionText() +{ + return String(); +} + +} // namespace WebCore + diff --git a/WebCore/platform/haiku/LoggingHaiku.cpp b/WebCore/platform/haiku/LoggingHaiku.cpp new file mode 100644 index 0000000..f09c483 --- /dev/null +++ b/WebCore/platform/haiku/LoggingHaiku.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com> + * + * 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 "Logging.h" + + +namespace WebCore { + +void InitializeLoggingChannelsIfNecessary() +{ + // FIXME: Should read the logging channels from a file. + static bool haveInitializedLoggingChannels = false; + if (haveInitializedLoggingChannels) + return; + + haveInitializedLoggingChannels = true; + + LogEvents.state = WTFLogChannelOn; + LogFrames.state = WTFLogChannelOn; + LogLoading.state = WTFLogChannelOn; + LogPlatformLeaks.state = WTFLogChannelOn; +} + +} // namespace WebCore + diff --git a/WebCore/platform/haiku/PasteboardHaiku.cpp b/WebCore/platform/haiku/PasteboardHaiku.cpp index 67a7f5b..8ad72ca 100644 --- a/WebCore/platform/haiku/PasteboardHaiku.cpp +++ b/WebCore/platform/haiku/PasteboardHaiku.cpp @@ -68,6 +68,23 @@ void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, clipboard.Unlock(); } +void Pasteboard::writePlainText(const String& text) +{ + BClipboard clipboard("WebKit"); + if (!clipboard.Lock()) + return; + + clipboard.Clear(); + BMessage* data = clipboard.Data(); + if (!data) + return; + + data->AddString("text/plain", BString(text)); + clipboard.Commit(); + + clipboard.Unlock(); +} + bool Pasteboard::canSmartReplace() { notImplemented(); diff --git a/WebCore/platform/haiku/RenderThemeHaiku.cpp b/WebCore/platform/haiku/RenderThemeHaiku.cpp new file mode 100644 index 0000000..4327795 --- /dev/null +++ b/WebCore/platform/haiku/RenderThemeHaiku.cpp @@ -0,0 +1,178 @@ +/* + * This file is part of the WebKit project. + * + * Copyright (C) 2006 Dirk Mueller <mueller@kde.org> + * 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2007 Ryan Leavengood <leavengood@gmail.com> + * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com> + * + * All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" +#include "RenderThemeHaiku.h" + +#include "GraphicsContext.h" +#include "NotImplemented.h" +#include <ControlLook.h> +#include <View.h> + + +namespace WebCore { + +PassRefPtr<RenderTheme> RenderThemeHaiku::create() +{ + return adoptRef(new RenderThemeHaiku()); +} + +PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page*) +{ + static RenderTheme* renderTheme = RenderThemeHaiku::create().releaseRef(); + return renderTheme; +} + +RenderThemeHaiku::RenderThemeHaiku() +{ +} + +RenderThemeHaiku::~RenderThemeHaiku() +{ +} + +static bool supportsFocus(ControlPart appearance) +{ + switch (appearance) { + case PushButtonPart: + case ButtonPart: + case TextFieldPart: + case TextAreaPart: + case SearchFieldPart: + case MenulistPart: + case RadioPart: + case CheckboxPart: + return true; + default: + return false; + } +} + +bool RenderThemeHaiku::supportsFocusRing(const RenderStyle* style) const +{ + return supportsFocus(style->appearance()); +} + +Color RenderThemeHaiku::platformActiveSelectionBackgroundColor() const +{ + return Color(ui_color(B_CONTROL_HIGHLIGHT_COLOR)); +} + +Color RenderThemeHaiku::platformInactiveSelectionBackgroundColor() const +{ + return Color(ui_color(B_CONTROL_HIGHLIGHT_COLOR)); +} + +Color RenderThemeHaiku::platformActiveSelectionForegroundColor() const +{ + return Color(ui_color(B_CONTROL_TEXT_COLOR)); +} + +Color RenderThemeHaiku::platformInactiveSelectionForegroundColor() const +{ + return Color(ui_color(B_CONTROL_TEXT_COLOR)); +} + +Color RenderThemeHaiku::platformTextSearchHighlightColor() const +{ + return Color(ui_color(B_MENU_SELECTED_BACKGROUND_COLOR)); +} + +void RenderThemeHaiku::systemFont(int propId, FontDescription&) const +{ + notImplemented(); +} + +bool RenderThemeHaiku::paintCheckbox(RenderObject*, const RenderObject::PaintInfo& info, const IntRect& intRect) +{ + if (info.context->paintingDisabled()) + return false; + + rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); + BRect rect = intRect; + BView* view = info.context->platformContext(); + + if (!be_control_look) + return false; + + be_control_look->DrawCheckBox(view, rect, rect, base); + return true; +} + +void RenderThemeHaiku::setCheckboxSize(RenderStyle* style) const +{ + int size = 10; + + // If the width and height are both specified, then we have nothing to do. + if (!style->width().isIntrinsicOrAuto() && !style->height().isAuto()) + return; + + // FIXME: A hard-coded size of 'size' is used. This is wrong but necessary for now. + if (style->width().isIntrinsicOrAuto()) + style->setWidth(Length(size, Fixed)); + + if (style->height().isAuto()) + style->setHeight(Length(size, Fixed)); +} + +bool RenderThemeHaiku::paintRadio(RenderObject*, const RenderObject::PaintInfo& info, const IntRect& intRect) +{ + if (info.context->paintingDisabled()) + return false; + + rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); + BRect rect = intRect; + BView* view = info.context->platformContext(); + + if (!be_control_look) + return false; + + be_control_look->DrawRadioButton(view, rect, rect, base); + return true; +} + +void RenderThemeHaiku::setRadioSize(RenderStyle* style) const +{ + // This is the same as checkboxes. + setCheckboxSize(style); +} + +void RenderThemeHaiku::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +{ + // Leave some space for the arrow. + style->setPaddingRight(Length(22, Fixed)); + const int minHeight = 20; + style->setMinHeight(Length(minHeight, Fixed)); +} + +bool RenderThemeHaiku::paintMenuList(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) +{ + notImplemented(); + return false; +} + +} // namespace WebCore diff --git a/WebCore/platform/haiku/RenderThemeHaiku.h b/WebCore/platform/haiku/RenderThemeHaiku.h new file mode 100644 index 0000000..7daebc4 --- /dev/null +++ b/WebCore/platform/haiku/RenderThemeHaiku.h @@ -0,0 +1,70 @@ +/* + * This file is part of the WebKit project. + * + * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com> + * + * All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef RenderThemeHaiku_h +#define RenderThemeHaiku_h + +#include "RenderTheme.h" + +namespace WebCore { + + class RenderThemeHaiku : public RenderTheme { + private: + RenderThemeHaiku(); + virtual ~RenderThemeHaiku(); + + public: + static PassRefPtr<RenderTheme> create(); + + // A method asking if the theme's controls actually care about redrawing when hovered. + virtual bool supportsHover(const RenderStyle* style) const { return false; } + + // A method asking if the theme is able to draw the focus ring. + virtual bool supportsFocusRing(const RenderStyle*) const; + + // The platform selection color. + virtual Color platformActiveSelectionBackgroundColor() const; + virtual Color platformInactiveSelectionBackgroundColor() const; + virtual Color platformActiveSelectionForegroundColor() const; + virtual Color platformInactiveSelectionForegroundColor() const; + + virtual Color platformTextSearchHighlightColor() const; + + // System fonts. + virtual void systemFont(int propId, FontDescription&) const; + + protected: + virtual bool paintCheckbox(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void setCheckboxSize(RenderStyle*) const; + + virtual bool paintRadio(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + virtual void setRadioSize(RenderStyle*) const; + + virtual void adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintMenuList(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); + }; + +} // namespace WebCore + +#endif // RenderThemeHaiku_h diff --git a/WebCore/platform/haiku/ScrollbarThemeHaiku.cpp b/WebCore/platform/haiku/ScrollbarThemeHaiku.cpp new file mode 100644 index 0000000..8adab3d --- /dev/null +++ b/WebCore/platform/haiku/ScrollbarThemeHaiku.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright 2009 Maxime Simon <simon.maxime@gmail.com> All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ScrollbarThemeHaiku.h" + +#include "GraphicsContext.h" +#include "Scrollbar.h" +#include <ControlLook.h> +#include <InterfaceDefs.h> + + +int buttonWidth(int scrollbarWidth, int thickness) +{ + return scrollbarWidth < 2 * thickness ? scrollbarWidth / 2 : thickness; +} + +namespace WebCore { + +ScrollbarTheme* ScrollbarTheme::nativeTheme() +{ + static ScrollbarThemeHaiku theme; + return &theme; +} + +ScrollbarThemeHaiku::ScrollbarThemeHaiku() +{ +} + +ScrollbarThemeHaiku::~ScrollbarThemeHaiku() +{ +} + +int ScrollbarThemeHaiku::scrollbarThickness(ScrollbarControlSize controlSize) +{ + // FIXME: Should we make a distinction between a Small and a Regular Scrollbar? + return 16; +} + +bool ScrollbarThemeHaiku::hasButtons(Scrollbar* scrollbar) +{ + return scrollbar->enabled(); +} + +bool ScrollbarThemeHaiku::hasThumb(Scrollbar* scrollbar) +{ + return scrollbar->enabled() && thumbLength(scrollbar) > 0; +} + +IntRect ScrollbarThemeHaiku::backButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool) +{ + if (part == BackButtonEndPart) + return IntRect(); + + int thickness = scrollbarThickness(); + IntPoint buttonOrigin(scrollbar->x(), scrollbar->y()); + IntSize buttonSize = scrollbar->orientation() == HorizontalScrollbar + ? IntSize(buttonWidth(scrollbar->width(), thickness), thickness) + : IntSize(thickness, buttonWidth(scrollbar->height(), thickness)); + IntRect buttonRect(buttonOrigin, buttonSize); + + return buttonRect; +} + +IntRect ScrollbarThemeHaiku::forwardButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool) +{ + if (part == BackButtonStartPart) + return IntRect(); + + int thickness = scrollbarThickness(); + if (scrollbar->orientation() == HorizontalScrollbar) { + int width = buttonWidth(scrollbar->width(), thickness); + return IntRect(scrollbar->x() + scrollbar->width() - width, scrollbar->y(), width, thickness); + } + + int height = buttonWidth(scrollbar->height(), thickness); + return IntRect(scrollbar->x(), scrollbar->y() + scrollbar->height() - height, thickness, height); +} + +IntRect ScrollbarThemeHaiku::trackRect(Scrollbar* scrollbar, bool) +{ + int thickness = scrollbarThickness(); + if (scrollbar->orientation() == HorizontalScrollbar) { + if (scrollbar->width() < 2 * thickness) + return IntRect(); + return IntRect(scrollbar->x() + thickness, scrollbar->y(), scrollbar->width() - 2 * thickness, thickness); + } + if (scrollbar->height() < 2 * thickness) + return IntRect(); + return IntRect(scrollbar->x(), scrollbar->y() + thickness, thickness, scrollbar->height() - 2 * thickness); +} + +void ScrollbarThemeHaiku::paintScrollbarBackground(GraphicsContext* context, Scrollbar* scrollbar) +{ + if (!be_control_look) + return; + + BRect rect = trackRect(scrollbar, false); + orientation scrollbarOrientation = scrollbar->orientation() == HorizontalScrollbar ? B_HORIZONTAL : B_VERTICAL; + + be_control_look->DrawScrollBarBackground(context->platformContext(), rect, rect, ui_color(B_PANEL_BACKGROUND_COLOR), 0, scrollbarOrientation); +} + +void ScrollbarThemeHaiku::paintButton(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part) +{ + if (!be_control_look) + return; + + BRect drawRect = BRect(rect); + BView* view = context->platformContext(); + rgb_color panelBgColor = ui_color(B_PANEL_BACKGROUND_COLOR); + rgb_color buttonBgColor = tint_color(panelBgColor, B_LIGHTEN_1_TINT); + + be_control_look->DrawButtonFrame(view, drawRect, drawRect, buttonBgColor, panelBgColor); + be_control_look->DrawButtonBackground(view, drawRect, drawRect, buttonBgColor); + + int arrowDirection; + if (scrollbar->orientation() == VerticalScrollbar) + arrowDirection = part == BackButtonStartPart ? BControlLook::B_UP_ARROW : BControlLook::B_DOWN_ARROW; + else + arrowDirection = part == BackButtonStartPart ? BControlLook::B_LEFT_ARROW : BControlLook::B_RIGHT_ARROW; + + be_control_look->DrawArrowShape(view, drawRect, drawRect, ui_color(B_CONTROL_TEXT_COLOR), arrowDirection); +} + +void ScrollbarThemeHaiku::paintThumb(GraphicsContext* context, Scrollbar*, const IntRect& rect) +{ + if (!be_control_look) + return; + + BRect drawRect = BRect(rect); + BView* view = context->platformContext(); + rgb_color panelBgColor = ui_color(B_PANEL_BACKGROUND_COLOR); + rgb_color buttonBgColor = tint_color(panelBgColor, B_LIGHTEN_1_TINT); + + be_control_look->DrawButtonFrame(view, drawRect, drawRect, buttonBgColor, panelBgColor); + be_control_look->DrawButtonBackground(view, drawRect, drawRect, buttonBgColor); +} + +} + diff --git a/WebCore/platform/haiku/ScrollbarThemeHaiku.h b/WebCore/platform/haiku/ScrollbarThemeHaiku.h new file mode 100644 index 0000000..18e2cc0 --- /dev/null +++ b/WebCore/platform/haiku/ScrollbarThemeHaiku.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright 2009 Maxime Simon <simon.maxime@gmail.com> All Rights Reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ScrollbarThemeHaiku_h +#define ScrollbarThemeHaiku_h + +#include "ScrollbarThemeComposite.h" + +namespace WebCore { + class Scrollbar; + + class ScrollbarThemeHaiku : public ScrollbarThemeComposite { + public: + ScrollbarThemeHaiku(); + virtual ~ScrollbarThemeHaiku(); + + virtual int scrollbarThickness(ScrollbarControlSize = RegularScrollbar); + + virtual bool hasButtons(Scrollbar*); + virtual bool hasThumb(Scrollbar*); + + virtual IntRect backButtonRect(Scrollbar*, ScrollbarPart, bool painting); + virtual IntRect forwardButtonRect(Scrollbar*, ScrollbarPart, bool painting); + virtual IntRect trackRect(Scrollbar*, bool painting); + + virtual void paintScrollbarBackground(GraphicsContext*, Scrollbar*); + virtual void paintButton(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart); + virtual void paintThumb(GraphicsContext*, Scrollbar*, const IntRect&); + }; + +} +#endif diff --git a/WebCore/platform/haiku/SharedBufferHaiku.cpp b/WebCore/platform/haiku/SharedBufferHaiku.cpp new file mode 100644 index 0000000..113cd2e --- /dev/null +++ b/WebCore/platform/haiku/SharedBufferHaiku.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com> + * + * 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 "SharedBuffer.h" + +#include <File.h> +#include <String.h> + +namespace WebCore { + +PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String& fileName) +{ + if (fileName.isEmpty()) + return 0; + + BFile file(BString(fileName).String(), B_READ_ONLY); + if (file.InitCheck() != B_OK) + return 0; + + RefPtr<SharedBuffer> result = SharedBuffer::create(); + + off_t size; + file.GetSize(&size); + result->m_buffer.resize(size); + if (result->m_buffer.size() != size) + return 0; + + file.Read(result->m_buffer.data(), result->m_buffer.size()); + return result.release(); +} + +} // namespace WebCore diff --git a/WebCore/platform/haiku/SharedTimerHaiku.cpp b/WebCore/platform/haiku/SharedTimerHaiku.cpp new file mode 100644 index 0000000..6265a2a --- /dev/null +++ b/WebCore/platform/haiku/SharedTimerHaiku.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com> + * + * 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 <MessageFilter.h> +#include <MessageRunner.h> +#include <Looper.h> +#include <support/Locker.h> +#include <support/Autolock.h> +#include <wtf/CurrentTime.h> + +#define FIRE_MESSAGE 'fire' + + +namespace WebCore { + +class SharedTimerHaiku: public BMessageFilter { + friend void setSharedTimerFiredFunction(void (*f)()); +public: + static SharedTimerHaiku* instance(); + + void start(double); + void stop(); + +protected: + virtual filter_result Filter(BMessage*, BHandler**); + +private: + SharedTimerHaiku(); + ~SharedTimerHaiku(); + + void (*m_timerFunction)(); + bool m_shouldRun; +}; + +SharedTimerHaiku::SharedTimerHaiku() + : BMessageFilter(FIRE_MESSAGE) + , m_timerFunction(0) + , m_shouldRun(false) +{ +} + +SharedTimerHaiku::~SharedTimerHaiku() +{ +} + +SharedTimerHaiku* SharedTimerHaiku::instance() +{ + BLooper* looper = BLooper::LooperForThread(find_thread(0)); + static SharedTimerHaiku* timer; + + if (!timer) { + BAutolock lock(looper); + timer = new SharedTimerHaiku(); + looper->AddCommonFilter(timer); + } + + return timer; +} + +void SharedTimerHaiku::start(double fireTime) +{ + m_shouldRun = true; + + double intervalInSeconds = fireTime - currentTime(); + bigtime_t intervalInMicroSeconds = intervalInSeconds < 0 ? 0 : intervalInSeconds * 1000000; + + BMessageRunner::StartSending(Looper(), new BMessage(FIRE_MESSAGE), intervalInMicroSeconds, 1); +} + +void SharedTimerHaiku::stop() +{ + m_shouldRun = false; +} + +filter_result SharedTimerHaiku::Filter(BMessage*, BHandler**) +{ + if (m_shouldRun && m_timerFunction) + m_timerFunction(); + + return B_SKIP_MESSAGE; +} + +// WebCore functions +void setSharedTimerFiredFunction(void (*f)()) +{ + SharedTimerHaiku::instance()->m_timerFunction = f; +} + +void setSharedTimerFireTime(double fireTime) +{ + SharedTimerHaiku::instance()->start(fireTime); +} + +void stopSharedTimer() +{ + SharedTimerHaiku::instance()->stop(); +} + +} // namespace WebCore diff --git a/WebCore/platform/haiku/TemporaryLinkStubs.cpp b/WebCore/platform/haiku/TemporaryLinkStubs.cpp index 48380fc..aa3d538 100644 --- a/WebCore/platform/haiku/TemporaryLinkStubs.cpp +++ b/WebCore/platform/haiku/TemporaryLinkStubs.cpp @@ -33,40 +33,11 @@ #include "config.h" -#include "AXObjectCache.h" -#include "CachedResource.h" -#include "CookieJar.h" -#include "Cursor.h" -#include "DataGridColumnList.h" -#include "FileSystem.h" -#include "Font.h" -#include "Frame.h" -#include "FrameView.h" -#include "GraphicsContext.h" -#include "History.h" -#include "IconLoader.h" -#include "InspectorController.h" -#include "IntPoint.h" #include "KURL.h" -#include "Language.h" -#include "Node.h" #include "NotImplemented.h" -#include "Path.h" -#include "PlatformMouseEvent.h" -#include "PlatformScrollBar.h" -#include "PluginInfoStore.h" -#include "RenderTheme.h" -#include "Screen.h" -#include "Scrollbar.h" -#include "ScrollbarTheme.h" -#include "SharedBuffer.h" -#include "TextBoundaries.h" -#include "Threading.h" -#include "Widget.h" -#include "loader.h" -#include <runtime/JSValue.h> -#include <stdio.h> -#include <stdlib.h> +#include "PlatformString.h" +#include "SSLKeyGenerator.h" +#include "SystemTime.h" using namespace WebCore; @@ -78,20 +49,14 @@ Vector<char> loadResourceIntoArray(const char*) namespace WebCore { -bool historyContains(String const&) +String signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String &challengeString, const KURL &url) { - return false; + return String(); } -Vector<String> supportedKeySizes() +void getSupportedKeySizes(Vector<String>&) { notImplemented(); - return Vector<String>(); -} - -String signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String &challengeString, const KURL &url) -{ - return String(); } float userIdleTime() @@ -105,22 +70,11 @@ void callOnMainThread(void (*)()) notImplemented(); } -PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String&) -{ - notImplemented(); - return 0; -} - String KURL::fileSystemPath() const { notImplemented(); return String(); } -void getSupportedKeySizes(Vector<String>&) -{ - notImplemented(); -} - } // namespace WebCore diff --git a/WebCore/platform/image-decoders/ImageDecoder.cpp b/WebCore/platform/image-decoders/ImageDecoder.cpp new file mode 100644 index 0000000..a16b940 --- /dev/null +++ b/WebCore/platform/image-decoders/ImageDecoder.cpp @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2008-2009 Torch Mobile, 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 "ImageDecoder.h" + +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) +#include <algorithm> +#endif + +#include "BMPImageDecoder.h" +#include "GIFImageDecoder.h" +#include "ICOImageDecoder.h" +#include "JPEGImageDecoder.h" +#include "PNGImageDecoder.h" +#include "SharedBuffer.h" +#include "XBMImageDecoder.h" + +namespace WebCore { + +ImageDecoder* ImageDecoder::create(const SharedBuffer& data) +{ + // We need at least 4 bytes to figure out what kind of image we're dealing with. + int length = data.size(); + if (length < 4) + return 0; + + const unsigned char* uContents = (const unsigned char*)data.data(); + const char* contents = data.data(); + + // GIFs begin with GIF8(7 or 9). + if (strncmp(contents, "GIF8", 4) == 0) + return new GIFImageDecoder(); + + // Test for PNG. + if (uContents[0]==0x89 && + uContents[1]==0x50 && + uContents[2]==0x4E && + uContents[3]==0x47) + return new PNGImageDecoder(); + + // JPEG + if (uContents[0]==0xFF && + uContents[1]==0xD8 && + uContents[2]==0xFF) + return new JPEGImageDecoder(); + + // BMP + if (strncmp(contents, "BM", 2) == 0) + return new BMPImageDecoder(); + + // ICOs always begin with a 2-byte 0 followed by a 2-byte 1. + // CURs begin with 2-byte 0 followed by 2-byte 2. + if (!memcmp(contents, "\000\000\001\000", 4) || + !memcmp(contents, "\000\000\002\000", 4)) + return new ICOImageDecoder(); + + // XBMs require 8 bytes of info. + if (length >= 8 && strncmp(contents, "#define ", 8) == 0) + return new XBMImageDecoder(); + + // Give up. We don't know what the heck this is. + return 0; +} + +#if !PLATFORM(SKIA) + +RGBA32Buffer::RGBA32Buffer() + : m_hasAlpha(false) + , m_status(FrameEmpty) + , m_duration(0) + , m_disposalMethod(DisposeNotSpecified) +{ +} + +void RGBA32Buffer::clear() +{ + m_bytes.clear(); + m_status = FrameEmpty; + // NOTE: Do not reset other members here; clearFrameBufferCache() + // calls this to free the bitmap data, but other functions like + // initFrameBuffer() and frameComplete() may still need to read + // other metadata out of this frame later. +} + +void RGBA32Buffer::zeroFill() +{ + m_bytes.fill(0); + m_hasAlpha = true; +} + +void RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other) +{ + if (this == &other) + return; + + m_bytes = other.m_bytes; + m_size = other.m_size; + setHasAlpha(other.m_hasAlpha); +} + +bool RGBA32Buffer::setSize(int newWidth, int newHeight) +{ + // NOTE: This has no way to check for allocation failure if the + // requested size was too big... + m_bytes.resize(newWidth * newHeight); + m_size = IntSize(newWidth, newHeight); + + // Zero the image. + zeroFill(); + + return true; +} + +bool RGBA32Buffer::hasAlpha() const +{ + return m_hasAlpha; +} + +void RGBA32Buffer::setHasAlpha(bool alpha) +{ + m_hasAlpha = alpha; +} + +void RGBA32Buffer::setStatus(FrameStatus status) +{ + m_status = status; +} + +RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other) +{ + if (this == &other) + return *this; + + copyBitmapData(other); + setRect(other.rect()); + setStatus(other.status()); + setDuration(other.duration()); + setDisposalMethod(other.disposalMethod()); + return *this; +} + +int RGBA32Buffer::width() const +{ + return m_size.width(); +} + +int RGBA32Buffer::height() const +{ + return m_size.height(); +} + +#endif + +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + +namespace { + +enum MatchType { + Exact, + UpperBound, + LowerBound +}; + +inline void fillScaledValues(Vector<int>& scaledValues, double scaleRate, int length) +{ + double inflateRate = 1. / scaleRate; + scaledValues.reserveCapacity(static_cast<int>(length * scaleRate + 0.5)); + for (int scaledIndex = 0;;) { + int index = static_cast<int>(scaledIndex * inflateRate + 0.5); + if (index < length) { + scaledValues.append(index); + ++scaledIndex; + } else + break; + } +} + +template <MatchType type> int getScaledValue(const Vector<int>& scaledValues, int valueToMatch, int searchStart) +{ + const int* dataStart = scaledValues.data(); + const int* dataEnd = dataStart + scaledValues.size(); + const int* matched = std::lower_bound(dataStart + searchStart, dataEnd, valueToMatch); + switch (type) { + case Exact: + return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : -1; + case LowerBound: + return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : matched - dataStart - 1; + case UpperBound: + default: + return matched != dataEnd ? matched - dataStart : -1; + } +} + +} + +void ImageDecoder::prepareScaleDataIfNecessary() +{ + int width = m_size.width(); + int height = m_size.height(); + int numPixels = height * width; + if (m_maxNumPixels <= 0 || numPixels <= m_maxNumPixels) { + m_scaled = false; + return; + } + + m_scaled = true; + double scale = sqrt(m_maxNumPixels / (double)numPixels); + fillScaledValues(m_scaledColumns, scale, width); + fillScaledValues(m_scaledRows, scale, height); +} + +int ImageDecoder::upperBoundScaledX(int origX, int searchStart) +{ + return getScaledValue<UpperBound>(m_scaledColumns, origX, searchStart); +} + +int ImageDecoder::lowerBoundScaledX(int origX, int searchStart) +{ + return getScaledValue<LowerBound>(m_scaledColumns, origX, searchStart); +} + +int ImageDecoder::scaledY(int origY, int searchStart) +{ + return getScaledValue<Exact>(m_scaledRows, origY, searchStart); +} + +#endif // ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + +} diff --git a/WebCore/platform/image-decoders/ImageDecoder.h b/WebCore/platform/image-decoders/ImageDecoder.h index 57f8735..37196fe 100644 --- a/WebCore/platform/image-decoders/ImageDecoder.h +++ b/WebCore/platform/image-decoders/ImageDecoder.h @@ -1,5 +1,7 @@ /* * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008-2009 Torch Mobile, Inc. + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,7 +39,8 @@ #if (PLATFORM(SKIA) || PLATFORM(SGL)) // TODO(benm): ANDROID: Can we define PLATFORM(SKIA) instead of PLATFORM(SGL) before upstreaming? #include "NativeImageSkia.h" -#include "SkBitmap.h" +#elif PLATFORM(QT) +#include <QImage> #endif namespace WebCore { @@ -55,7 +58,11 @@ namespace WebCore { DisposeOverwriteBgcolor, // Clear frame to transparent DisposeOverwritePrevious, // Clear frame to previous framebuffer contents }; +<<<<<<< HEAD:WebCore/platform/image-decoders/ImageDecoder.h #if (PLATFORM(SKIA) || PLATFORM(SGL)) +======= +#if PLATFORM(SKIA) || PLATFORM(QT) +>>>>>>> webkit.org at 49305:WebCore/platform/image-decoders/ImageDecoder.h typedef uint32_t PixelData; #else typedef unsigned PixelData; @@ -132,6 +139,11 @@ namespace WebCore { setRGBA(getAddr(x, y), r, g, b, a); } +#if PLATFORM(QT) + void setDecodedImage(const QImage& image); + QImage decodedImage() const { return m_image; } +#endif + private: RGBA32Buffer& operator=(const RGBA32Buffer& other); @@ -140,13 +152,18 @@ namespace WebCore { inline PixelData* getAddr(int x, int y) { +<<<<<<< HEAD:WebCore/platform/image-decoders/ImageDecoder.h #if PLATFORM(CAIRO) || PLATFORM(WX) return m_bytes.data() + (y * width()) + x; #elif (PLATFORM(SKIA) || PLATFORM(SGL)) +======= +#if PLATFORM(SKIA) +>>>>>>> webkit.org at 49305:WebCore/platform/image-decoders/ImageDecoder.h return m_bitmap.getAddr32(x, y); +#elif PLATFORM(QT) + return reinterpret_cast<QRgb*>(m_image.scanLine(y)) + x; #else - ASSERT_NOT_REACHED(); - return 0; + return m_bytes.data() + (y * width()) + x; #endif } @@ -166,13 +183,22 @@ namespace WebCore { } } -#if PLATFORM(CAIRO) || PLATFORM(WX) +#if PLATFORM(SKIA) + NativeImageSkia m_bitmap; +#elif PLATFORM(QT) + mutable QImage m_image; + bool m_hasAlpha; + IntSize m_size; +#else Vector<PixelData> m_bytes; IntSize m_size; // The size of the buffer. This should be the // same as ImageDecoder::m_size. bool m_hasAlpha; // Whether or not any of the pixels in the buffer have transparency. +<<<<<<< HEAD:WebCore/platform/image-decoders/ImageDecoder.h #elif (PLATFORM(SKIA) || PLATFORM(SGL)) NativeImageSkia m_bitmap; +======= +>>>>>>> webkit.org at 49305:WebCore/platform/image-decoders/ImageDecoder.h #endif IntRect m_rect; // The rect of the original specified frame within the overall buffer. // This will always just be the entire buffer except for GIF frames @@ -188,14 +214,27 @@ namespace WebCore { // and the base class manages the RGBA32 frame cache. class ImageDecoder { public: + // ENABLE(IMAGE_DECODER_DOWN_SAMPLING) allows image decoders to write directly to + // scaled output buffers by down sampling. Call setMaxNumPixels() to specify the + // biggest size that decoded images can have. Image decoders will deflate those + // images that are bigger than m_maxNumPixels. (Not supported by all image decoders yet) ImageDecoder() : m_failed(false) , m_sizeAvailable(false) +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + , m_maxNumPixels(-1) + , m_scaled(false) +#endif { } virtual ~ImageDecoder() {} + // Factory function to create an ImageDecoder. Ports that subclass + // ImageDecoder can provide their own implementation of this to avoid + // needing to write a dedicated setData() implementation. + static ImageDecoder* create(const SharedBuffer& data); + // The the filename extension usually associated with an undecoded image of this type. virtual String filenameExtension() const = 0; @@ -272,8 +311,25 @@ namespace WebCore { // since in practice only GIFs will ever use this. virtual void clearFrameBufferCache(size_t clearBeforeFrame) { } +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + void setMaxNumPixels(int m) { m_maxNumPixels = m; } +#endif + protected: +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + void prepareScaleDataIfNecessary(); + int upperBoundScaledX(int origX, int searchStart = 0); + int lowerBoundScaledX(int origX, int searchStart = 0); + int scaledY(int origY, int searchStart = 0); +#endif + RefPtr<SharedBuffer> m_data; // The encoded data. +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + int m_maxNumPixels; + Vector<int> m_scaledColumns; + Vector<int> m_scaledRows; + bool m_scaled; +#endif Vector<RGBA32Buffer> m_frameBufferCache; bool m_failed; diff --git a/WebCore/platform/image-decoders/cairo/ImageDecoderCairo.cpp b/WebCore/platform/image-decoders/cairo/ImageDecoderCairo.cpp index c53eabd..203205d 100644 --- a/WebCore/platform/image-decoders/cairo/ImageDecoderCairo.cpp +++ b/WebCore/platform/image-decoders/cairo/ImageDecoderCairo.cpp @@ -30,53 +30,6 @@ namespace WebCore { -RGBA32Buffer::RGBA32Buffer() - : m_hasAlpha(false) - , m_status(FrameEmpty) - , m_duration(0) - , m_disposalMethod(DisposeNotSpecified) -{ -} - -void RGBA32Buffer::clear() -{ - m_bytes.clear(); - m_status = FrameEmpty; - // NOTE: Do not reset other members here; clearFrameBufferCache() - // calls this to free the bitmap data, but other functions like - // initFrameBuffer() and frameComplete() may still need to read - // other metadata out of this frame later. -} - -void RGBA32Buffer::zeroFill() -{ - m_bytes.fill(0); - m_hasAlpha = true; -} - -void RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other) -{ - if (this == &other) - return; - - m_bytes = other.m_bytes; - m_size = other.m_size; - setHasAlpha(other.m_hasAlpha); -} - -bool RGBA32Buffer::setSize(int newWidth, int newHeight) -{ - // NOTE: This has no way to check for allocation failure if the - // requested size was too big... - m_bytes.resize(newWidth * newHeight); - m_size = IntSize(newWidth, newHeight); - - // Zero the image. - zeroFill(); - - return true; -} - NativeImagePtr RGBA32Buffer::asNewNativeImage() const { return cairo_image_surface_create_for_data( @@ -85,40 +38,4 @@ NativeImagePtr RGBA32Buffer::asNewNativeImage() const width() * sizeof(PixelData)); } -bool RGBA32Buffer::hasAlpha() const -{ - return m_hasAlpha; -} - -void RGBA32Buffer::setHasAlpha(bool alpha) -{ - m_hasAlpha = alpha; -} - -void RGBA32Buffer::setStatus(FrameStatus status) -{ - m_status = status; -} - -RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other) -{ - if (this == &other) - return *this; - - copyBitmapData(other); - setRect(other.rect()); - setStatus(other.status()); - setDuration(other.duration()); - setDisposalMethod(other.disposalMethod()); - return *this; -} - -int RGBA32Buffer::width() const { - return m_size.width(); -} - -int RGBA32Buffer::height() const { - return m_size.height(); -} - } // namespace WebCore diff --git a/WebCore/platform/image-decoders/haiku/ImageDecoderHaiku.cpp b/WebCore/platform/image-decoders/haiku/ImageDecoderHaiku.cpp index 3542cc2..dc120e3 100644 --- a/WebCore/platform/image-decoders/haiku/ImageDecoderHaiku.cpp +++ b/WebCore/platform/image-decoders/haiku/ImageDecoderHaiku.cpp @@ -28,104 +28,14 @@ #include <Bitmap.h> - namespace WebCore { -RGBA32Buffer::RGBA32Buffer() - : m_hasAlpha(false) - , m_status(FrameEmpty) - , m_duration(0) - , m_disposalMethod(DisposeNotSpecified) -{ -} - -void RGBA32Buffer::clear() -{ - m_bytes.clear(); - m_status = FrameEmpty; - // NOTE: Do not reset other members here; clearFrameBufferCache() - // calls this to free the bitmap data, but other functions like - // initFrameBuffer() and frameComplete() may still need to read - // other metadata out of this frame later. -} - -void RGBA32Buffer::zeroFill() -{ - m_bytes.fill(0); - m_hasAlpha = true; -} - -void RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other) -{ - if (this == &other) - return; - - m_bytes = other.m_bytes; - setHasAlpha(other.m_hasAlpha); -} - -bool RGBA32Buffer::setSize(int newWidth, int newHeight) -{ - // NOTE: This has no way to check for allocation failure if the - // requested size was too big... - m_bytes.resize(newWidth * newHeight); - m_size = IntSize(newWidth, newHeight); - - // Zero the image. - zeroFill(); - - return true; -} - NativeImagePtr RGBA32Buffer::asNewNativeImage() const { - const void* bytes = m_bytes.data(); - BBitmap* bmp = new BBitmap(BRect(0, 0, width(), height()), B_RGB32); - bmp->SetBits(bytes, m_size.width() * m_size.height(), 0, B_RGB32); - + bmp->SetBits(m_bytes.data(), m_size.width() * m_size.height(), 0, B_RGB32); return bmp; } -bool RGBA32Buffer::hasAlpha() const -{ - return m_hasAlpha; -} - -void RGBA32Buffer::setHasAlpha(bool alpha) -{ - m_hasAlpha = alpha; -} - -void RGBA32Buffer::setStatus(FrameStatus status) -{ - m_status = status; -} - -RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other) -{ - if (this == &other) - return *this; - - m_bytes = other.m_bytes; - m_size = other.m_size; - setHasAlpha(other.hasAlpha()); - setRect(other.rect()); - setStatus(other.status()); - setDuration(other.duration()); - setDisposalMethod(other.disposalMethod()); - return *this; -} - -int RGBA32Buffer::width() const -{ - return m_size.width(); -} - -int RGBA32Buffer::height() const -{ - return m_size.height(); -} - } // namespace WebCore diff --git a/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp b/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp index e9296ad..a0ec4f7 100644 --- a/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp +++ b/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp @@ -51,12 +51,6 @@ ICOImageDecoder::ICOImageDecoder() { } -ICOImageDecoder::~ICOImageDecoder() -{ - deleteAllValues(m_bmpReaders); - deleteAllValues(m_pngDecoders); -} - void ICOImageDecoder::setData(SharedBuffer* data, bool allDataReceived) { if (failed()) @@ -208,12 +202,12 @@ bool ICOImageDecoder::decodeAtIndex(size_t index) // We need to have already sized m_frameBufferCache before this, and // we must not resize it again later (see caution in frameCount()). ASSERT(m_frameBufferCache.size() == m_dirEntries.size()); - m_bmpReaders[index] = - new BMPImageReader(this, dirEntry.m_imageOffset, 0, true); + m_bmpReaders[index].set( + new BMPImageReader(this, dirEntry.m_imageOffset, 0, true)); m_bmpReaders[index]->setData(m_data.get()); m_bmpReaders[index]->setBuffer(&m_frameBufferCache[index]); } else if (imageType == PNG) { - m_pngDecoders[index] = new PNGImageDecoder(); + m_pngDecoders[index].set(new PNGImageDecoder()); setDataForPNGDecoderAtIndex(index); } else { // Not enough data to determine image type yet. @@ -249,18 +243,15 @@ bool ICOImageDecoder::processDirectory() ICON = 1, CURSOR = 2, }; - if (((fileType != ICON) && (fileType != CURSOR)) || (idCount == 0)) { + if (((fileType != ICON) && (fileType != CURSOR)) || (!idCount)) { setFailed(); return false; } - // Enlarge member vectors to hold all the entries. We must initialize the - // BMP and PNG decoding vectors to 0 so that all entries can be safely - // deleted in our destructor. If we don't do this, they'll contain garbage - // values, and deleting those will corrupt memory. + // Enlarge member vectors to hold all the entries. m_dirEntries.resize(idCount); - m_bmpReaders.fill(0, idCount); - m_pngDecoders.fill(0, idCount); + m_bmpReaders.resize(idCount); + m_pngDecoders.resize(idCount); return true; } @@ -303,10 +294,10 @@ ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry() // matching uint8_ts) is so we can record dimensions of size 256 (which is // what a zero byte really means). int width = static_cast<uint8_t>(m_data->data()[m_decodedOffset]); - if (width == 0) + if (!width) width = 256; int height = static_cast<uint8_t>(m_data->data()[m_decodedOffset + 1]); - if (height == 0) + if (!height) height = 256; IconDirectoryEntry entry; entry.m_size = IntSize(width, height); @@ -318,11 +309,12 @@ ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry() // this isn't quite what the bitmap info header says later, as we only use // this value to determine which icon entry is best. if (!entry.m_bitCount) { - uint8_t colorCount = m_data->data()[m_decodedOffset + 2]; - if (colorCount) { - for (--colorCount; colorCount; colorCount >>= 1) - ++entry.m_bitCount; - } + int colorCount = + static_cast<uint8_t>(m_data->data()[m_decodedOffset + 2]); + if (!colorCount) + colorCount = 256; // Vague in the spec, needed by real-world icons. + for (--colorCount; colorCount; colorCount >>= 1) + ++entry.m_bitCount; } m_decodedOffset += sizeOfDirEntry; diff --git a/WebCore/platform/image-decoders/ico/ICOImageDecoder.h b/WebCore/platform/image-decoders/ico/ICOImageDecoder.h index f8bddf9..6117e06 100644 --- a/WebCore/platform/image-decoders/ico/ICOImageDecoder.h +++ b/WebCore/platform/image-decoders/ico/ICOImageDecoder.h @@ -41,7 +41,6 @@ namespace WebCore { class ICOImageDecoder : public ImageDecoder { public: ICOImageDecoder(); - virtual ~ICOImageDecoder(); // ImageDecoder virtual String filenameExtension() const { return "ico"; } @@ -134,9 +133,9 @@ namespace WebCore { IconDirectoryEntries m_dirEntries; // The image decoders for the various frames. - typedef Vector<BMPImageReader*> BMPReaders; + typedef Vector<OwnPtr<BMPImageReader> > BMPReaders; BMPReaders m_bmpReaders; - typedef Vector<PNGImageDecoder*> PNGDecoders; + typedef Vector<OwnPtr<PNGImageDecoder> > PNGDecoders; PNGDecoders m_pngDecoders; // Valid only while a BMPImageReader is decoding, this holds the size diff --git a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp index ae09586..410ef60 100644 --- a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp +++ b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp @@ -461,11 +461,27 @@ void JPEGImageDecoder::decode(bool sizeOnly) } } -static void convertCMYKToRGBA(RGBA32Buffer& dest, JSAMPROW src, jpeg_decompress_struct* info) +static void convertCMYKToRGBA(RGBA32Buffer& dest, int destY, JSAMPROW src, JDIMENSION srcWidth +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + , bool scaled, const Vector<int>& scaledColumns +#endif + ) { - ASSERT(info->out_color_space == JCS_CMYK); - - for (unsigned x = 0; x < info->output_width; ++x) { +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + if (scaled) { + int numColumns = scaledColumns.size(); + for (int x = 0; x < numColumns; ++x) { + JSAMPLE* jsample = src + scaledColumns[x] * 3; + unsigned c = jsample[0]; + unsigned m = jsample[1]; + unsigned y = jsample[2]; + unsigned k = jsample[3]; + dest.setRGBA(x, destY, c * k / 255, m * k / 255, y * k / 255, 0xFF); + } + return; + } +#endif + for (JDIMENSION x = 0; x < srcWidth; ++x) { unsigned c = *src++; unsigned m = *src++; unsigned y = *src++; @@ -489,23 +505,31 @@ static void convertCMYKToRGBA(RGBA32Buffer& dest, JSAMPROW src, jpeg_decompress_ // G = 1 - M => 1 - (1 - iM*iK) => iM*iK // B = 1 - Y => 1 - (1 - iY*iK) => iY*iK - // read_scanlines has increased the scanline counter, so we - // actually mean the previous one. - dest.setRGBA(x, info->output_scanline - 1, c * k / 255, m * k / 255, y * k / 255, 0xFF); + dest.setRGBA(x, destY, c * k / 255, m * k / 255, y * k / 255, 0xFF); } } -static void convertRGBToRGBA(RGBA32Buffer& dest, JSAMPROW src, jpeg_decompress_struct* info) +static void convertRGBToRGBA(RGBA32Buffer& dest, int destY, JSAMPROW src, JDIMENSION srcWidth +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + , bool scaled, const Vector<int>& scaledColumns +#endif + ) { - ASSERT(info->out_color_space == JCS_RGB); - - for (unsigned x = 0; x < info->output_width; ++x) { +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + if (scaled) { + int numColumns = scaledColumns.size(); + for (int x = 0; x < numColumns; ++x) { + JSAMPLE* jsample = src + scaledColumns[x] * 3; + dest.setRGBA(x, destY, jsample[0], jsample[1], jsample[2], 0xFF); + } + return; + } +#endif + for (JDIMENSION x = 0; x < srcWidth; ++x) { unsigned r = *src++; unsigned g = *src++; unsigned b = *src++; - // read_scanlines has increased the scanline counter, so we - // actually mean the previous one. - dest.setRGBA(x, info->output_scanline - 1, r, g, b, 0xFF); + dest.setRGBA(x, destY, r, g, b, 0xFF); } } @@ -517,7 +541,17 @@ bool JPEGImageDecoder::outputScanlines() // Initialize the framebuffer if needed. RGBA32Buffer& buffer = m_frameBufferCache[0]; if (buffer.status() == RGBA32Buffer::FrameEmpty) { - if (!buffer.setSize(size().width(), size().height())) { + int bufferWidth = size().width(); + int bufferHeight = size().height(); +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + // Let's resize our buffer now to the correct width/height. + if (m_scaled) { + bufferWidth = m_scaledColumns.size(); + bufferHeight = m_scaledRows.size(); + } +#endif + + if (!buffer.setSize(bufferWidth, bufferHeight)) { m_failed = true; return false; } @@ -532,16 +566,34 @@ bool JPEGImageDecoder::outputScanlines() JSAMPARRAY samples = m_reader->samples(); while (info->output_scanline < info->output_height) { + // jpeg_read_scanlines will increase the scanline counter, so we + // save the scanline before calling it. + int sourceY = info->output_scanline; /* Request one scanline. Returns 0 or 1 scanlines. */ if (jpeg_read_scanlines(info, samples, 1) != 1) return false; + int destY = sourceY; +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + if (m_scaled) { + destY = scaledY(sourceY); + if (destY < 0) + continue; + } if (info->out_color_space == JCS_RGB) - convertRGBToRGBA(buffer, *samples, info); + convertRGBToRGBA(buffer, destY, *samples, info->output_width, m_scaled, m_scaledColumns); else if (info->out_color_space == JCS_CMYK) - convertCMYKToRGBA(buffer, *samples, info); + convertCMYKToRGBA(buffer, destY, *samples, info->output_width, m_scaled, m_scaledColumns); else return false; +#else + if (info->out_color_space == JCS_RGB) + convertRGBToRGBA(buffer, destY, *samples, info->output_width); + else if (info->out_color_space == JCS_CMYK) + convertCMYKToRGBA(buffer, destY, *samples, info->output_width); + else + return false; +#endif } return true; diff --git a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h index 56e007d..4a822d7 100644 --- a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h +++ b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008-2009 Torch Mobile, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -57,6 +58,16 @@ namespace WebCore { bool outputScanlines(); void jpegComplete(); +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + bool setSize(int width, int height) + { + if (!ImageDecoder::setSize(width, height)) + return false; + prepareScaleDataIfNecessary(); + return true; + } +#endif + private: JPEGImageReader* m_reader; }; diff --git a/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp b/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp index d14333f..ad79fc8 100644 --- a/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp +++ b/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2007-2009 Torch Mobile, Inc. * * Portions are Copyright (C) 2001 mozilla.org * @@ -242,6 +243,9 @@ void PNGImageDecoder::headerAvailable() longjmp(png->jmpbuf, 1); return; } +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + prepareScaleDataIfNecessary(); +#endif } int bitDepth, colorType, interlaceType, compressionType, filterType, channels; @@ -313,7 +317,14 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, // Initialize the framebuffer if needed. RGBA32Buffer& buffer = m_frameBufferCache[0]; if (buffer.status() == RGBA32Buffer::FrameEmpty) { - if (!buffer.setSize(size().width(), size().height())) { +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + int width = m_scaled ? m_scaledColumns.size() : size().width(); + int height = m_scaled ? m_scaledRows.size() : size().height(); +#else + int width = size().width(); + int height = size().height(); +#endif + if (!buffer.setSize(width, height)) { static_cast<PNGImageDecoder*>(png_get_progressive_ptr(reader()->pngPtr()))->decodingFailed(); longjmp(reader()->pngPtr()->jmpbuf, 1); return; @@ -358,7 +369,7 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, * to pass the current row, and the function will combine the * old row and the new row. */ - + png_structp png = reader()->pngPtr(); bool hasAlpha = reader()->hasAlpha(); unsigned colorChannels = hasAlpha ? 4 : 3; @@ -372,8 +383,27 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, row = rowBuffer; // Copy the data into our buffer. +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + if (m_scaled) { + int destY = scaledY(rowIndex); + if (destY < 0) + return; + int columns = m_scaledColumns.size(); + bool sawAlpha = buffer.hasAlpha(); + for (int x = 0; x < columns; ++x) { + png_bytep pixel = row + m_scaledColumns[x] * 4; + unsigned alpha = pixel[3]; + buffer.setRGBA(x, destY, pixel[0], pixel[1], pixel[2], alpha); + if (!sawAlpha && alpha < 255) { + sawAlpha = true; + buffer.setHasAlpha(true); + } + } + return; + } +#endif int width = size().width(); - bool sawAlpha = false; + bool sawAlpha = buffer.hasAlpha(); for (int x = 0; x < width; x++) { unsigned red = *row++; unsigned green = *row++; diff --git a/WebCore/platform/image-decoders/qt/RGBA32BufferQt.cpp b/WebCore/platform/image-decoders/qt/RGBA32BufferQt.cpp new file mode 100644 index 0000000..da6ab38 --- /dev/null +++ b/WebCore/platform/image-decoders/qt/RGBA32BufferQt.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008, 2009 Google, Inc. + * Copyright (C) 2009 Holger Hans Peter Freyther + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ImageDecoder.h" + +#include <QPixmap> +#include <stdio.h> + +namespace WebCore { + +RGBA32Buffer::RGBA32Buffer() + : m_status(FrameEmpty) + , m_hasAlpha(false) + , m_size() + , m_duration(0) + , m_disposalMethod(DisposeNotSpecified) +{ +} + +// The image must not have format 8888 pre multiplied... +void RGBA32Buffer::setDecodedImage(const QImage& image) +{ + m_image = image; + m_size = image.size(); + m_hasAlpha = image.hasAlphaChannel(); +} + +void RGBA32Buffer::clear() +{ + m_image = QImage(); + m_status = FrameEmpty; + // NOTE: Do not reset other members here; clearFrameBufferCache() + // calls this to free the bitmap data, but other functions like + // initFrameBuffer() and frameComplete() may still need to read + // other metadata out of this frame later. +} + +void RGBA32Buffer::zeroFill() +{ + m_image.fill(0); +} + +void RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other) +{ + if (this == &other) + return; + + m_image = other.m_image; + m_size = other.m_size; + m_hasAlpha = other.m_hasAlpha; +} + +bool RGBA32Buffer::setSize(int newWidth, int newHeight) +{ + // This function should only be called once, it will leak memory + // otherwise. + ASSERT(width() == 0 && height() == 0); + + m_size = IntSize(newWidth, newHeight); + m_image = QImage(newWidth, newHeight, QImage::Format_ARGB32_Premultiplied); + if (m_image.isNull()) { + // Allocation failure, maybe the bitmap was too big. + setStatus(FrameComplete); + return false; + } + + // Zero the image. + zeroFill(); + + return true; +} + +QPixmap* RGBA32Buffer::asNewNativeImage() const +{ + QPixmap pix = QPixmap::fromImage(m_image); + m_image = QImage(); + + return new QPixmap(pix); +} + +bool RGBA32Buffer::hasAlpha() const +{ + return m_hasAlpha; +} + +void RGBA32Buffer::setHasAlpha(bool alpha) +{ + m_hasAlpha = alpha; +} + +void RGBA32Buffer::setStatus(FrameStatus status) +{ + m_status = status; +} + +RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other) +{ + if (this == &other) + return *this; + + copyBitmapData(other); + setRect(other.rect()); + setStatus(other.status()); + setDuration(other.duration()); + setDisposalMethod(other.disposalMethod()); + return *this; +} + +int RGBA32Buffer::width() const +{ + return m_size.width(); +} + +int RGBA32Buffer::height() const +{ + return m_size.height(); +} + +} diff --git a/WebCore/platform/image-decoders/wx/ImageDecoderWx.cpp b/WebCore/platform/image-decoders/wx/ImageDecoderWx.cpp index 8e8809e..3cadf1c 100644 --- a/WebCore/platform/image-decoders/wx/ImageDecoderWx.cpp +++ b/WebCore/platform/image-decoders/wx/ImageDecoderWx.cpp @@ -37,73 +37,21 @@ namespace WebCore { -RGBA32Buffer::RGBA32Buffer() - : m_hasAlpha(false) - , m_status(FrameEmpty) - , m_duration(0) - , m_disposalMethod(DisposeNotSpecified) -{ -} - -void RGBA32Buffer::clear() -{ - m_bytes.clear(); - m_status = FrameEmpty; - // NOTE: Do not reset other members here; clearFrameBufferCache() - // calls this to free the bitmap data, but other functions like - // initFrameBuffer() and frameComplete() may still need to read - // other metadata out of this frame later. -} - -void RGBA32Buffer::zeroFill() -{ - m_bytes.fill(0); - m_hasAlpha = true; -} - -void RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other) -{ - if (this == &other) - return; - - m_bytes = other.m_bytes; - m_size = other.m_size; - setHasAlpha(other.m_hasAlpha); -} - -bool RGBA32Buffer::setSize(int newWidth, int newHeight) -{ - // NOTE: This has no way to check for allocation failure if the - // requested size was too big... - m_bytes.resize(newWidth * newHeight); - m_size = IntSize(newWidth, newHeight); - - // Zero the image. - zeroFill(); - - return true; -} - NativeImagePtr RGBA32Buffer::asNewNativeImage() const { - const unsigned char* bytes = (const unsigned char*)m_bytes.data(); - - typedef wxPixelData<wxBitmap, wxAlphaPixelFormat> WxPixelData; - wxBitmap* bmp = new wxBitmap(width(), height(), 32); + typedef wxPixelData<wxBitmap, wxAlphaPixelFormat> WxPixelData; WxPixelData data(*bmp); + // NB: It appears that the data is in BGRA format instead of RGBA format. + // This code works properly on both ppc and intel, meaning the issue is + // likely not an issue of byte order getting mixed up on different archs. + const unsigned char* bytes = (const unsigned char*)m_bytes.data(); int rowCounter = 0; long pixelCounter = 0; - WxPixelData::Iterator p(data); - WxPixelData::Iterator rowStart = p; - - // NB: It appears that the data is in BGRA format instead of RGBA format. - // This code works properly on both ppc and intel, meaning the issue is - // likely not an issue of byte order getting mixed up on different archs. - for (long i = 0; i < m_bytes.size() * sizeof(PixelData); i += sizeof(PixelData)) { + for (size_t i = 0; i < m_bytes.size() * sizeof(PixelData); i += sizeof(PixelData)) { p.Red() = bytes[i+2]; p.Green() = bytes[i+1]; p.Blue() = bytes[i+0]; @@ -112,12 +60,11 @@ NativeImagePtr RGBA32Buffer::asNewNativeImage() const p++; pixelCounter++; - if ( (pixelCounter % width() ) == 0 ) { + if ((pixelCounter % width()) == 0) { rowCounter++; p = rowStart; p.MoveTo(data, 0, rowCounter); } - } #if !wxCHECK_VERSION(2,9,0) bmp->UseAlpha(); @@ -125,7 +72,7 @@ NativeImagePtr RGBA32Buffer::asNewNativeImage() const ASSERT(bmp->IsOk()); #if USE(WXGC) - wxGraphicsBitmap* bitmap = new wxGraphicsBitmap(wxGraphicsRenderer::GetDefaultRenderer()->CreateBitmap(*bmp)); + wxGraphicsBitmap* bitmap = new wxGraphicsBitmap(wxGraphicsRenderer::GetDefaultRenderer()->CreateBitmap(*bmp)); delete bmp; return bitmap; #else @@ -133,40 +80,4 @@ NativeImagePtr RGBA32Buffer::asNewNativeImage() const #endif } -bool RGBA32Buffer::hasAlpha() const -{ - return m_hasAlpha; -} - -void RGBA32Buffer::setHasAlpha(bool alpha) -{ - m_hasAlpha = alpha; -} - -void RGBA32Buffer::setStatus(FrameStatus status) -{ - m_status = status; -} - -RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other) -{ - if (this == &other) - return *this; - - copyBitmapData(other); - setRect(other.rect()); - setStatus(other.status()); - setDuration(other.duration()); - setDisposalMethod(other.disposalMethod()); - return *this; -} - -int RGBA32Buffer::width() const { - return m_size.width(); -} - -int RGBA32Buffer::height() const { - return m_size.height(); -} - } // namespace WebCore diff --git a/WebCore/platform/mac/ClipboardMac.h b/WebCore/platform/mac/ClipboardMac.h index 9bdd276..3d3c78e 100644 --- a/WebCore/platform/mac/ClipboardMac.h +++ b/WebCore/platform/mac/ClipboardMac.h @@ -67,7 +67,9 @@ public: void setDragImageElement(Node *, const IntPoint&); virtual DragImageRef createDragImage(IntPoint& dragLoc) const; +#if ENABLE(DRAG_SUPPORT) virtual void declareAndWriteDragImage(Element*, const KURL&, const String& title, Frame*); +#endif virtual void writeRange(Range*, Frame* frame); virtual void writeURL(const KURL&, const String&, Frame* frame); diff --git a/WebCore/platform/mac/ClipboardMac.mm b/WebCore/platform/mac/ClipboardMac.mm index 52bc952..78fb659 100644 --- a/WebCore/platform/mac/ClipboardMac.mm +++ b/WebCore/platform/mac/ClipboardMac.mm @@ -63,7 +63,7 @@ bool ClipboardMac::hasData() return m_pasteboard && [m_pasteboard.get() types] && [[m_pasteboard.get() types] count] > 0; } -static NSString *cocoaTypeFromMIMEType(const String& type) +static NSString *cocoaTypeFromHTMLClipboardType(const String& type) { String qType = type.stripWhiteSpace(); @@ -82,10 +82,9 @@ static NSString *cocoaTypeFromMIMEType(const String& type) // Try UTI now NSString *mimeType = qType; - CFStringRef UTIType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (CFStringRef)mimeType, NULL); - if (UTIType) { - CFStringRef pbType = UTTypeCopyPreferredTagWithClass(UTIType, kUTTagClassNSPboardType); - CFRelease(UTIType); + RetainPtr<CFStringRef> utiType(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (CFStringRef)mimeType, NULL)); + if (utiType) { + CFStringRef pbType = UTTypeCopyPreferredTagWithClass(utiType.get(), kUTTagClassNSPboardType); if (pbType) return HardAutorelease(pbType); } @@ -94,28 +93,41 @@ static NSString *cocoaTypeFromMIMEType(const String& type) return qType; } -static String MIMETypeFromCocoaType(NSString *type) +static String utiTypeFromCocoaType(NSString *type) +{ + RetainPtr<CFStringRef> utiType(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassNSPboardType, (CFStringRef)type, NULL)); + if (utiType) { + RetainPtr<CFStringRef> mimeType(AdoptCF, UTTypeCopyPreferredTagWithClass(utiType.get(), kUTTagClassMIMEType)); + if (mimeType) + return String(mimeType.get()); + } + return String(); +} + +static void addHTMLClipboardTypesForCocoaType(HashSet<String>& resultTypes, NSString *cocoaType, NSPasteboard *pasteboard) { // UTI may not do these right, so make sure we get the right, predictable result - if ([type isEqualToString:NSStringPboardType]) - return "text/plain"; - if ([type isEqualToString:NSURLPboardType] || [type isEqualToString:NSFilenamesPboardType]) - return "text/uri-list"; - - // Now try the general UTI mechanism - CFStringRef UTIType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassNSPboardType, (CFStringRef)type, NULL); - if (UTIType) { - CFStringRef mimeType = UTTypeCopyPreferredTagWithClass(UTIType, kUTTagClassMIMEType); - CFRelease(UTIType); - if (mimeType) { - String result = mimeType; - CFRelease(mimeType); - return result; + if ([cocoaType isEqualToString:NSStringPboardType]) + resultTypes.add("text/plain"); + else if ([cocoaType isEqualToString:NSURLPboardType]) + resultTypes.add("text/uri-list"); + else if ([cocoaType isEqualToString:NSFilenamesPboardType]) { + // If file list is empty, add nothing. + // Note that there is a chance that the file list count could have changed since we grabbed the types array. + // However, this is not really an issue for us doing a sanity check here. + NSArray *fileList = [pasteboard propertyListForType:NSFilenamesPboardType]; + if ([fileList count]) { + // It is unknown if NSFilenamesPboardType always implies NSURLPboardType in Cocoa, + // but NSFilenamesPboardType should imply both 'text/uri-list' and 'Files' + resultTypes.add("text/uri-list"); + resultTypes.add("Files"); } + } else if (String utiType = utiTypeFromCocoaType(cocoaType)) + resultTypes.add(utiType); + else { + // No mapping, just pass the whole string though + resultTypes.add(cocoaType); } - - // No mapping, just pass the whole string though - return type; } void ClipboardMac::clearData(const String& type) @@ -125,7 +137,7 @@ void ClipboardMac::clearData(const String& type) // note NSPasteboard enforces changeCount itself on writing - can't write if not the owner - NSString *cocoaType = cocoaTypeFromMIMEType(type); + NSString *cocoaType = cocoaTypeFromHTMLClipboardType(type); if (cocoaType) [m_pasteboard.get() setString:@"" forType:cocoaType]; } @@ -192,12 +204,12 @@ String ClipboardMac::getData(const String& type, bool& success) const if (policy() != ClipboardReadable) return String(); - NSString *cocoaType = cocoaTypeFromMIMEType(type); + NSString *cocoaType = cocoaTypeFromHTMLClipboardType(type); NSString *cocoaValue = nil; // Grab the value off the pasteboard corresponding to the cocoaType if ([cocoaType isEqualToString:NSURLPboardType]) { - // "URL" and "text/url-list" both map to NSURLPboardType in cocoaTypeFromMIMEType(), "URL" only wants the first URL + // "URL" and "text/url-list" both map to NSURLPboardType in cocoaTypeFromHTMLClipboardType(), "URL" only wants the first URL bool onlyFirstURL = (type == "URL"); NSArray *absoluteURLs = absoluteURLsFromPasteboard(m_pasteboard.get(), onlyFirstURL); cocoaValue = [absoluteURLs componentsJoinedByString:@"\n"]; @@ -222,7 +234,7 @@ bool ClipboardMac::setData(const String &type, const String &data) return false; // note NSPasteboard enforces changeCount itself on writing - can't write if not the owner - NSString *cocoaType = cocoaTypeFromMIMEType(type); + NSString *cocoaType = cocoaTypeFromHTMLClipboardType(type); NSString *cocoaData = data; if ([cocoaType isEqualToString:NSURLPboardType]) { @@ -263,15 +275,16 @@ HashSet<String> ClipboardMac::types() const HashSet<String> result; NSUInteger count = [types count]; + // FIXME: This loop could be split into two stages. One which adds all the HTML5 specified types + // and a second which adds all the extra types from the cocoa clipboard (which is Mac-only behavior). for (NSUInteger i = 0; i < count; i++) { NSString *pbType = [types objectAtIndex:i]; if ([pbType isEqualToString:@"NeXT plain ascii pasteboard type"]) continue; // skip this ancient type that gets auto-supplied by some system conversion - String str = MIMETypeFromCocoaType(pbType); - if (!result.contains(str)) - result.add(str); + addHTMLClipboardTypesForCocoaType(result, pbType, m_pasteboard.get()); } + return result; } @@ -283,7 +296,7 @@ PassRefPtr<FileList> ClipboardMac::files() const if (policy() != ClipboardReadable) return FileList::create(); - NSArray *absoluteURLs = absoluteURLsFromPasteboard(m_pasteboard.get()); + NSArray *absoluteURLs = absoluteURLsFromPasteboardFilenames(m_pasteboard.get()); NSUInteger count = [absoluteURLs count]; RefPtr<FileList> fileList = FileList::create(); @@ -355,12 +368,14 @@ void ClipboardMac::writeURL(const KURL& url, const String& title, Frame* frame) Pasteboard::writeURL(m_pasteboard.get(), nil, url, title, frame); } +#if ENABLE(DRAG_SUPPORT) void ClipboardMac::declareAndWriteDragImage(Element* element, const KURL& url, const String& title, Frame* frame) { ASSERT(frame); if (Page* page = frame->page()) page->dragController()->client()->declareAndWriteDragImage(m_pasteboard.get(), kit(element), url, title, frame); } +#endif // ENABLE(DRAG_SUPPORT) DragImageRef ClipboardMac::createDragImage(IntPoint& loc) const { diff --git a/WebCore/platform/mac/ContextMenuItemMac.mm b/WebCore/platform/mac/ContextMenuItemMac.mm index c5e2942..48da786 100644 --- a/WebCore/platform/mac/ContextMenuItemMac.mm +++ b/WebCore/platform/mac/ContextMenuItemMac.mm @@ -26,6 +26,8 @@ #include "config.h" #include "ContextMenuItem.h" +#if ENABLE(CONTEXT_MENUS) + #include "ContextMenu.h" namespace WebCore { @@ -152,4 +154,6 @@ bool ContextMenuItem::enabled() const return [m_platformDescription.get() isEnabled]; } -} +} // namespace WebCore + +#endif // ENABLE(CONTEXT_MENUS) diff --git a/WebCore/platform/mac/ContextMenuMac.mm b/WebCore/platform/mac/ContextMenuMac.mm index b56d0b9..8ced8cb 100644 --- a/WebCore/platform/mac/ContextMenuMac.mm +++ b/WebCore/platform/mac/ContextMenuMac.mm @@ -26,6 +26,8 @@ #include "config.h" #include "ContextMenu.h" +#if ENABLE(CONTEXT_MENUS) + #include "ContextMenuController.h" @interface WebCoreMenuTarget : NSObject { @@ -151,4 +153,6 @@ NSMutableArray* ContextMenu::releasePlatformDescription() return m_platformDescription.releaseRef(); } -} +} // namespace WebCore + +#endif // ENABLE(CONTEXT_MENUS) diff --git a/WebCore/platform/mac/CookieJar.mm b/WebCore/platform/mac/CookieJar.mm index d8df601..e1d3e5a 100644 --- a/WebCore/platform/mac/CookieJar.mm +++ b/WebCore/platform/mac/CookieJar.mm @@ -27,6 +27,7 @@ #import "CookieJar.h" #import "BlockExceptions.h" +#import "Cookie.h" #import "Document.h" #import "KURL.h" #import <wtf/RetainPtr.h> @@ -116,4 +117,52 @@ bool cookiesEnabled(const Document*) return false; } +bool getRawCookies(const Document*, const KURL& url, Vector<Cookie>& rawCookies) +{ + rawCookies.clear(); + BEGIN_BLOCK_OBJC_EXCEPTIONS; + + NSURL *cookieURL = url; + NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:cookieURL]; + + NSUInteger count = [cookies count]; + rawCookies.reserveCapacity(count); + for (NSUInteger i = 0; i < count; ++i) { + NSHTTPCookie *cookie = (NSHTTPCookie *)[cookies objectAtIndex:i]; + NSString *name = [cookie name]; + NSString *value = [cookie value]; + NSString *domain = [cookie domain]; + NSString *path = [cookie path]; + NSTimeInterval expires = [[cookie expiresDate] timeIntervalSince1970] * 1000; + bool httpOnly = [cookie isHTTPOnly]; + bool secure = [cookie isSecure]; + bool session = [cookie isSessionOnly]; + rawCookies.uncheckedAppend(Cookie(name, value, domain, path, expires, httpOnly, secure, session)); + } + + END_BLOCK_OBJC_EXCEPTIONS; + return true; +} + +void deleteCookie(const Document*, const KURL& url, const String& cookieName) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + + NSURL *cookieURL = url; + NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + NSArray *cookies = [cookieStorage cookiesForURL:cookieURL]; + NSString *cookieNameString = (NSString *) cookieName; + + NSUInteger count = [cookies count]; + for (NSUInteger i = 0; i < count; ++i) { + NSHTTPCookie *cookie = (NSHTTPCookie *)[cookies objectAtIndex:i]; + if ([[cookie name] isEqualToString:cookieNameString]) { + [cookieStorage deleteCookie:cookie]; + break; + } + } + + END_BLOCK_OBJC_EXCEPTIONS; +} + } diff --git a/WebCore/platform/mac/DragDataMac.mm b/WebCore/platform/mac/DragDataMac.mm index a7b751c..02a6af7 100644 --- a/WebCore/platform/mac/DragDataMac.mm +++ b/WebCore/platform/mac/DragDataMac.mm @@ -26,6 +26,7 @@ #import "config.h" #import "DragData.h" +#if ENABLE(DRAG_SUPPORT) #import "ClipboardMac.h" #import "ClipboardAccessPolicy.h" #import "Document.h" @@ -127,5 +128,6 @@ PassRefPtr<DocumentFragment> DragData::asFragment(Document*) const return core(m_pasteboardHelper->fragmentFromPasteboard([m_platformDragData draggingPasteboard])); } -} +} // namespace WebCore +#endif // ENABLE(DRAG_SUPPORT) diff --git a/WebCore/platform/mac/DragImageMac.mm b/WebCore/platform/mac/DragImageMac.mm index 842e6d4..7b51018 100644 --- a/WebCore/platform/mac/DragImageMac.mm +++ b/WebCore/platform/mac/DragImageMac.mm @@ -26,6 +26,7 @@ #import "config.h" #import "DragImage.h" +#if ENABLE(DRAG_SUPPORT) #import "CachedImage.h" #import "Image.h" #import "KURL.h" @@ -98,4 +99,6 @@ RetainPtr<NSImage> createDragImageIconForCachedImage(CachedImage* image) return [[NSWorkspace sharedWorkspace] iconForFileType:extension]; } -} +} // namespace WebCore + +#endif // ENABLE(DRAG_SUPPORT) diff --git a/WebCore/platform/mac/GeolocationServiceMac.h b/WebCore/platform/mac/GeolocationServiceMac.h index d0342e7..4beefca 100644 --- a/WebCore/platform/mac/GeolocationServiceMac.h +++ b/WebCore/platform/mac/GeolocationServiceMac.h @@ -45,7 +45,7 @@ namespace WebCore { class GeolocationServiceMac : public GeolocationService { public: - GeolocationServiceMac(GeolocationServiceClient*); + static GeolocationService* create(GeolocationServiceClient*); virtual ~GeolocationServiceMac(); virtual bool startUpdating(PositionOptions*); @@ -61,6 +61,8 @@ public: void errorOccurred(PassRefPtr<PositionError>); private: + GeolocationServiceMac(GeolocationServiceClient*); + RetainPtr<CLLocationManager> m_locationManager; RetainPtr<WebCoreCoreLocationObserver> m_objcObserver; diff --git a/WebCore/platform/mac/GeolocationServiceMac.mm b/WebCore/platform/mac/GeolocationServiceMac.mm index 01eca4a..1093e69 100644 --- a/WebCore/platform/mac/GeolocationServiceMac.mm +++ b/WebCore/platform/mac/GeolocationServiceMac.mm @@ -65,11 +65,13 @@ using namespace WebCore; namespace WebCore { -GeolocationService* GeolocationService::create(GeolocationServiceClient* client) +GeolocationService* GeolocationServiceMac::create(GeolocationServiceClient* client) { return new GeolocationServiceMac(client); } +GeolocationService::FactoryFunction* GeolocationService::s_factoryFunction = &GeolocationServiceMac::create; + GeolocationServiceMac::GeolocationServiceMac(GeolocationServiceClient* client) : GeolocationService(client) , m_objcObserver(AdoptNS, [[WebCoreCoreLocationObserver alloc] initWithCallback:this]) diff --git a/WebCore/platform/mac/LocalizedStringsMac.mm b/WebCore/platform/mac/LocalizedStringsMac.mm index fdd7df5..261347f 100644 --- a/WebCore/platform/mac/LocalizedStringsMac.mm +++ b/WebCore/platform/mac/LocalizedStringsMac.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2003, 2006, 2009 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 @@ -89,6 +89,7 @@ String copyImageUnknownFileLabel() return String(); } +#if ENABLE(CONTEXT_MENUS) String contextMenuItemTagOpenLinkInNewWindow() { BEGIN_BLOCK_OBJC_EXCEPTIONS; @@ -544,6 +545,7 @@ String contextMenuItemTagInspectElement() END_BLOCK_OBJC_EXCEPTIONS; return String(); } +#endif // ENABLE(CONTEXT_MENUS) String searchMenuNoRecentSearchesText() { @@ -625,6 +627,14 @@ String AXDefinitionListDefinitionText() return String(); } +String AXARIAContentGroupText(const String& ariaType) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] AXARIAContentGroupText:ariaType]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + String AXButtonActionVerb() { BEGIN_BLOCK_OBJC_EXCEPTIONS; @@ -713,4 +723,29 @@ String mediaElementLiveBroadcastStateText() return String(); } +String localizedMediaControlElementString(const String& controlName) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] localizedMediaControlElementString:controlName]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String localizedMediaControlElementHelpText(const String& controlName) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] localizedMediaControlElementHelpText:controlName]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + +String localizedMediaTimeDescription(float time) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] localizedMediaTimeDescription:time]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + + } diff --git a/WebCore/platform/mac/PasteboardMac.mm b/WebCore/platform/mac/PasteboardMac.mm index e21f549..f048791 100644 --- a/WebCore/platform/mac/PasteboardMac.mm +++ b/WebCore/platform/mac/PasteboardMac.mm @@ -135,8 +135,8 @@ static NSAttributedString *stripAttachmentCharacters(NSAttributedString *string) void Pasteboard::writeSelection(NSPasteboard* pasteboard, Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame) { - if (WebArchivePboardType == nil) - Pasteboard::generalPasteboard(); //Initialises pasteboard types + if (!WebArchivePboardType) + Pasteboard::generalPasteboard(); // Initialises pasteboard types ASSERT(selectedRange); NSAttributedString *attributedString = [[[NSAttributedString alloc] _initWithDOMRange:kit(selectedRange)] autorelease]; @@ -203,12 +203,24 @@ void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Pasteboard::writeSelection(m_pasteboard.get(), selectedRange, canSmartCopyOrDelete, frame); } +void Pasteboard::writePlainText(const String& text) +{ + if (!WebArchivePboardType) + Pasteboard::generalPasteboard(); // Initialises pasteboard types + + NSArray *types = [NSArray arrayWithObject:NSStringPboardType]; + NSPasteboard *pasteboard = m_pasteboard.get(); + [pasteboard declareTypes:types owner:nil]; + + [pasteboard setString:text forType:NSStringPboardType]; +} + void Pasteboard::writeURL(NSPasteboard* pasteboard, NSArray* types, const KURL& url, const String& titleStr, Frame* frame) { - if (WebArchivePboardType == nil) - Pasteboard::generalPasteboard(); //Initialises pasteboard types + if (!WebArchivePboardType) + Pasteboard::generalPasteboard(); // Initialises pasteboard types - if (types == nil) { + if (!types) { types = writableTypesForURL(); [pasteboard declareTypes:types owner:nil]; } diff --git a/WebCore/platform/mac/PopupMenuMac.mm b/WebCore/platform/mac/PopupMenuMac.mm index b98235d..dfb0fff 100644 --- a/WebCore/platform/mac/PopupMenuMac.mm +++ b/WebCore/platform/mac/PopupMenuMac.mm @@ -105,7 +105,7 @@ void PopupMenu::show(const IntRect& r, FrameView* v, int index) int numItems = [m_popup.get() numberOfItems]; if (numItems <= 0) { if (client()) - client()->hidePopup(); + client()->popupDidHide(); return; } ASSERT(numItems > index); @@ -162,7 +162,7 @@ void PopupMenu::show(const IntRect& r, FrameView* v, int index) if (client()) { int newIndex = [m_popup.get() indexOfSelectedItem]; - client()->hidePopup(); + client()->popupDidHide(); // Adjust newIndex for hidden first item. if (!client()->shouldPopOver()) diff --git a/WebCore/platform/mac/ScrollViewMac.mm b/WebCore/platform/mac/ScrollViewMac.mm index 5ff0ff5..202d49e 100644 --- a/WebCore/platform/mac/ScrollViewMac.mm +++ b/WebCore/platform/mac/ScrollViewMac.mm @@ -163,26 +163,12 @@ bool ScrollView::platformScroll(ScrollDirection, ScrollGranularity) void ScrollView::platformRepaintContentRectangle(const IntRect& rect, bool now) { BEGIN_BLOCK_OBJC_EXCEPTIONS; - NSView *view = documentView(); - NSRect visibleRect = visibleContentRect(); - - // FIXME: I don't think this intersection is necessary any more now that - // selection doesn't call this method directly (but has to go through FrameView's - // repaintContentRectangle, which does the intersection test also). Leaving it in - // for now until I'm sure. - // Checking for rect visibility is an important optimization for the case of - // Select All of a large document. AppKit does not do this check, and so ends - // up building a large complicated NSRegion if we don't perform the check. - NSRect dirtyRect = NSIntersectionRect(rect, visibleRect); - if (!NSIsEmptyRect(dirtyRect)) { - [view setNeedsDisplayInRect:dirtyRect]; - if (now) { - [[view window] displayIfNeeded]; - [[view window] flushWindowIfNeeded]; - } + [view setNeedsDisplayInRect:rect]; + if (now) { + [[view window] displayIfNeeded]; + [[view window] flushWindowIfNeeded]; } - END_BLOCK_OBJC_EXCEPTIONS; } diff --git a/WebCore/platform/mac/ThemeMac.mm b/WebCore/platform/mac/ThemeMac.mm index e7e12ac..fd2f944 100644 --- a/WebCore/platform/mac/ThemeMac.mm +++ b/WebCore/platform/mac/ThemeMac.mm @@ -311,6 +311,14 @@ static const IntSize* buttonSizes() return sizes; } +#if ENABLE(DATALIST) +static const IntSize* listButtonSizes() +{ + static const IntSize sizes[3] = { IntSize(21, 21), IntSize(19, 18), IntSize(17, 16) }; + return sizes; +} +#endif + static const int* buttonMargins(NSControlSize controlSize) { static const int margins[3][4] = @@ -333,6 +341,13 @@ static NSButtonCell* button(ControlPart part, ControlStates states, const IntRec } // Set the control size based off the rectangle we're painting into. + const IntSize* sizes = buttonSizes(); +#if ENABLE(DATALIST) + if (part == ListButtonPart) { + [buttonCell setBezelStyle:NSRoundedDisclosureBezelStyle]; + sizes = listButtonSizes(); + } else +#endif if (part == SquareButtonPart || zoomedRect.height() > buttonSizes()[NSRegularControlSize].height() * zoomFactor) { // Use the square button if ([buttonCell bezelStyle] != NSShadowlessSquareBezelStyle) @@ -362,7 +377,11 @@ static void paintButton(ControlPart part, ControlStates states, GraphicsContext* LocalCurrentGraphicsContext localContext(context); NSControlSize controlSize = [buttonCell controlSize]; +#if ENABLE(DATALIST) + IntSize zoomedSize = (part == ListButtonPart ? listButtonSizes() : buttonSizes())[controlSize]; +#else IntSize zoomedSize = buttonSizes()[controlSize]; +#endif zoomedSize.setWidth(zoomedRect.width()); // Buttons don't ever constrain width, so the zoomed width can just be honored. zoomedSize.setHeight(zoomedSize.height() * zoomFactor); IntRect inflatedRect = zoomedRect; @@ -442,6 +461,10 @@ LengthSize ThemeMac::controlSize(ControlPart part, const Font& font, const Lengt case PushButtonPart: // Height is reset to auto so that specified heights can be ignored. return sizeFromFont(font, LengthSize(zoomedSize.width(), Length()), zoomFactor, buttonSizes()); +#if ENABLE(DATALIST) + case ListButtonPart: + return sizeFromFont(font, LengthSize(zoomedSize.width(), Length()), zoomFactor, listButtonSizes()); +#endif default: return zoomedSize; } @@ -453,6 +476,7 @@ LengthSize ThemeMac::minimumControlSize(ControlPart part, const Font& font, floa case SquareButtonPart: case DefaultButtonPart: case ButtonPart: + case ListButtonPart: return LengthSize(Length(0, Fixed), Length(static_cast<int>(15 * zoomFactor), Fixed)); default: return Theme::minimumControlSize(part, font, zoomFactor); @@ -465,6 +489,7 @@ LengthBox ThemeMac::controlBorder(ControlPart part, const Font& font, const Leng case SquareButtonPart: case DefaultButtonPart: case ButtonPart: + case ListButtonPart: return LengthBox(0, zoomedBox.right().value(), 0, zoomedBox.left().value()); default: return Theme::controlBorder(part, font, zoomedBox, zoomFactor); @@ -548,6 +573,7 @@ void ThemeMac::paint(ControlPart part, ControlStates states, GraphicsContext* co case DefaultButtonPart: case ButtonPart: case SquareButtonPart: + case ListButtonPart: paintButton(part, states, context, zoomedRect, zoomFactor, scrollView); break; default: diff --git a/WebCore/platform/mac/WebCoreNSStringExtras.mm b/WebCore/platform/mac/WebCoreNSStringExtras.mm index b7087f1..d6c3f0c 100644 --- a/WebCore/platform/mac/WebCoreNSStringExtras.mm +++ b/WebCore/platform/mac/WebCoreNSStringExtras.mm @@ -29,6 +29,8 @@ #import "config.h" #import "WebCoreNSStringExtras.h" +#import <wtf/RetainPtr.h> + BOOL stringIsCaseInsensitiveEqualToString(NSString *first, NSString *second) { return [first compare:second options:(NSCaseInsensitiveSearch|NSLiteralSearch)] == NSOrderedSame; @@ -69,50 +71,41 @@ NSString *filenameByFixingIllegalCharacters(NSString *string) CFStringEncoding stringEncodingForResource(Handle resource) { short resRef = HomeResFile(resource); - if (ResError() != noErr) { + if (ResError() != noErr) return NSMacOSRomanStringEncoding; - } // Get the FSRef for the current resource file FSRef fref; OSStatus error = FSGetForkCBInfo(resRef, 0, NULL, NULL, NULL, &fref, NULL); - if (error != noErr) { + if (error != noErr) return NSMacOSRomanStringEncoding; - } - CFURLRef URL = CFURLCreateFromFSRef(NULL, &fref); - if (URL == NULL) { + RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateFromFSRef(NULL, &fref)); + if (!url) return NSMacOSRomanStringEncoding; - } - - NSString *path = [(NSURL *)URL path]; - CFRelease(URL); - + + NSString *path = [(NSURL *)url.get() path]; + // Get the lproj directory name path = [path stringByDeletingLastPathComponent]; - if (!stringIsCaseInsensitiveEqualToString([path pathExtension], @"lproj")) { + if (!stringIsCaseInsensitiveEqualToString([path pathExtension], @"lproj")) return NSMacOSRomanStringEncoding; - } NSString *directoryName = [[path stringByDeletingPathExtension] lastPathComponent]; - CFStringRef locale = CFLocaleCreateCanonicalLocaleIdentifierFromString(NULL, (CFStringRef)directoryName); - if (locale == NULL) { + RetainPtr<CFStringRef> locale(AdoptCF, CFLocaleCreateCanonicalLocaleIdentifierFromString(NULL, (CFStringRef)directoryName)); + if (!locale) return NSMacOSRomanStringEncoding; - } - + LangCode lang; RegionCode region; - error = LocaleStringToLangAndRegionCodes([(NSString *)locale UTF8String], &lang, ®ion); - CFRelease(locale); - if (error != noErr) { + error = LocaleStringToLangAndRegionCodes([(NSString *)locale.get() UTF8String], &lang, ®ion); + if (error != noErr) return NSMacOSRomanStringEncoding; - } - + TextEncoding encoding; error = UpgradeScriptInfoToTextEncoding(kTextScriptDontCare, lang, region, NULL, &encoding); - if (error != noErr) { + if (error != noErr) return NSMacOSRomanStringEncoding; - } return encoding; } diff --git a/WebCore/platform/network/Credential.cpp b/WebCore/platform/network/Credential.cpp index 4743959..caca785 100644 --- a/WebCore/platform/network/Credential.cpp +++ b/WebCore/platform/network/Credential.cpp @@ -43,6 +43,11 @@ Credential::Credential(const String& user, const String& password, CredentialPer , m_persistence(persistence) { } + +bool Credential::isEmpty() +{ + return m_user.isEmpty() && m_password.isEmpty(); +} const String& Credential::user() const { diff --git a/WebCore/platform/network/Credential.h b/WebCore/platform/network/Credential.h index 4d80490..ca4a45a 100644 --- a/WebCore/platform/network/Credential.h +++ b/WebCore/platform/network/Credential.h @@ -41,6 +41,8 @@ public: Credential(); Credential(const String& user, const String& password, CredentialPersistence); + bool isEmpty(); + const String& user() const; const String& password() const; bool hasPassword() const; diff --git a/WebCore/platform/network/CredentialStorage.cpp b/WebCore/platform/network/CredentialStorage.cpp new file mode 100644 index 0000000..407ed5b --- /dev/null +++ b/WebCore/platform/network/CredentialStorage.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CredentialStorage.h" + +#include "CString.h" +#include "Credential.h" +#include "KURL.h" +#include "ProtectionSpaceHash.h" +#include "StringHash.h" + +#include <wtf/StdLibExtras.h> + +namespace WebCore { + +typedef HashMap<ProtectionSpace, Credential> ProtectionSpaceToCredentialMap; +static ProtectionSpaceToCredentialMap& protectionSpaceToCredentialMap() +{ + DEFINE_STATIC_LOCAL(ProtectionSpaceToCredentialMap, map, ()); + return map; +} + +typedef HashMap<String, HashMap<String, Credential> > OriginToDefaultBasicCredentialMap; +static OriginToDefaultBasicCredentialMap& originToDefaultBasicCredentialMap() +{ + DEFINE_STATIC_LOCAL(OriginToDefaultBasicCredentialMap, map, ()); + return map; +} + +static String originStringFromURL(const KURL& url) +{ + if (url.port()) + return url.protocol() + "://" + url.host() + String::format(":%i/", url.port()); + + return url.protocol() + "://" + url.host() + "/"; +} + +void CredentialStorage::set(const Credential& credential, const ProtectionSpace& protectionSpace, const KURL& url) +{ + ASSERT(url.protocolInHTTPFamily()); + ASSERT(url.isValid()); + + protectionSpaceToCredentialMap().set(protectionSpace, credential); + + ProtectionSpaceAuthenticationScheme scheme = protectionSpace.authenticationScheme(); + if (url.protocolInHTTPFamily() && (scheme == ProtectionSpaceAuthenticationSchemeHTTPBasic || scheme == ProtectionSpaceAuthenticationSchemeDefault)) { + String origin = originStringFromURL(url); + + HashMap<String, Credential> pathToCredentialMap; + pair<HashMap<String, HashMap<String, Credential> >::iterator, bool> result = originToDefaultBasicCredentialMap().add(origin, pathToCredentialMap); + + // Remove the last path component that is not a directory to determine the subpath for which this credential applies. + // We keep a leading slash, but remove a trailing one. + String path = url.path(); + ASSERT(path.length() > 0); + ASSERT(path[0] == '/'); + if (path.length() > 1) { + int index = path.reverseFind('/'); + path = path.substring(0, index ? index : 1); + } + ASSERT(path.length() == 1 || path[path.length() - 1] != '/'); + + result.first->second.set(path, credential); + } +} + +Credential CredentialStorage::get(const ProtectionSpace& protectionSpace) +{ + return protectionSpaceToCredentialMap().get(protectionSpace); +} + +Credential CredentialStorage::getDefaultAuthenticationCredential(const KURL& url) +{ + ASSERT(url.protocolInHTTPFamily()); + String origin = originStringFromURL(url); + const HashMap<String, Credential>& pathToCredentialMap(originToDefaultBasicCredentialMap().get(origin)); + if (pathToCredentialMap.isEmpty()) + return Credential(); + + // Check to see if there is a stored credential for the subpath ancestry of this url. + String path = url.path(); + Credential credential = pathToCredentialMap.get(path); + while (credential.isEmpty() && !path.isNull()) { + int index = path.reverseFind('/'); + if (index == 0) { + credential = pathToCredentialMap.get("/"); + break; + } else if (index == -1) { + // This case should never happen, as all HTTP URL paths should start with a leading / + ASSERT_NOT_REACHED(); + credential = pathToCredentialMap.get(path); + break; + } else { + path = path.substring(0, index); + credential = pathToCredentialMap.get(path); + } + } + return credential; +} + +} // namespace WebCore diff --git a/WebCore/platform/network/CredentialStorage.h b/WebCore/platform/network/CredentialStorage.h new file mode 100644 index 0000000..737efa6 --- /dev/null +++ b/WebCore/platform/network/CredentialStorage.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SessionCredentialStorage_h +#define SessionCredentialStorage_h + +namespace WebCore { + +class Credential; +class KURL; +class ProtectionSpace; + +class CredentialStorage { +public: + static void set(const Credential&, const ProtectionSpace&, const KURL&); + static Credential get(const ProtectionSpace&); + static Credential getDefaultAuthenticationCredential(const KURL&); +}; + +} // namespace WebCore + +#endif // SessionCredentialStorage_h diff --git a/WebCore/platform/network/HTTPHeaderMap.cpp b/WebCore/platform/network/HTTPHeaderMap.cpp index ff470a0..07c66e8 100644 --- a/WebCore/platform/network/HTTPHeaderMap.cpp +++ b/WebCore/platform/network/HTTPHeaderMap.cpp @@ -45,7 +45,7 @@ auto_ptr<CrossThreadHTTPHeaderMapData> HTTPHeaderMap::copyData() const HTTPHeaderMap::const_iterator end_it = end(); for (HTTPHeaderMap::const_iterator it = begin(); it != end_it; ++it) { - data->append(make_pair(it->first.string().copy(), it->second.copy())); + data->append(make_pair(it->first.string().crossThreadString(), it->second.crossThreadString())); } return data; } diff --git a/WebCore/platform/network/ProtectionSpace.cpp b/WebCore/platform/network/ProtectionSpace.cpp index bd73558..d04bcbe 100644 --- a/WebCore/platform/network/ProtectionSpace.cpp +++ b/WebCore/platform/network/ProtectionSpace.cpp @@ -37,7 +37,11 @@ namespace WebCore { // combined with the semantics of the String(NSString*) constructor ProtectionSpace::ProtectionSpace() : m_host("") + , m_port(0) + , m_serverType(ProtectionSpaceServerHTTP) , m_realm("") + , m_authenticationScheme(ProtectionSpaceAuthenticationSchemeDefault) + , m_isHashTableDeletedValue(false) { } @@ -49,6 +53,7 @@ ProtectionSpace::ProtectionSpace(const String& host, int port, ProtectionSpaceSe , m_serverType(serverType) , m_realm(realm.length() ? realm : "") , m_authenticationScheme(authenticationScheme) + , m_isHashTableDeletedValue(false) { } diff --git a/WebCore/platform/network/ProtectionSpace.h b/WebCore/platform/network/ProtectionSpace.h index 9a73cff..126b499 100644 --- a/WebCore/platform/network/ProtectionSpace.h +++ b/WebCore/platform/network/ProtectionSpace.h @@ -54,6 +54,10 @@ class ProtectionSpace { public: ProtectionSpace(); ProtectionSpace(const String& host, int port, ProtectionSpaceServerType, const String& realm, ProtectionSpaceAuthenticationScheme); + + // Hash table deleted values, which are only constructed and never copied or destroyed. + ProtectionSpace(WTF::HashTableDeletedValueType) : m_isHashTableDeletedValue(true) { } + bool isHashTableDeletedValue() const { return m_isHashTableDeletedValue; } const String& host() const; int port() const; @@ -70,10 +74,12 @@ private: ProtectionSpaceServerType m_serverType; String m_realm; ProtectionSpaceAuthenticationScheme m_authenticationScheme; + bool m_isHashTableDeletedValue; }; bool operator==(const ProtectionSpace& a, const ProtectionSpace& b); inline bool operator!=(const ProtectionSpace& a, const ProtectionSpace& b) { return !(a == b); } -} -#endif +} // namespace WebCore + +#endif // ProtectionSpace_h diff --git a/WebCore/platform/network/ProtectionSpaceHash.h b/WebCore/platform/network/ProtectionSpaceHash.h new file mode 100644 index 0000000..6f68b5b --- /dev/null +++ b/WebCore/platform/network/ProtectionSpaceHash.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ProtectionSpaceHash_h +#define ProtectionSpaceHash_h + +#include "ProtectionSpace.h" + +namespace WebCore { + +struct ProtectionSpaceHash { + static unsigned hash(const ProtectionSpace& protectionSpace) + { + unsigned hashCodes[5] = { + protectionSpace.host().impl() ? protectionSpace.host().impl()->hash() : 0, + protectionSpace.port(), + protectionSpace.serverType(), + protectionSpace.realm().impl() ? protectionSpace.realm().impl()->hash() : 0, + protectionSpace.authenticationScheme() + }; + + return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar)); + } + + static bool equal(const ProtectionSpace& a, const ProtectionSpace& b) { return a == b; } + static const bool safeToCompareToEmptyOrDeleted = false; +}; + +} // namespace WebCore + +namespace WTF { + + // WebCore::ProtectionSpaceHash is the default hash for ProtectionSpace + template<> struct HashTraits<WebCore::ProtectionSpace> : GenericHashTraits<WebCore::ProtectionSpace> { + static const bool emptyValueIsZero = true; + static void constructDeletedValue(WebCore::ProtectionSpace& slot) { new (&slot) WebCore::ProtectionSpace(HashTableDeletedValue); } + static bool isDeletedValue(const WebCore::ProtectionSpace& slot) { return slot.isHashTableDeletedValue(); } + }; + + template<typename T> struct DefaultHash; + template<> struct DefaultHash<WebCore::ProtectionSpace> { + typedef WebCore::ProtectionSpaceHash Hash; + }; + +} // namespace WTF + + +#endif // ProtectionSpaceHash_h diff --git a/WebCore/platform/network/ResourceErrorBase.cpp b/WebCore/platform/network/ResourceErrorBase.cpp index 370650f..97435ba 100644 --- a/WebCore/platform/network/ResourceErrorBase.cpp +++ b/WebCore/platform/network/ResourceErrorBase.cpp @@ -34,10 +34,10 @@ ResourceError ResourceErrorBase::copy() const lazyInit(); ResourceError errorCopy; - errorCopy.m_domain = m_domain.copy(); + errorCopy.m_domain = m_domain.crossThreadString(); errorCopy.m_errorCode = m_errorCode; - errorCopy.m_failingURL = m_failingURL.copy(); - errorCopy.m_localizedDescription = m_localizedDescription.copy(); + errorCopy.m_failingURL = m_failingURL.crossThreadString(); + errorCopy.m_localizedDescription = m_localizedDescription.crossThreadString(); errorCopy.m_isNull = m_isNull; errorCopy.m_isCancellation = m_isCancellation; return errorCopy; diff --git a/WebCore/platform/network/ResourceHandleInternal.h b/WebCore/platform/network/ResourceHandleInternal.h index 7951109..31d740a 100644 --- a/WebCore/platform/network/ResourceHandleInternal.h +++ b/WebCore/platform/network/ResourceHandleInternal.h @@ -159,6 +159,8 @@ namespace WebCore { String m_user; String m_pass; + Credential m_initialCredential; + int status; bool m_defersLoading; diff --git a/WebCore/platform/network/ResourceRequestBase.cpp b/WebCore/platform/network/ResourceRequestBase.cpp index f9ecb6b..a568cc7 100644 --- a/WebCore/platform/network/ResourceRequestBase.cpp +++ b/WebCore/platform/network/ResourceRequestBase.cpp @@ -62,7 +62,7 @@ auto_ptr<ResourceRequest> ResourceRequestBase::adopt(auto_ptr<CrossThreadResourc request->setResponseContentDispositionEncodingFallbackArray(encoding1, encoding2, encoding3); } request->setHTTPBody(data->m_httpBody); - request->setAllowHTTPCookies(data->m_allowHTTPCookies); + request->setAllowCookies(data->m_allowCookies); return request; } @@ -73,17 +73,17 @@ auto_ptr<CrossThreadResourceRequestData> ResourceRequestBase::copyData() const data->m_cachePolicy = cachePolicy(); data->m_timeoutInterval = timeoutInterval(); data->m_firstPartyForCookies = firstPartyForCookies().copy(); - data->m_httpMethod = httpMethod().copy(); + data->m_httpMethod = httpMethod().crossThreadString(); data->m_httpHeaders.adopt(httpHeaderFields().copyData()); data->m_responseContentDispositionEncodingFallbackArray.reserveInitialCapacity(m_responseContentDispositionEncodingFallbackArray.size()); size_t encodingArraySize = m_responseContentDispositionEncodingFallbackArray.size(); for (size_t index = 0; index < encodingArraySize; ++index) { - data->m_responseContentDispositionEncodingFallbackArray.append(m_responseContentDispositionEncodingFallbackArray[index].copy()); + data->m_responseContentDispositionEncodingFallbackArray.append(m_responseContentDispositionEncodingFallbackArray[index].crossThreadString()); } if (m_httpBody) data->m_httpBody = m_httpBody->deepCopy(); - data->m_allowHTTPCookies = m_allowHTTPCookies; + data->m_allowCookies = m_allowCookies; return data; } @@ -251,18 +251,18 @@ void ResourceRequestBase::setHTTPBody(PassRefPtr<FormData> httpBody) m_platformRequestUpdated = false; } -bool ResourceRequestBase::allowHTTPCookies() const +bool ResourceRequestBase::allowCookies() const { updateResourceRequest(); - return m_allowHTTPCookies; + return m_allowCookies; } -void ResourceRequestBase::setAllowHTTPCookies(bool allowHTTPCookies) +void ResourceRequestBase::setAllowCookies(bool allowCookies) { updateResourceRequest(); - m_allowHTTPCookies = allowHTTPCookies; + m_allowCookies = allowCookies; if (url().protocolInHTTPFamily()) m_platformRequestUpdated = false; @@ -274,6 +274,9 @@ void ResourceRequestBase::addHTTPHeaderField(const AtomicString& name, const Str pair<HTTPHeaderMap::iterator, bool> result = m_httpHeaderFields.add(name, value); if (!result.second) result.first->second += "," + value; + + if (url().protocolInHTTPFamily()) + m_platformRequestUpdated = false; } void ResourceRequestBase::addHTTPHeaderFields(const HTTPHeaderMap& headerFields) @@ -300,7 +303,7 @@ bool equalIgnoringHeaderFields(const ResourceRequestBase& a, const ResourceReque if (a.httpMethod() != b.httpMethod()) return false; - if (a.allowHTTPCookies() != b.allowHTTPCookies()) + if (a.allowCookies() != b.allowCookies()) return false; FormData* formDataA = a.httpBody(); @@ -355,7 +358,11 @@ void ResourceRequestBase::updateResourceRequest() const m_resourceRequestUpdated = true; } +<<<<<<< HEAD:WebCore/platform/network/ResourceRequestBase.cpp #if !PLATFORM(MAC) && !USE(CFNETWORK) && !PLATFORM(ANDROID) +======= +#if !PLATFORM(MAC) && !USE(CFNETWORK) && !USE(SOUP) +>>>>>>> webkit.org at 49305:WebCore/platform/network/ResourceRequestBase.cpp unsigned initializeMaximumHTTPConnectionCountPerHost() { // This is used by the loader to control the number of issued parallel load requests. diff --git a/WebCore/platform/network/ResourceRequestBase.h b/WebCore/platform/network/ResourceRequestBase.h index 2d87d6e..348e6b3 100644 --- a/WebCore/platform/network/ResourceRequestBase.h +++ b/WebCore/platform/network/ResourceRequestBase.h @@ -105,8 +105,8 @@ namespace WebCore { FormData* httpBody() const; void setHTTPBody(PassRefPtr<FormData> httpBody); - bool allowHTTPCookies() const; - void setAllowHTTPCookies(bool allowHTTPCookies); + bool allowCookies() const; + void setAllowCookies(bool allowCookies); bool isConditional() const; @@ -129,7 +129,7 @@ namespace WebCore { , m_cachePolicy(policy) , m_timeoutInterval(unspecifiedTimeoutInterval) , m_httpMethod("GET") - , m_allowHTTPCookies(true) + , m_allowCookies(true) , m_resourceRequestUpdated(true) , m_platformRequestUpdated(false) , m_reportUploadProgress(false) @@ -148,7 +148,7 @@ namespace WebCore { HTTPHeaderMap m_httpHeaderFields; Vector<String> m_responseContentDispositionEncodingFallbackArray; RefPtr<FormData> m_httpBody; - bool m_allowHTTPCookies; + bool m_allowCookies; mutable bool m_resourceRequestUpdated; mutable bool m_platformRequestUpdated; bool m_reportUploadProgress; @@ -173,7 +173,7 @@ namespace WebCore { OwnPtr<CrossThreadHTTPHeaderMapData> m_httpHeaders; Vector<String> m_responseContentDispositionEncodingFallbackArray; RefPtr<FormData> m_httpBody; - bool m_allowHTTPCookies; + bool m_allowCookies; }; unsigned initializeMaximumHTTPConnectionCountPerHost(); diff --git a/WebCore/platform/network/ResourceResponseBase.cpp b/WebCore/platform/network/ResourceResponseBase.cpp index 7f8a4e2..fd44225 100644 --- a/WebCore/platform/network/ResourceResponseBase.cpp +++ b/WebCore/platform/network/ResourceResponseBase.cpp @@ -108,12 +108,12 @@ auto_ptr<CrossThreadResourceResponseData> ResourceResponseBase::copyData() const { auto_ptr<CrossThreadResourceResponseData> data(new CrossThreadResourceResponseData()); data->m_url = url().copy(); - data->m_mimeType = mimeType().copy(); + data->m_mimeType = mimeType().crossThreadString(); data->m_expectedContentLength = expectedContentLength(); - data->m_textEncodingName = textEncodingName().copy(); - data->m_suggestedFilename = suggestedFilename().copy(); + data->m_textEncodingName = textEncodingName().crossThreadString(); + data->m_suggestedFilename = suggestedFilename().crossThreadString(); data->m_httpStatusCode = httpStatusCode(); - data->m_httpStatusText = httpStatusText().copy(); + data->m_httpStatusText = httpStatusText().crossThreadString(); data->m_httpHeaders.adopt(httpHeaderFields().copyData()); data->m_lastModifiedDate = lastModifiedDate(); return data; diff --git a/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumMac.cpp b/WebCore/platform/network/SocketStreamErrorBase.cpp index 35a40f5..72fb44c 100644 --- a/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumMac.cpp +++ b/WebCore/platform/network/SocketStreamErrorBase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2009 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -29,14 +29,20 @@ */ #include "config.h" -#include "SQLiteFileSystem.h" +#include "SocketStreamError.h" namespace WebCore { -void SQLiteFileSystem::registerSQLiteVFS() +SocketStreamError SocketStreamErrorBase::copy() const { - // stub for registering Chromium's SQLite VFS for Mac - ASSERT_NOT_REACHED(); + SocketStreamError errorCopy; + errorCopy.m_errorCode = m_errorCode; + return errorCopy; } -} // namespace WebCore +bool SocketStreamErrorBase::compare(const SocketStreamError& a, const SocketStreamError& b) +{ + return a.errorCode() == b.errorCode(); +} + +} // namespace WebCore diff --git a/WebCore/platform/network/SocketStreamErrorBase.h b/WebCore/platform/network/SocketStreamErrorBase.h new file mode 100644 index 0000000..b7ca35b --- /dev/null +++ b/WebCore/platform/network/SocketStreamErrorBase.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER 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 SocketStreamErrorBase_h +#define SocketStreamErrorBase_h + +namespace WebCore { + + class SocketStreamError; + + class SocketStreamErrorBase { + public: + // Makes a deep copy. Useful for when you need to use a SocketStreamError on another thread. + SocketStreamError copy() const; + + bool isNull() const { return m_isNull; } + + int errorCode() const { return m_errorCode; } + + static bool compare(const SocketStreamError&, const SocketStreamError&); + + protected: + SocketStreamErrorBase() + : m_errorCode(0) + , m_isNull(true) + { + } + + explicit SocketStreamErrorBase(int errorCode) + : m_errorCode(errorCode) + , m_isNull(false) + { + } + + int m_errorCode; + bool m_isNull; + }; + + inline bool operator==(const SocketStreamError& a, const SocketStreamError& b) { return SocketStreamErrorBase::compare(a, b); } + inline bool operator!=(const SocketStreamError& a, const SocketStreamError& b) { return !(a == b); } + +} // namespace WebCore + +#endif // SocketStreamErrorBase_h diff --git a/WebCore/platform/network/SocketStreamHandleBase.cpp b/WebCore/platform/network/SocketStreamHandleBase.cpp new file mode 100644 index 0000000..875c248 --- /dev/null +++ b/WebCore/platform/network/SocketStreamHandleBase.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER 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 "SocketStreamHandleBase.h" + +#include "SocketStreamHandleClient.h" + +namespace WebCore { + +const unsigned int bufferSize = 100 * 1024 * 1024; + +SocketStreamHandleBase::SocketStreamHandleBase(const KURL& url, SocketStreamHandleClient* client) + : m_url(url) + , m_client(client) + , m_state(Connecting) +{ +} + +SocketStreamHandleBase::SocketStreamState SocketStreamHandleBase::state() const +{ + return m_state; +} + +bool SocketStreamHandleBase::send(const char* data, int length) +{ + if (m_state == Connecting) + return false; + if (!m_buffer.isEmpty()) { + if (m_buffer.size() + length > bufferSize) { + // FIXME: report error to indicate that buffer has no more space. + return false; + } + m_buffer.append(data, length); + return true; + } + int bytesWritten = 0; + if (m_state == Open) + bytesWritten = platformSend(data, length); + if (bytesWritten <= 0) + return false; + if (m_buffer.size() + length - bytesWritten > bufferSize) { + // FIXME: report error to indicate that buffer has no more space. + return false; + } + if (bytesWritten < length) + m_buffer.append(data + bytesWritten, length - bytesWritten); + return true; +} + +void SocketStreamHandleBase::close() +{ + platformClose(); + m_state = Closed; +} + +void SocketStreamHandleBase::setClient(SocketStreamHandleClient* client) +{ + ASSERT(!client || (!m_client && m_state == Connecting)); + m_client = client; +} + +bool SocketStreamHandleBase::sendPendingData() +{ + if (m_state != Open) + return false; + if (m_buffer.isEmpty()) + return false; + int bytesWritten = platformSend(m_buffer.data(), m_buffer.size()); + if (bytesWritten <= 0) + return false; + Vector<char> remainingData; + ASSERT(m_buffer.size() - bytesWritten <= bufferSize); + remainingData.append(m_buffer.data() + bytesWritten, m_buffer.size() - bytesWritten); + m_buffer.swap(remainingData); + return true; +} + +} // namespace WebCore diff --git a/WebCore/platform/network/SocketStreamHandleBase.h b/WebCore/platform/network/SocketStreamHandleBase.h new file mode 100644 index 0000000..fc011dd --- /dev/null +++ b/WebCore/platform/network/SocketStreamHandleBase.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER 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 SocketStreamHandleBase_h +#define SocketStreamHandleBase_h + +#include "KURL.h" + +#include <wtf/Vector.h> + +namespace WebCore { + + class SocketStreamHandle; + class SocketStreamHandleClient; + + class SocketStreamHandleBase { + public: + enum SocketStreamState { Connecting, Open, Closed }; + virtual ~SocketStreamHandleBase() { } + SocketStreamState state() const; + + bool send(const char* data, int length); + void close(); + int bufferedAmount() const { return m_buffer.size(); } + + SocketStreamHandleClient* client() const { return m_client; } + void setClient(SocketStreamHandleClient*); + + protected: + SocketStreamHandleBase(const KURL&, SocketStreamHandleClient*); + + bool sendPendingData(); + virtual int platformSend(const char* data, int length) = 0; + virtual void platformClose() = 0; + + KURL m_url; + SocketStreamHandleClient* m_client; + Vector<char> m_buffer; + SocketStreamState m_state; + }; + +} // namespace WebCore + +#endif // SocketStreamHandleBase_h diff --git a/WebCore/platform/network/SocketStreamHandleClient.h b/WebCore/platform/network/SocketStreamHandleClient.h new file mode 100644 index 0000000..04c744e --- /dev/null +++ b/WebCore/platform/network/SocketStreamHandleClient.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER 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 SocketStreamHandleClient_h +#define SocketStreamHandleClient_h + +namespace WebCore { + + class AuthenticationChallenge; + class KURL; + class SocketStreamError; + class SocketStreamHandle; + + class SocketStreamHandleClient { + public: + virtual ~SocketStreamHandleClient() { } + + virtual void willOpenStream(SocketStreamHandle*, const KURL&) { } + virtual void willSendData(SocketStreamHandle*, const char* /*data*/, int /*length*/) { } + + virtual void didOpen(SocketStreamHandle*) { } + virtual void didClose(SocketStreamHandle*) { } + virtual void didReceiveData(SocketStreamHandle*, const char* /*data*/, int /*length*/) { } + + virtual void didFail(SocketStreamHandle*, const SocketStreamError&) { } + + virtual void didReceiveAuthenticationChallenge(SocketStreamHandle*, const AuthenticationChallenge&) { } + virtual void didCancelAuthenticationChallenge(SocketStreamHandle*, const AuthenticationChallenge&) { } + virtual void receivedCancellation(SocketStreamHandle*, const AuthenticationChallenge&) { } + }; + +} // namespace WebCore + +#endif // SocketStreamHandleClient_h diff --git a/WebCore/platform/network/cf/AuthenticationCF.cpp b/WebCore/platform/network/cf/AuthenticationCF.cpp index 51d60a4..bb05a39 100644 --- a/WebCore/platform/network/cf/AuthenticationCF.cpp +++ b/WebCore/platform/network/cf/AuthenticationCF.cpp @@ -37,8 +37,6 @@ namespace WebCore { -CFMutableDictionaryRef WebCoreCredentialStorage::m_storage; - AuthenticationChallenge::AuthenticationChallenge(const ProtectionSpace& protectionSpace, const Credential& proposedCredential, unsigned previousFailureCount, diff --git a/WebCore/platform/network/cf/AuthenticationCF.h b/WebCore/platform/network/cf/AuthenticationCF.h index d3fc014..55f3e5f 100644 --- a/WebCore/platform/network/cf/AuthenticationCF.h +++ b/WebCore/platform/network/cf/AuthenticationCF.h @@ -43,26 +43,6 @@ CFURLProtectionSpaceRef createCF(const ProtectionSpace&); Credential core(CFURLCredentialRef); ProtectionSpace core(CFURLProtectionSpaceRef); -class WebCoreCredentialStorage { -public: - static void set(CFURLProtectionSpaceRef protectionSpace, CFURLCredentialRef credential) - { - if (!m_storage) - m_storage = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFDictionarySetValue(m_storage, protectionSpace, credential); - } - - static CFURLCredentialRef get(CFURLProtectionSpaceRef protectionSpace) - { - if (!m_storage) - return 0; - return (CFURLCredentialRef)CFDictionaryGetValue(m_storage, protectionSpace); - } - -private: - static CFMutableDictionaryRef m_storage; -}; - } #endif diff --git a/WebCore/platform/network/cf/DNSCFNet.cpp b/WebCore/platform/network/cf/DNSCFNet.cpp index bf21ab1..381dff2 100644 --- a/WebCore/platform/network/cf/DNSCFNet.cpp +++ b/WebCore/platform/network/cf/DNSCFNet.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 Collin Jackson <collinj@webkit.org> + * Copyright (C) 2009 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,13 +27,128 @@ #include "config.h" #include "DNS.h" -#include "NotImplemented.h" +#include "StringHash.h" +#include "Timer.h" +#include <wtf/RetainPtr.h> +#include <wtf/StdLibExtras.h> + +#if PLATFORM(WIN) +#include "ResourceHandle.h" // for loaderRunLoop() +#endif + +#ifdef BUILDING_ON_TIGER +// This function is available on Tiger, but not declared in the CFRunLoop.h header on Tiger. +extern "C" CFRunLoopRef CFRunLoopGetMain(); +#endif namespace WebCore { -void prefetchDNS(const String&) +// When resolve queue is empty, we fire async resolution requests immediately (which is important if the prefetch is triggered by hovering). +// But during page parsing, we should coalesce identical requests to avoid stressing out CFHost. +const int namesToResolveImmediately = 4; + +// Coalesce prefetch requests for this long before sending them out. +const double coalesceDelay = 1.0; + +// For a page has links to many outside sites, it is likely that the system DNS resolver won't be able to cache them all anyway, and we don't want +// to negatively affect other appications' performance, by pushing their cached entries out, too. +// If we end up with lots of names to prefetch, some will be dropped. +const int maxRequestsToSend = 64; + +class DNSResolveQueue : public TimerBase { +public: + static DNSResolveQueue& shared(); + void add(const String&); + void decrementRequestCount(); + +private: + DNSResolveQueue(); + + void resolve(const String&); + virtual void fired(); + HashSet<String> m_names; + int m_requestsInFlight; +}; + +DNSResolveQueue::DNSResolveQueue() + : m_requestsInFlight(0) +{ +} + +DNSResolveQueue& DNSResolveQueue::shared() +{ + DEFINE_STATIC_LOCAL(DNSResolveQueue, names, ()); + return names; +} + +void DNSResolveQueue::add(const String& name) +{ + // If there are no names queued, and few enough are in flight, resolve immediately (the mouse may be over a link). + if (!m_names.size()) { + if (atomicIncrement(&m_requestsInFlight) <= namesToResolveImmediately) { + resolve(name); + return; + } + atomicDecrement(&m_requestsInFlight); + } + m_names.add(name); + if (!isActive()) + startOneShot(coalesceDelay); +} + +void DNSResolveQueue::decrementRequestCount() +{ + atomicDecrement(&m_requestsInFlight); +} + +void DNSResolveQueue::fired() +{ + int requestsAllowed = maxRequestsToSend - m_requestsInFlight; + + for (HashSet<String>::iterator iter = m_names.begin(); iter != m_names.end() && requestsAllowed > 0; ++iter, --requestsAllowed) { + atomicIncrement(&m_requestsInFlight); + resolve(*iter); + } + + // It's better to skip some names than to clog the queue. + m_names.clear(); +} + +static void clientCallback(CFHostRef theHost, CFHostInfoType, const CFStreamError*, void*) +{ + DNSResolveQueue::shared().decrementRequestCount(); // It's ok to call shared() from a secondary thread, the static variable has already been initialized by now. + CFRelease(theHost); +} + +void DNSResolveQueue::resolve(const String& hostname) +{ + ASSERT(isMainThread()); + + RetainPtr<CFStringRef> hostnameCF(AdoptCF, hostname.createCFString()); + RetainPtr<CFHostRef> host(AdoptCF, CFHostCreateWithName(0, hostnameCF.get())); + if (!host) { + atomicDecrement(&m_requestsInFlight); + return; + } + CFHostClientContext context = { 0, 0, 0, 0, 0 }; + Boolean result = CFHostSetClient(host.get(), clientCallback, &context); + ASSERT_UNUSED(result, result); +#if !PLATFORM(WIN) + CFHostScheduleWithRunLoop(host.get(), CFRunLoopGetMain(), kCFRunLoopCommonModes); +#else + // On Windows, we run a separate thread with CFRunLoop, which is where clientCallback will be called. + CFHostScheduleWithRunLoop(host.get(), ResourceHandle::loaderRunLoop(), kCFRunLoopDefaultMode); +#endif + CFHostStartInfoResolution(host.get(), kCFHostAddresses, 0); + host.releaseRef(); // The host will be released from clientCallback(). +} + +void prefetchDNS(const String& hostname) { - notImplemented(); + ASSERT(isMainThread()); + if (hostname.isEmpty()) + return; + DNSResolveQueue::shared().add(hostname); } } diff --git a/WebCore/platform/network/cf/ResourceErrorCF.cpp b/WebCore/platform/network/cf/ResourceErrorCF.cpp index 8e82cd5..dacc68b 100644 --- a/WebCore/platform/network/cf/ResourceErrorCF.cpp +++ b/WebCore/platform/network/cf/ResourceErrorCF.cpp @@ -129,7 +129,7 @@ ResourceError::operator CFErrorRef() const if (!m_failingURL.isEmpty()) { RetainPtr<CFStringRef> failingURLString(AdoptCF, m_failingURL.createCFString()); CFDictionarySetValue(userInfo.get(), failingURLStringKey, failingURLString.get()); - RetainPtr<CFURLRef> url(AdoptCF, KURL(m_failingURL).createCFURL()); + RetainPtr<CFURLRef> url(AdoptCF, KURL(ParsedURLString, m_failingURL).createCFURL()); CFDictionarySetValue(userInfo.get(), failingURLKey, url.get()); } diff --git a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp index e348f83..ea5fcc6 100644 --- a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp +++ b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp @@ -31,9 +31,12 @@ #include "AuthenticationCF.h" #include "AuthenticationChallenge.h" -#include "CookieStorageWin.h" +#include "Base64.h" #include "CString.h" +#include "CookieStorageWin.h" +#include "CredentialStorage.h" #include "DocLoader.h" +#include "FormDataStreamCFNet.h" #include "Frame.h" #include "FrameLoader.h" #include "Logging.h" @@ -79,6 +82,8 @@ private: RetainPtr<CFURLRef> m_url; RetainPtr<CFStringRef> m_user; RetainPtr<CFStringRef> m_pass; + // Store the preemptively used initial credential so that if we get an authentication challenge, we won't use the same one again. + Credential m_initialCredential; bool m_allowStoredCredentials; ResourceResponse& m_response; RetainPtr<CFMutableDataRef> m_data; @@ -105,6 +110,16 @@ static void setDefaultMIMEType(CFURLResponseRef response) CFURLResponseSetMIMEType(response, defaultMIMETypeString); } +static String encodeBasicAuthorization(const String& user, const String& password) +{ + CString unencodedString = (user + ":" + password).utf8(); + Vector<char> unencoded(unencodedString.length()); + std::copy(unencodedString.data(), unencodedString.data() + unencodedString.length(), unencoded.begin()); + Vector<char> encoded; + base64Encode(unencoded, encoded); + return String(encoded.data(), encoded.size()); +} + CFURLRequestRef willSendRequest(CFURLConnectionRef conn, CFURLRequestRef cfRequest, CFURLResponseRef cfRedirectResponse, const void* clientInfo) { ResourceHandle* handle = static_cast<ResourceHandle*>(const_cast<void*>(clientInfo)); @@ -125,6 +140,16 @@ CFURLRequestRef willSendRequest(CFURLConnectionRef conn, CFURLRequestRef cfReque if (CFStringCompareWithOptions(originalMethod.get(), newMethod.get(), CFRangeMake(0, CFStringGetLength(originalMethod.get())), kCFCompareCaseInsensitive)) { RetainPtr<CFMutableURLRequestRef> mutableRequest(AdoptCF, CFURLRequestCreateMutableCopy(0, cfRequest)); CFURLRequestSetHTTPRequestMethod(mutableRequest.get(), originalMethod.get()); + + FormData* body = handle->request().httpBody(); + if (!equalIgnoringCase(handle->request().httpMethod(), "GET") && body && !body->isEmpty()) + WebCore::setHTTPBody(mutableRequest.get(), body); + + String originalContentType = handle->request().httpContentType(); + RetainPtr<CFStringRef> originalContentTypeCF(AdoptCF, originalContentType.createCFString()); + if (!originalContentType.isEmpty()) + CFURLRequestSetHTTPHeaderFieldValue(mutableRequest.get(), CFSTR("Content-Type"), originalContentTypeCF.get()); + request = mutableRequest.get(); } } @@ -374,6 +399,16 @@ bool ResourceHandle::start(Frame* frame) d->m_request.setURL(urlWithCredentials); } + // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication, + // try and reuse the credential preemptively, as allowed by RFC 2617. + if (!client() || client()->shouldUseCredentialStorage(this) && d->m_request.url().protocolInHTTPFamily()) + d->m_initialCredential = CredentialStorage::getDefaultAuthenticationCredential(d->m_request.url()); + + if (!d->m_initialCredential.isEmpty()) { + String authHeader = "Basic " + encodeBasicAuthorization(d->m_initialCredential.user(), d->m_initialCredential.password()); + d->m_request.addHTTPHeaderField("Authorization", authHeader); + } + RetainPtr<CFURLRequestRef> request(AdoptCF, makeFinalRequest(d->m_request, d->m_shouldContentSniff)); CFURLConnectionClient_V3 client = { 3, this, 0, 0, 0, WebCore::willSendRequest, didReceiveResponse, didReceiveData, NULL, didFinishLoading, didFail, willCacheResponse, didReceiveChallenge, didSendBodyData, shouldUseCredentialStorageCallback, 0}; @@ -441,7 +476,12 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall RetainPtr<CFStringRef> pass(AdoptCF, d->m_pass.createCFString()); RetainPtr<CFURLCredentialRef> credential(AdoptCF, CFURLCredentialCreate(kCFAllocatorDefault, user.get(), pass.get(), 0, kCFURLCredentialPersistenceNone)); - WebCoreCredentialStorage::set(CFURLAuthChallengeGetProtectionSpace(challenge.cfURLAuthChallengeRef()), credential.get()); + + KURL urlToStore; + if (challenge.failureResponse().httpStatusCode() == 401) + urlToStore = d->m_request.url(); + CredentialStorage::set(core(credential.get()), challenge.protectionSpace(), urlToStore); + CFURLConnectionUseCredential(d->m_connection.get(), credential.get(), challenge.cfURLAuthChallengeRef()); d->m_user = String(); d->m_pass = String(); @@ -450,10 +490,11 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall } if (!challenge.previousFailureCount() && (!client() || client()->shouldUseCredentialStorage(this))) { - CFURLCredentialRef credential = WebCoreCredentialStorage::get(CFURLAuthChallengeGetProtectionSpace(challenge.cfURLAuthChallengeRef())); - if (credential) { - ASSERT(CFURLCredentialGetPersistence(credential) == kCFURLCredentialPersistenceNone); - CFURLConnectionUseCredential(d->m_connection.get(), credential, challenge.cfURLAuthChallengeRef()); + Credential credential = CredentialStorage::get(challenge.protectionSpace()); + if (!credential.isEmpty() && credential != d->m_initialCredential) { + ASSERT(credential.persistence() == CredentialPersistenceNone); + RetainPtr<CFURLCredentialRef> cfCredential(AdoptCF, createCF(credential)); + CFURLConnectionUseCredential(d->m_connection.get(), cfCredential.get(), challenge.cfURLAuthChallengeRef()); return; } } @@ -478,7 +519,12 @@ void ResourceHandle::receivedCredential(const AuthenticationChallenge& challenge // to ignore it for a particular request (short of removing it altogether). Credential webCredential(credential.user(), credential.password(), CredentialPersistenceNone); RetainPtr<CFURLCredentialRef> cfCredential(AdoptCF, createCF(webCredential)); - WebCoreCredentialStorage::set(CFURLAuthChallengeGetProtectionSpace(challenge.cfURLAuthChallengeRef()), cfCredential.get()); + + KURL urlToStore; + if (challenge.failureResponse().httpStatusCode() == 401) + urlToStore = d->m_request.url(); + CredentialStorage::set(webCredential, challenge.protectionSpace(), urlToStore); + CFURLConnectionUseCredential(d->m_connection.get(), cfCredential.get(), challenge.cfURLAuthChallengeRef()); } else { RetainPtr<CFURLCredentialRef> cfCredential(AdoptCF, createCF(credential)); @@ -659,19 +705,28 @@ void WebCoreSynchronousLoader::didReceiveChallenge(CFURLConnectionRef conn, CFUR WebCoreSynchronousLoader* loader = static_cast<WebCoreSynchronousLoader*>(const_cast<void*>(clientInfo)); if (loader->m_user && loader->m_pass) { - RetainPtr<CFURLCredentialRef> credential(AdoptCF, - CFURLCredentialCreate(kCFAllocatorDefault, loader->m_user.get(), loader->m_pass.get(), 0, kCFURLCredentialPersistenceNone)); - WebCoreCredentialStorage::set(CFURLAuthChallengeGetProtectionSpace(challenge), credential.get()); - CFURLConnectionUseCredential(conn, credential.get(), challenge); + Credential credential(loader->m_user.get(), loader->m_pass.get(), CredentialPersistenceNone); + RetainPtr<CFURLCredentialRef> cfCredential(AdoptCF, createCF(credential)); + + CFURLResponseRef urlResponse = (CFURLResponseRef)CFURLAuthChallengeGetFailureResponse(challenge); + CFHTTPMessageRef httpResponse = urlResponse ? CFURLResponseGetHTTPResponse(urlResponse) : 0; + KURL urlToStore; + if (httpResponse && CFHTTPMessageGetResponseStatusCode(httpResponse) == 401) + urlToStore = loader->m_url.get(); + + CredentialStorage::set(credential, core(CFURLAuthChallengeGetProtectionSpace(challenge)), urlToStore); + + CFURLConnectionUseCredential(conn, cfCredential.get(), challenge); loader->m_user = 0; loader->m_pass = 0; return; } if (!CFURLAuthChallengeGetPreviousFailureCount(challenge) && loader->m_allowStoredCredentials) { - CFURLCredentialRef credential = WebCoreCredentialStorage::get(CFURLAuthChallengeGetProtectionSpace(challenge)); - if (credential) { - ASSERT(CFURLCredentialGetPersistence(credential) == kCFURLCredentialPersistenceNone); - CFURLConnectionUseCredential(conn, credential, challenge); + Credential credential = CredentialStorage::get(core(CFURLAuthChallengeGetProtectionSpace(challenge))); + if (!credential.isEmpty() && credential != loader->m_initialCredential) { + ASSERT(credential.persistence() == CredentialPersistenceNone); + RetainPtr<CFURLCredentialRef> cfCredential(AdoptCF, createCF(credential)); + CFURLConnectionUseCredential(conn, cfCredential.get(), challenge); return; } } @@ -696,8 +751,10 @@ RetainPtr<CFDataRef> WebCoreSynchronousLoader::load(const ResourceRequest& reque KURL url = request.url(); - loader.m_user.adoptCF(url.user().createCFString()); - loader.m_pass.adoptCF(url.pass().createCFString()); + if (url.user().length()) + loader.m_user.adoptCF(url.user().createCFString()); + if (url.pass().length()) + loader.m_pass.adoptCF(url.pass().createCFString()); loader.m_allowStoredCredentials = (storedCredentials == AllowStoredCredentials); // Take user/pass out of the URL. @@ -707,8 +764,20 @@ RetainPtr<CFDataRef> WebCoreSynchronousLoader::load(const ResourceRequest& reque ResourceRequest requestWithoutCredentials(request); requestWithoutCredentials.removeCredentials(); cfRequest.adoptCF(makeFinalRequest(requestWithoutCredentials, ResourceHandle::shouldContentSniffURL(requestWithoutCredentials.url()))); - } else - cfRequest.adoptCF(makeFinalRequest(request, ResourceHandle::shouldContentSniffURL(request.url()))); + } else { + // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication, + // try and reuse the credential preemptively, as allowed by RFC 2617. + ResourceRequest requestWithInitialCredential(request); + if (loader.m_allowStoredCredentials && url.protocolInHTTPFamily()) + loader.m_initialCredential = CredentialStorage::getDefaultAuthenticationCredential(url); + + if (!loader.m_initialCredential.isEmpty()) { + String authHeader = "Basic " + encodeBasicAuthorization(loader.m_initialCredential.user(), loader.m_initialCredential.password()); + requestWithInitialCredential.addHTTPHeaderField("Authorization", authHeader); + } + + cfRequest.adoptCF(makeFinalRequest(requestWithInitialCredential, ResourceHandle::shouldContentSniffURL(requestWithInitialCredential.url()))); + } CFURLConnectionClient_V3 client = { 3, &loader, 0, 0, 0, willSendRequest, didReceiveResponse, didReceiveData, 0, didFinishLoading, didFail, 0, didReceiveChallenge, 0, shouldUseCredentialStorage, 0 }; RetainPtr<CFURLConnectionRef> connection(AdoptCF, CFURLConnectionCreate(kCFAllocatorDefault, cfRequest.get(), reinterpret_cast<CFURLConnectionClient*>(&client))); diff --git a/WebCore/platform/network/cf/ResourceRequest.h b/WebCore/platform/network/cf/ResourceRequest.h index a4e9749..8ead412 100644 --- a/WebCore/platform/network/cf/ResourceRequest.h +++ b/WebCore/platform/network/cf/ResourceRequest.h @@ -37,7 +37,7 @@ namespace WebCore { struct ResourceRequest : ResourceRequestBase { ResourceRequest(const String& url) - : ResourceRequestBase(KURL(url), UseProtocolCachePolicy) + : ResourceRequestBase(KURL(ParsedURLString, url), UseProtocolCachePolicy) { } diff --git a/WebCore/platform/network/cf/ResourceRequestCFNet.cpp b/WebCore/platform/network/cf/ResourceRequestCFNet.cpp index 7355401..bba3d3e 100644 --- a/WebCore/platform/network/cf/ResourceRequestCFNet.cpp +++ b/WebCore/platform/network/cf/ResourceRequestCFNet.cpp @@ -112,7 +112,7 @@ void ResourceRequest::doUpdatePlatformRequest() addHeadersFromHashMap(cfRequest, httpHeaderFields()); WebCore::setHTTPBody(cfRequest, httpBody()); - CFURLRequestSetShouldHandleHTTPCookies(cfRequest, allowHTTPCookies()); + CFURLRequestSetShouldHandleHTTPCookies(cfRequest, allowCookies()); unsigned fallbackCount = m_responseContentDispositionEncodingFallbackArray.size(); RetainPtr<CFMutableArrayRef> encodingFallbacks(AdoptCF, CFArrayCreateMutable(kCFAllocatorDefault, fallbackCount, 0)); @@ -146,7 +146,7 @@ void ResourceRequest::doUpdateResourceRequest() m_httpMethod = method; CFRelease(method); } - m_allowHTTPCookies = CFURLRequestShouldHandleHTTPCookies(m_cfRequest.get()); + m_allowCookies = CFURLRequestShouldHandleHTTPCookies(m_cfRequest.get()); if (CFDictionaryRef headers = CFURLRequestCopyAllHTTPHeaderFields(m_cfRequest.get())) { CFIndex headerCount = CFDictionaryGetCount(headers); diff --git a/WebCore/platform/network/cf/SocketStreamError.h b/WebCore/platform/network/cf/SocketStreamError.h new file mode 100644 index 0000000..f9641ad --- /dev/null +++ b/WebCore/platform/network/cf/SocketStreamError.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER 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 SocketStreamError_h +#define SocketStreamError_h + +#include "SocketStreamErrorBase.h" + +namespace WebCore { + + class SocketStreamError : public SocketStreamErrorBase { + public: + SocketStreamError() { } + explicit SocketStreamError(int errorCode) + : SocketStreamErrorBase(errorCode) + { + } + + }; + +} // namespace WebCore + +#endif // SocketStreamError_h diff --git a/WebCore/platform/network/cf/SocketStreamHandle.h b/WebCore/platform/network/cf/SocketStreamHandle.h new file mode 100644 index 0000000..64139e5 --- /dev/null +++ b/WebCore/platform/network/cf/SocketStreamHandle.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER 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 SocketStreamHandle_h +#define SocketStreamHandle_h + +#include "SocketStreamHandleBase.h" + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + + class AuthenticationChallenge; + class Credential; + class SocketStreamHandleClient; + + class SocketStreamHandle : public RefCounted<SocketStreamHandle>, public SocketStreamHandleBase { + public: + static PassRefPtr<SocketStreamHandle> create(const KURL& url, SocketStreamHandleClient* client) { return adoptRef(new SocketStreamHandle(url, client)); } + + virtual ~SocketStreamHandle(); + + protected: + virtual int platformSend(const char* data, int length); + virtual void platformClose(); + + private: + SocketStreamHandle(const KURL&, SocketStreamHandleClient*); + + // No authentication for streams per se, but proxy may ask for credentials. + void didReceiveAuthenticationChallenge(const AuthenticationChallenge&); + void receivedCredential(const AuthenticationChallenge&, const Credential&); + void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&); + void receivedCancellation(const AuthenticationChallenge&); + }; + +} // namespace WebCore + +#endif // SocketStreamHandle_h diff --git a/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp b/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp new file mode 100644 index 0000000..6aa33fc --- /dev/null +++ b/WebCore/platform/network/cf/SocketStreamHandleCFNet.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER 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 "SocketStreamHandle.h" + +#include "KURL.h" +#include "Logging.h" +#include "NotImplemented.h" +#include "SocketStreamHandleClient.h" + +namespace WebCore { + +SocketStreamHandle::SocketStreamHandle(const KURL& url, SocketStreamHandleClient* client) + : SocketStreamHandleBase(url, client) +{ + LOG(Network, "SocketStreamHandle %p new client %p", this, m_client); + notImplemented(); +} + +SocketStreamHandle::~SocketStreamHandle() +{ + LOG(Network, "SocketStreamHandle %p delete", this); + setClient(0); + notImplemented(); +} + +int SocketStreamHandle::platformSend(const char*, int) +{ + LOG(Network, "SocketStreamHandle %p platformSend", this); + notImplemented(); + return 0; +} + +void SocketStreamHandle::platformClose() +{ + LOG(Network, "SocketStreamHandle %p platformClose", this); + notImplemented(); +} + +void SocketStreamHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge&) +{ + notImplemented(); +} + +void SocketStreamHandle::receivedCredential(const AuthenticationChallenge&, const Credential&) +{ + notImplemented(); +} + +void SocketStreamHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&) +{ + notImplemented(); +} + +void SocketStreamHandle::receivedCancellation(const AuthenticationChallenge&) +{ + notImplemented(); +} + +} // namespace WebCore diff --git a/WebCore/platform/network/chromium/CookieJarChromium.cpp b/WebCore/platform/network/chromium/CookieJarChromium.cpp index 65be451..7862cc3 100644 --- a/WebCore/platform/network/chromium/CookieJarChromium.cpp +++ b/WebCore/platform/network/chromium/CookieJarChromium.cpp @@ -31,6 +31,7 @@ #include "config.h" #include "CookieJar.h" +#include "Cookie.h" #include "ChromiumBridge.h" #include "Document.h" @@ -52,4 +53,16 @@ bool cookiesEnabled(const Document*) return true; } +bool getRawCookies(const Document*, const KURL&, Vector<Cookie>& rawCookies) +{ + // FIXME: Not yet implemented + rawCookies.clear(); + return false; // return true when implemented +} + +void deleteCookie(const Document*, const KURL&, const String&) +{ + // FIXME: Not yet implemented +} + } // namespace WebCore diff --git a/WebCore/platform/network/chromium/ResourceRequest.h b/WebCore/platform/network/chromium/ResourceRequest.h index aa76de4..48ff1e7 100644 --- a/WebCore/platform/network/chromium/ResourceRequest.h +++ b/WebCore/platform/network/chromium/ResourceRequest.h @@ -46,10 +46,10 @@ namespace WebCore { }; ResourceRequest(const String& url) - : ResourceRequestBase(KURL(url), UseProtocolCachePolicy) + : ResourceRequestBase(KURL(ParsedURLString, url), UseProtocolCachePolicy) , m_requestorID(0) , m_requestorProcessID(0) - , m_appCacheContextID(0) + , m_appCacheHostID(0) , m_targetType(TargetIsSubResource) { } @@ -58,7 +58,7 @@ namespace WebCore { : ResourceRequestBase(url, UseProtocolCachePolicy) , m_requestorID(0) , m_requestorProcessID(0) - , m_appCacheContextID(0) + , m_appCacheHostID(0) , m_targetType(TargetIsSubResource) , m_securityInfo(securityInfo) { @@ -68,7 +68,7 @@ namespace WebCore { : ResourceRequestBase(url, UseProtocolCachePolicy) , m_requestorID(0) , m_requestorProcessID(0) - , m_appCacheContextID(0) + , m_appCacheHostID(0) , m_targetType(TargetIsSubResource) { } @@ -77,7 +77,7 @@ namespace WebCore { : ResourceRequestBase(url, policy) , m_requestorID(0) , m_requestorProcessID(0) - , m_appCacheContextID(0) + , m_appCacheHostID(0) , m_targetType(TargetIsSubResource) { setHTTPReferrer(referrer); @@ -87,7 +87,7 @@ namespace WebCore { : ResourceRequestBase(KURL(), UseProtocolCachePolicy) , m_requestorID(0) , m_requestorProcessID(0) - , m_appCacheContextID(0) + , m_appCacheHostID(0) , m_targetType(TargetIsSubResource) { } @@ -107,9 +107,9 @@ namespace WebCore { int requestorProcessID() const { return m_requestorProcessID; } void setRequestorProcessID(int requestorProcessID) { m_requestorProcessID = requestorProcessID; } - // Allows the request to be matched up with its app cache context. - int appCacheContextID() const { return m_appCacheContextID; } - void setAppCacheContextID(int id) { m_appCacheContextID = id; } + // Allows the request to be matched up with its app cache host. + int appCacheHostID() const { return m_appCacheHostID; } + void setAppCacheHostID(int id) { m_appCacheHostID = id; } // Opaque buffer that describes the security state (including SSL // connection state) for the resource that should be reported when the @@ -128,7 +128,7 @@ namespace WebCore { int m_requestorID; int m_requestorProcessID; - int m_appCacheContextID; + int m_appCacheHostID; TargetType m_targetType; CString m_securityInfo; }; diff --git a/WebCore/platform/network/chromium/ResourceResponse.h b/WebCore/platform/network/chromium/ResourceResponse.h index 6c928c0..0c2b5d9 100644 --- a/WebCore/platform/network/chromium/ResourceResponse.h +++ b/WebCore/platform/network/chromium/ResourceResponse.h @@ -60,12 +60,18 @@ namespace WebCore { m_isContentFiltered = isContentFiltered; } - long long getAppCacheID() const { return m_appCacheID; } + long long appCacheID() const { return m_appCacheID; } void setAppCacheID(long long id) { m_appCacheID = id; } + const KURL& appCacheManifestURL() const { return m_appCacheManifestURL; } + void setAppCacheManifestURL(const KURL& url) + { + m_appCacheManifestURL = url; + } + private: friend class ResourceResponseBase; @@ -86,6 +92,10 @@ namespace WebCore { // The id of the appcache this response was retrieved from, or zero if // the response was not retrieved from an appcache. long long m_appCacheID; + + // The manifest url of the appcache this response was retrieved from, if any. + // Note: only valid for main resource responses. + KURL m_appCacheManifestURL; }; } // namespace WebCore diff --git a/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumLinux.cpp b/WebCore/platform/network/chromium/SocketStreamError.h index 3582448..540496b 100644 --- a/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumLinux.cpp +++ b/WebCore/platform/network/chromium/SocketStreamError.h @@ -28,15 +28,20 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" -#include "SQLiteFileSystem.h" +#ifndef SocketStreamError_h +#define SocketStreamError_h + +#include "SocketStreamErrorBase.h" namespace WebCore { -void SQLiteFileSystem::registerSQLiteVFS() -{ - // stub for registering Chromium's SQLite VFS for Linux - ASSERT_NOT_REACHED(); -} +class SocketStreamError : public SocketStreamErrorBase { +public: + SocketStreamError() { } + explicit SocketStreamError(int errorCode) + : SocketStreamErrorBase(errorCode) { } +}; + +} // namespace WebCore -} // namespace WebCore +#endif // SocketStreamError_h diff --git a/WebCore/platform/network/chromium/SocketStreamHandle.h b/WebCore/platform/network/chromium/SocketStreamHandle.h new file mode 100644 index 0000000..5a905cb --- /dev/null +++ b/WebCore/platform/network/chromium/SocketStreamHandle.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER 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 SocketStreamHandle_h +#define SocketStreamHandle_h + +#include "SocketStreamHandleBase.h" + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + + class AuthenticationChallenge; + class Credential; + class SocketStreamHandleClient; + class SocketStreamHandleInternal; + + class SocketStreamHandle : public RefCounted<SocketStreamHandle>, public SocketStreamHandleBase { + public: + static PassRefPtr<SocketStreamHandle> create(const KURL& url, SocketStreamHandleClient* client) { return adoptRef(new SocketStreamHandle(url, client)); } + + virtual ~SocketStreamHandle(); + + protected: + virtual int platformSend(const char* data, int length); + virtual void platformClose(); + + private: + SocketStreamHandle(const KURL&, SocketStreamHandleClient*); + + // No authentication for streams per se, but proxy may ask for credentials. + void didReceiveAuthenticationChallenge(const AuthenticationChallenge&); + void receivedCredential(const AuthenticationChallenge&, const Credential&); + void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&); + void receivedCancellation(const AuthenticationChallenge&); + + friend class SocketStreamHandleInternal; + OwnPtr<SocketStreamHandleInternal> m_internal; + }; + +} // namespace WebCore + +#endif // SocketStreamHandle_h diff --git a/WebCore/platform/network/curl/CookieJarCurl.cpp b/WebCore/platform/network/curl/CookieJarCurl.cpp index 5ac0f9c..3bad4e4 100644 --- a/WebCore/platform/network/curl/CookieJarCurl.cpp +++ b/WebCore/platform/network/curl/CookieJarCurl.cpp @@ -17,6 +17,7 @@ #include "config.h" #include "CookieJar.h" +#include "Cookie.h" #include "Document.h" #include "KURL.h" #include "PlatformString.h" @@ -43,4 +44,16 @@ bool cookiesEnabled(const Document* /*document*/) return true; } +bool getRawCookies(const Document*, const KURL&, Vector<Cookie>& rawCookies) +{ + // FIXME: Not yet implemented + rawCookies.clear(); + return false; // return true when implemented +} + +void deleteCookie(const Document*, const KURL&, const String&) +{ + // FIXME: Not yet implemented +} + } diff --git a/WebCore/platform/network/curl/ResourceHandleCurl.cpp b/WebCore/platform/network/curl/ResourceHandleCurl.cpp index a6f5dca..5469ec9 100644 --- a/WebCore/platform/network/curl/ResourceHandleCurl.cpp +++ b/WebCore/platform/network/curl/ResourceHandleCurl.cpp @@ -103,7 +103,13 @@ ResourceHandle::~ResourceHandle() bool ResourceHandle::start(Frame* frame) { - ASSERT(frame); + // The frame could be null if the ResourceHandle is not associated to any + // Frame, e.g. if we are downloading a file. + // If the frame is not null but the page is null this must be an attempted + // load from an onUnload handler, so let's just block it. + if (frame && !frame->page()) + return false; + ResourceHandleManager::sharedInstance()->add(this); return true; } diff --git a/WebCore/platform/network/curl/ResourceHandleManager.cpp b/WebCore/platform/network/curl/ResourceHandleManager.cpp index 2aa286a..14c6f31 100644 --- a/WebCore/platform/network/curl/ResourceHandleManager.cpp +++ b/WebCore/platform/network/curl/ResourceHandleManager.cpp @@ -5,6 +5,8 @@ * Copyright (C) 2007 Holger Hans Peter Freyther * Copyright (C) 2008 Collabora Ltd. * Copyright (C) 2008 Nuanti Ltd. + * Copyright (C) 2009 Appcelerator Inc. + * Copyright (C) 2009 Brent Fulgham <bfulgham@webkit.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,6 +46,7 @@ #include <errno.h> #include <stdio.h> +#include <wtf/Threading.h> #include <wtf/Vector.h> namespace WebCore { @@ -54,16 +57,72 @@ const int maxRunningJobs = 5; static const bool ignoreSSLErrors = getenv("WEBKIT_IGNORE_SSL_ERRORS"); +static CString certificatePath() +{ +#if PLATFORM(CF) + CFBundleRef webKitBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.WebKit")); + if (webKitBundle) { + RetainPtr<CFURLRef> certURLRef(AdoptCF, CFBundleCopyResourceURL(webKitBundle, CFSTR("cacert"), CFSTR("pem"), CFSTR("certificates"))); + if (certURLRef) { + char path[MAX_PATH]; + CFURLGetFileSystemRepresentation(certURLRef.get(), false, reinterpret_cast<UInt8*>(path), MAX_PATH); + return path; + } + } +#endif + char* envPath = getenv("CURL_CA_BUNDLE_PATH"); + if (envPath) + return envPath; + + return CString(); +} + +static Mutex* sharedResourceMutex(curl_lock_data data) { + DEFINE_STATIC_LOCAL(Mutex, cookieMutex, ()); + DEFINE_STATIC_LOCAL(Mutex, dnsMutex, ()); + DEFINE_STATIC_LOCAL(Mutex, shareMutex, ()); + + switch (data) { + case CURL_LOCK_DATA_COOKIE: + return &cookieMutex; + case CURL_LOCK_DATA_DNS: + return &dnsMutex; + case CURL_LOCK_DATA_SHARE: + return &shareMutex; + default: + ASSERT_NOT_REACHED(); + return NULL; + } +} + +// libcurl does not implement its own thread synchronization primitives. +// these two functions provide mutexes for cookies, and for the global DNS +// cache. +static void curl_lock_callback(CURL* handle, curl_lock_data data, curl_lock_access access, void* userPtr) +{ + if (Mutex* mutex = sharedResourceMutex(data)) + mutex->lock(); +} + +static void curl_unlock_callback(CURL* handle, curl_lock_data data, void* userPtr) +{ + if (Mutex* mutex = sharedResourceMutex(data)) + mutex->unlock(); +} + ResourceHandleManager::ResourceHandleManager() : m_downloadTimer(this, &ResourceHandleManager::downloadTimerCallback) , m_cookieJarFileName(0) , m_runningJobs(0) + , m_certificatePath (certificatePath()) { curl_global_init(CURL_GLOBAL_ALL); m_curlMultiHandle = curl_multi_init(); m_curlShareHandle = curl_share_init(); curl_share_setopt(m_curlShareHandle, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); curl_share_setopt(m_curlShareHandle, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS); + curl_share_setopt(m_curlShareHandle, CURLSHOPT_LOCKFUNC, curl_lock_callback); + curl_share_setopt(m_curlShareHandle, CURLSHOPT_UNLOCKFUNC, curl_unlock_callback); } ResourceHandleManager::~ResourceHandleManager() @@ -88,6 +147,23 @@ ResourceHandleManager* ResourceHandleManager::sharedInstance() return sharedInstance; } +static void handleLocalReceiveResponse (CURL* handle, ResourceHandle* job, ResourceHandleInternal* d) +{ + // since the code in headerCallback will not have run for local files + // the code to set the URL and fire didReceiveResponse is never run, + // which means the ResourceLoader's response does not contain the URL. + // Run the code here for local files to resolve the issue. + // TODO: See if there is a better approach for handling this. + const char* hdr; + CURLcode err = curl_easy_getinfo(handle, CURLINFO_EFFECTIVE_URL, &hdr); + ASSERT(CURLE_OK == err); + d->m_response.setURL(KURL(ParsedURLString, hdr)); + if (d->client()) + d->client()->didReceiveResponse(job, d->m_response); + d->m_response.setResponseFired(true); +} + + // called with data after all headers have been processed via headerCallback static size_t writeCallback(void* ptr, size_t size, size_t nmemb, void* data) { @@ -112,18 +188,10 @@ static size_t writeCallback(void* ptr, size_t size, size_t nmemb, void* data) if (CURLE_OK == err && httpCode >= 300 && httpCode < 400) return totalSize; - // since the code in headerCallback will not have run for local files - // the code to set the URL and fire didReceiveResponse is never run, - // which means the ResourceLoader's response does not contain the URL. - // Run the code here for local files to resolve the issue. - // TODO: See if there is a better approach for handling this. if (!d->m_response.responseFired()) { - const char* hdr; - err = curl_easy_getinfo(h, CURLINFO_EFFECTIVE_URL, &hdr); - d->m_response.setURL(KURL(hdr)); - if (d->client()) - d->client()->didReceiveResponse(job, d->m_response); - d->m_response.setResponseFired(true); + handleLocalReceiveResponse(h, job, d); + if (d->m_cancelled) + return 0; } if (d->client()) @@ -174,7 +242,7 @@ static size_t headerCallback(char* ptr, size_t size, size_t nmemb, void* data) const char* hdr; err = curl_easy_getinfo(h, CURLINFO_EFFECTIVE_URL, &hdr); - d->m_response.setURL(KURL(hdr)); + d->m_response.setURL(KURL(ParsedURLString, hdr)); long httpCode = 0; err = curl_easy_getinfo(h, CURLINFO_RESPONSE_CODE, &httpCode); @@ -222,6 +290,7 @@ size_t readCallback(void* ptr, size_t size, size_t nmemb, void* data) { ResourceHandle* job = static_cast<ResourceHandle*>(data); ResourceHandleInternal* d = job->getInternal(); + if (d->m_cancelled) return 0; @@ -311,6 +380,14 @@ void ResourceHandleManager::downloadTimerCallback(Timer<ResourceHandleManager>* continue; if (CURLE_OK == msg->data.result) { + if (!d->m_response.responseFired()) { + handleLocalReceiveResponse(d->m_handle, job, d); + if (d->m_cancelled) { + removeFromCurl(job); + continue; + } + } + if (d->client()) d->client()->didFinishLoading(job); } else { @@ -629,6 +706,10 @@ void ResourceHandleManager::initializeHandle(ResourceHandle* job) // and/or reporting SSL errors to the user. if (ignoreSSLErrors) curl_easy_setopt(d->m_handle, CURLOPT_SSL_VERIFYPEER, false); + + if (!m_certificatePath.isNull()) + curl_easy_setopt(d->m_handle, CURLOPT_CAINFO, m_certificatePath.data()); + // enable gzip and deflate through Accept-Encoding: curl_easy_setopt(d->m_handle, CURLOPT_ENCODING, ""); diff --git a/WebCore/platform/network/curl/ResourceHandleManager.h b/WebCore/platform/network/curl/ResourceHandleManager.h index d38e577..89b27d7 100644 --- a/WebCore/platform/network/curl/ResourceHandleManager.h +++ b/WebCore/platform/network/curl/ResourceHandleManager.h @@ -29,6 +29,7 @@ #define ResourceHandleManager_h #include "Frame.h" +#include "CString.h" #include "Timer.h" #include "ResourceHandleClient.h" @@ -71,6 +72,7 @@ private: char* m_cookieJarFileName; char m_curlErrorBuffer[CURL_ERROR_SIZE]; Vector<ResourceHandle*> m_resourceHandleList; + const CString m_certificatePath; int m_runningJobs; }; diff --git a/WebCore/platform/network/curl/ResourceRequest.h b/WebCore/platform/network/curl/ResourceRequest.h index b3032aa..3fa2795 100644 --- a/WebCore/platform/network/curl/ResourceRequest.h +++ b/WebCore/platform/network/curl/ResourceRequest.h @@ -36,7 +36,7 @@ namespace WebCore { struct ResourceRequest : ResourceRequestBase { ResourceRequest(const String& url) - : ResourceRequestBase(KURL(url), UseProtocolCachePolicy) + : ResourceRequestBase(KURL(ParsedURLString, url), UseProtocolCachePolicy) { } diff --git a/WebCore/platform/network/curl/SocketStreamError.h b/WebCore/platform/network/curl/SocketStreamError.h new file mode 100644 index 0000000..f9641ad --- /dev/null +++ b/WebCore/platform/network/curl/SocketStreamError.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER 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 SocketStreamError_h +#define SocketStreamError_h + +#include "SocketStreamErrorBase.h" + +namespace WebCore { + + class SocketStreamError : public SocketStreamErrorBase { + public: + SocketStreamError() { } + explicit SocketStreamError(int errorCode) + : SocketStreamErrorBase(errorCode) + { + } + + }; + +} // namespace WebCore + +#endif // SocketStreamError_h diff --git a/WebCore/platform/network/curl/SocketStreamHandle.h b/WebCore/platform/network/curl/SocketStreamHandle.h new file mode 100644 index 0000000..64139e5 --- /dev/null +++ b/WebCore/platform/network/curl/SocketStreamHandle.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER 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 SocketStreamHandle_h +#define SocketStreamHandle_h + +#include "SocketStreamHandleBase.h" + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + + class AuthenticationChallenge; + class Credential; + class SocketStreamHandleClient; + + class SocketStreamHandle : public RefCounted<SocketStreamHandle>, public SocketStreamHandleBase { + public: + static PassRefPtr<SocketStreamHandle> create(const KURL& url, SocketStreamHandleClient* client) { return adoptRef(new SocketStreamHandle(url, client)); } + + virtual ~SocketStreamHandle(); + + protected: + virtual int platformSend(const char* data, int length); + virtual void platformClose(); + + private: + SocketStreamHandle(const KURL&, SocketStreamHandleClient*); + + // No authentication for streams per se, but proxy may ask for credentials. + void didReceiveAuthenticationChallenge(const AuthenticationChallenge&); + void receivedCredential(const AuthenticationChallenge&, const Credential&); + void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&); + void receivedCancellation(const AuthenticationChallenge&); + }; + +} // namespace WebCore + +#endif // SocketStreamHandle_h diff --git a/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp b/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp new file mode 100644 index 0000000..891e96e --- /dev/null +++ b/WebCore/platform/network/curl/SocketStreamHandleCurl.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2009 Brent Fulgham. All rights reserved. + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER 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 "SocketStreamHandle.h" + +#include "KURL.h" +#include "Logging.h" +#include "NotImplemented.h" +#include "SocketStreamHandleClient.h" + +namespace WebCore { + +SocketStreamHandle::SocketStreamHandle(const KURL& url, SocketStreamHandleClient* client) + : SocketStreamHandleBase(url, client) +{ + LOG(Network, "SocketStreamHandle %p new client %p", this, m_client); + notImplemented(); +} + +SocketStreamHandle::~SocketStreamHandle() +{ + LOG(Network, "SocketStreamHandle %p delete", this); + setClient(0); + notImplemented(); +} + +int SocketStreamHandle::platformSend(const char*, int) +{ + LOG(Network, "SocketStreamHandle %p platformSend", this); + notImplemented(); + return 0; +} + +void SocketStreamHandle::platformClose() +{ + LOG(Network, "SocketStreamHandle %p platformClose", this); + notImplemented(); +} + +void SocketStreamHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge&) +{ + notImplemented(); +} + +void SocketStreamHandle::receivedCredential(const AuthenticationChallenge&, const Credential&) +{ + notImplemented(); +} + +void SocketStreamHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&) +{ + notImplemented(); +} + +void SocketStreamHandle::receivedCancellation(const AuthenticationChallenge&) +{ + notImplemented(); +} + +} // namespace WebCore diff --git a/WebCore/platform/network/mac/AuthenticationMac.h b/WebCore/platform/network/mac/AuthenticationMac.h index 7fb6bee..f55ac24 100644 --- a/WebCore/platform/network/mac/AuthenticationMac.h +++ b/WebCore/platform/network/mac/AuthenticationMac.h @@ -45,24 +45,6 @@ AuthenticationChallenge core(NSURLAuthenticationChallenge *); ProtectionSpace core(NSURLProtectionSpace *); Credential core(NSURLCredential *); -class WebCoreCredentialStorage { -public: - static void set(NSURLCredential *credential, NSURLProtectionSpace *protectionSpace) - { - if (!m_storage) - m_storage = [[NSMutableDictionary alloc] init]; - [m_storage setObject:credential forKey:protectionSpace]; - } - - static NSURLCredential *get(NSURLProtectionSpace *protectionSpace) - { - return static_cast<NSURLCredential *>([m_storage objectForKey:protectionSpace]); - } - -private: - static NSMutableDictionary* m_storage; -}; - } #endif diff --git a/WebCore/platform/network/mac/AuthenticationMac.mm b/WebCore/platform/network/mac/AuthenticationMac.mm index 961a79d..355931d 100644 --- a/WebCore/platform/network/mac/AuthenticationMac.mm +++ b/WebCore/platform/network/mac/AuthenticationMac.mm @@ -36,9 +36,6 @@ namespace WebCore { - -NSMutableDictionary* WebCoreCredentialStorage::m_storage; - AuthenticationChallenge::AuthenticationChallenge(const ProtectionSpace& protectionSpace, const Credential& proposedCredential, unsigned previousFailureCount, diff --git a/WebCore/platform/network/mac/FormDataStreamMac.mm b/WebCore/platform/network/mac/FormDataStreamMac.mm index a8d6887..8aa9a6d 100644 --- a/WebCore/platform/network/mac/FormDataStreamMac.mm +++ b/WebCore/platform/network/mac/FormDataStreamMac.mm @@ -161,11 +161,9 @@ static void advanceCurrentStream(FormStreamFields *form) form->currentData = data; } else { const String& path = nextInput.m_shouldGenerateFile ? nextInput.m_generatedFilename : nextInput.m_filename; - CFStringRef filename = path.createCFString(); - CFURLRef fileURL = CFURLCreateWithFileSystemPath(0, filename, kCFURLPOSIXPathStyle, FALSE); - CFRelease(filename); - form->currentStream = CFReadStreamCreateWithFile(0, fileURL); - CFRelease(fileURL); + RetainPtr<CFStringRef> filename(AdoptCF, path.createCFString()); + RetainPtr<CFURLRef> fileURL(AdoptCF, CFURLCreateWithFileSystemPath(0, filename.get(), kCFURLPOSIXPathStyle, FALSE)); + form->currentStream = CFReadStreamCreateWithFile(0, fileURL.get()); } form->remainingElements.removeLast(); @@ -375,11 +373,10 @@ void setHTTPBody(NSMutableURLRequest *request, PassRefPtr<FormData> formData) // Pass the length along with the formData so it does not have to be recomputed. FormContext formContext = { formData.releaseRef(), length }; - CFReadStreamRef stream = wkCreateCustomCFReadStream(formCreate, formFinalize, + RetainPtr<CFReadStreamRef> stream(AdoptCF, wkCreateCustomCFReadStream(formCreate, formFinalize, formOpen, formRead, formCanRead, formClose, formSchedule, formUnschedule, - &formContext); - [request setHTTPBodyStream:(NSInputStream *)stream]; - CFRelease(stream); + &formContext)); + [request setHTTPBodyStream:(NSInputStream *)stream.get()]; } FormData* httpBodyFromStream(NSInputStream* stream) diff --git a/WebCore/platform/network/mac/ResourceErrorMac.mm b/WebCore/platform/network/mac/ResourceErrorMac.mm index 94c2124..efd738f 100644 --- a/WebCore/platform/network/mac/ResourceErrorMac.mm +++ b/WebCore/platform/network/mac/ResourceErrorMac.mm @@ -76,7 +76,7 @@ ResourceError::operator NSError*() const [userInfo.get() setValue:m_localizedDescription forKey:NSLocalizedDescriptionKey]; if (!m_failingURL.isEmpty()) { - NSURL *cocoaURL = KURL(m_failingURL); + NSURL *cocoaURL = KURL(ParsedURLString, m_failingURL); [userInfo.get() setValue:m_failingURL forKey:@"NSErrorFailingURLStringKey"]; [userInfo.get() setValue:cocoaURL forKey:@"NSErrorFailingURLKey"]; } diff --git a/WebCore/platform/network/mac/ResourceHandleMac.mm b/WebCore/platform/network/mac/ResourceHandleMac.mm index db76d1a..ec60079 100644 --- a/WebCore/platform/network/mac/ResourceHandleMac.mm +++ b/WebCore/platform/network/mac/ResourceHandleMac.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2006 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2006-2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,7 +28,10 @@ #import "AuthenticationChallenge.h" #import "AuthenticationMac.h" +#import "Base64.h" #import "BlockExceptions.h" +#import "CString.h" +#import "CredentialStorage.h" #import "DocLoader.h" #import "FormDataStreamMac.h" #import "Frame.h" @@ -64,10 +67,6 @@ using namespace WebCore; - (NSData *)_bufferedData; @end -@interface NSURLResponse (Details) -- (void)_setMIMEType:(NSString *)type; -@end - @interface NSURLRequest (Details) - (id)_propertyForKey:(NSString *)key; @end @@ -78,6 +77,8 @@ using namespace WebCore; NSURL *m_url; NSString *m_user; NSString *m_pass; + // Store the preemptively used initial credential so that if we get an authentication challenge, we won't use the same one again. + Credential m_initialCredential; BOOL m_allowStoredCredentials; NSURLResponse *m_response; NSMutableData *m_data; @@ -118,6 +119,16 @@ public: } }; +static String encodeBasicAuthorization(const String& user, const String& password) +{ + CString unencodedString = (user + ":" + password).utf8(); + Vector<char> unencoded(unencodedString.length()); + std::copy(unencodedString.data(), unencodedString.data() + unencodedString.length(), unencoded.begin()); + Vector<char> encoded; + base64Encode(unencoded, encoded); + return String(encoded.data(), encoded.size()); +} + ResourceHandleInternal::~ResourceHandleInternal() { } @@ -171,6 +182,16 @@ bool ResourceHandle::start(Frame* frame) urlWithCredentials.setPass(d->m_pass); d->m_request.setURL(urlWithCredentials); } + + // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication, + // try and reuse the credential preemptively, as allowed by RFC 2617. + if (!client() || client()->shouldUseCredentialStorage(this) && d->m_request.url().protocolInHTTPFamily()) + d->m_initialCredential = CredentialStorage::getDefaultAuthenticationCredential(d->m_request.url()); + + if (!d->m_initialCredential.isEmpty()) { + String authHeader = "Basic " + encodeBasicAuthorization(d->m_initialCredential.user(), d->m_initialCredential.password()); + d->m_request.addHTTPHeaderField("Authorization", authHeader); + } if (!ResourceHandle::didSendBodyDataDelegateExists()) associateStreamWithResourceHandle([d->m_request.nsURLRequest() HTTPBodyStream], this); @@ -249,6 +270,10 @@ void ResourceHandle::cancel() { LOG(Network, "Handle %p cancel connection %p", this, d->m_connection.get()); + // Leaks were seen on HTTP tests without this; can be removed once <rdar://problem/6886937> is fixed. + if (d->m_currentMacChallenge) + [[d->m_currentMacChallenge sender] cancelAuthenticationChallenge:d->m_currentMacChallenge]; + if (!ResourceHandle::didSendBodyDataDelegateExists()) disassociateStreamWithResourceHandle([d->m_request.nsURLRequest() HTTPBodyStream]); [d->m_connection.get() cancel]; @@ -458,9 +483,10 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall } if (!challenge.previousFailureCount() && (!client() || client()->shouldUseCredentialStorage(this))) { - NSURLCredential *credential = WebCoreCredentialStorage::get([mac(challenge) protectionSpace]); - if (credential) { - [challenge.sender() useCredential:credential forAuthenticationChallenge:mac(challenge)]; + Credential credential = CredentialStorage::get(challenge.protectionSpace()); + if (!credential.isEmpty() && credential != d->m_initialCredential) { + ASSERT(credential.persistence() == CredentialPersistenceNone); + [challenge.sender() useCredential:mac(credential) forAuthenticationChallenge:mac(challenge)]; return; } } @@ -495,7 +521,11 @@ void ResourceHandle::receivedCredential(const AuthenticationChallenge& challenge if (credential.persistence() == CredentialPersistenceNone) { // NSURLCredentialPersistenceNone doesn't work on Tiger, so we have to use session persistence. Credential webCredential(credential.user(), credential.password(), CredentialPersistenceForSession); - WebCoreCredentialStorage::set(mac(webCredential), [d->m_currentMacChallenge protectionSpace]); + KURL urlToStore; + if (challenge.failureResponse().httpStatusCode() == 401) + urlToStore = d->m_request.url(); + CredentialStorage::set(webCredential, core([d->m_currentMacChallenge protectionSpace]), urlToStore); + [[d->m_currentMacChallenge sender] useCredential:mac(webCredential) forAuthenticationChallenge:d->m_currentMacChallenge]; } else #else @@ -504,7 +534,10 @@ void ResourceHandle::receivedCredential(const AuthenticationChallenge& challenge // to ignore it for a particular request (short of removing it altogether). // <rdar://problem/6867598> gallery.me.com is temporarily whitelisted, so that QuickTime plug-in could see the credentials. Credential webCredential(credential.user(), credential.password(), CredentialPersistenceNone); - WebCoreCredentialStorage::set(mac(webCredential), [d->m_currentMacChallenge protectionSpace]); + KURL urlToStore; + if (challenge.failureResponse().httpStatusCode() == 401) + urlToStore = d->m_request.url(); + CredentialStorage::set(webCredential, core([d->m_currentMacChallenge protectionSpace]), urlToStore); [[d->m_currentMacChallenge sender] useCredential:mac(webCredential) forAuthenticationChallenge:d->m_currentMacChallenge]; } else #endif @@ -572,6 +605,15 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen if (!equalIgnoringCase(originalMethod, String([newRequest HTTPMethod]))) { NSMutableURLRequest *mutableRequest = [newRequest mutableCopy]; [mutableRequest setHTTPMethod:originalMethod]; + + FormData* body = m_handle->request().httpBody(); + if (!equalIgnoringCase(originalMethod, "GET") && body && !body->isEmpty()) + WebCore::setHTTPBody(mutableRequest, body); + + String originalContentType = m_handle->request().httpContentType(); + if (!originalContentType.isEmpty()) + [mutableRequest setValue:originalContentType forHTTPHeaderField:@"Content-Type"]; + newRequest = [mutableRequest autorelease]; } } @@ -635,13 +677,13 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen { UNUSED_PARAM(connection); - LOG(Network, "Handle %p delegate connection:%p didReceiveResponse:%p (HTTP status %d, MIMEType '%s', reported MIMEType '%s')", m_handle, connection, r, [r respondsToSelector:@selector(statusCode)] ? [(id)r statusCode] : 0, [[r MIMEType] UTF8String], [[r _webcore_reportedMIMEType] UTF8String]); + LOG(Network, "Handle %p delegate connection:%p didReceiveResponse:%p (HTTP status %d, reported MIMEType '%s')", m_handle, connection, r, [r respondsToSelector:@selector(statusCode)] ? [(id)r statusCode] : 0, [[r MIMEType] UTF8String]); if (!m_handle || !m_handle->client()) return; CallbackGuard guard; - swizzleMIMETypeMethodIfNecessary(); + [r adjustMIMETypeIfNecessary]; if ([m_handle->request().nsURLRequest() _propertyForKey:@"ForceHTMLMIMEType"]) [r _setMIMEType:@"text/html"]; @@ -851,9 +893,11 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen [super dealloc]; } -- (NSURLRequest *)connection:(NSURLConnection *)unusedConnection willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse +- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse { - UNUSED_PARAM(unusedConnection); + UNUSED_PARAM(connection); + + LOG(Network, "WebCoreSynchronousLoader delegate connection:%p willSendRequest:%@ redirectResponse:%p", connection, [newRequest description], redirectResponse); // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests. if (m_url && !protocolHostAndPortAreEqual(m_url, [newRequest URL])) { @@ -882,23 +926,31 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen return newRequest; } -- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)unusedConnection +- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection { - UNUSED_PARAM(unusedConnection); + UNUSED_PARAM(connection); + + LOG(Network, "WebCoreSynchronousLoader delegate connectionShouldUseCredentialStorage:%p", connection); // FIXME: We should ask FrameLoaderClient whether using credential storage is globally forbidden. return m_allowStoredCredentials; } -- (void)connection:(NSURLConnection *)unusedConnection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { - UNUSED_PARAM(unusedConnection); + UNUSED_PARAM(connection); + + LOG(Network, "WebCoreSynchronousLoader delegate connection:%p didReceiveAuthenticationChallenge:%p", connection, challenge); if (m_user && m_pass) { NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:m_user password:m_pass persistence:NSURLCredentialPersistenceNone]; - WebCoreCredentialStorage::set(credential, [challenge protectionSpace]); + KURL urlToStore; + if ([[challenge failureResponse] isKindOfClass:[NSHTTPURLResponse class]] && [(NSHTTPURLResponse*)[challenge failureResponse] statusCode] == 401) + urlToStore = m_url; + CredentialStorage::set(core(credential), core([challenge protectionSpace]), urlToStore); + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; [credential release]; [m_user release]; @@ -908,10 +960,10 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen return; } if ([challenge previousFailureCount] == 0 && m_allowStoredCredentials) { - NSURLCredential *credential = WebCoreCredentialStorage::get([challenge protectionSpace]); - ASSERT([credential persistence] == NSURLCredentialPersistenceNone); - if (credential) { - [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; + Credential credential = CredentialStorage::get(core([challenge protectionSpace])); + if (!credential.isEmpty() && credential != m_initialCredential) { + ASSERT(credential.persistence() == CredentialPersistenceNone); + [[challenge sender] useCredential:mac(credential) forAuthenticationChallenge:challenge]; return; } } @@ -919,9 +971,11 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge]; } -- (void)connection:(NSURLConnection *)unusedConnection didReceiveResponse:(NSURLResponse *)response +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { - UNUSED_PARAM(unusedConnection); + UNUSED_PARAM(connection); + + LOG(Network, "WebCoreSynchronousLoader delegate connection:%p didReceiveResponse:%p (HTTP status %d, reported MIMEType '%s')", connection, response, [response respondsToSelector:@selector(statusCode)] ? [(id)response statusCode] : 0, [[response MIMEType] UTF8String]); NSURLResponse *r = [response copy]; @@ -929,9 +983,11 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen m_response = r; } -- (void)connection:(NSURLConnection *)unusedConnection didReceiveData:(NSData *)data +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { - UNUSED_PARAM(unusedConnection); + UNUSED_PARAM(connection); + + LOG(Network, "WebCoreSynchronousLoader delegate connection:%p didReceiveData:%p", connection, data); if (!m_data) m_data = [[NSMutableData alloc] init]; @@ -939,16 +995,20 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen [m_data appendData:data]; } -- (void)connectionDidFinishLoading:(NSURLConnection *)unusedConnection +- (void)connectionDidFinishLoading:(NSURLConnection *)connection { - UNUSED_PARAM(unusedConnection); + UNUSED_PARAM(connection); + + LOG(Network, "WebCoreSynchronousLoader delegate connectionDidFinishLoading:%p", connection); m_isDone = YES; } -- (void)connection:(NSURLConnection *)unusedConnection didFailWithError:(NSError *)error +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { - UNUSED_PARAM(unusedConnection); + UNUSED_PARAM(connection); + + LOG(Network, "WebCoreSynchronousLoader delegate connection:%p didFailWithError:%@", connection, error); ASSERT(!m_error); @@ -973,23 +1033,36 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen + (NSData *)loadRequest:(NSURLRequest *)request allowStoredCredentials:(BOOL)allowStoredCredentials returningResponse:(NSURLResponse **)response error:(NSError **)error { + LOG(Network, "WebCoreSynchronousLoader loadRequest:%@ allowStoredCredentials:%u", request, allowStoredCredentials); + WebCoreSynchronousLoader *delegate = [[WebCoreSynchronousLoader alloc] init]; - NSURL *url = [request URL]; - delegate->m_user = [[url user] copy]; - delegate->m_pass = [[url password] copy]; + KURL url([request URL]); + delegate->m_user = [nsStringNilIfEmpty(url.user()) retain]; + delegate->m_pass = [nsStringNilIfEmpty(url.pass()) retain]; delegate->m_allowStoredCredentials = allowStoredCredentials; NSURLConnection *connection; // Take user/pass out of the URL. // Credentials for ftp can only be passed in URL, the connection:didReceiveAuthenticationChallenge: delegate call won't be made. - if ((delegate->m_user || delegate->m_pass) && KURL(url).protocolInHTTPFamily()) { + if ((delegate->m_user || delegate->m_pass) && url.protocolInHTTPFamily()) { ResourceRequest requestWithoutCredentials = request; requestWithoutCredentials.removeCredentials(); connection = [[NSURLConnection alloc] initWithRequest:requestWithoutCredentials.nsURLRequest() delegate:delegate startImmediately:NO]; - } else - connection = [[NSURLConnection alloc] initWithRequest:request delegate:delegate startImmediately:NO]; + } else { + // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication, + // try and reuse the credential preemptively, as allowed by RFC 2617. + ResourceRequest requestWithInitialCredentials = request; + if (allowStoredCredentials && url.protocolInHTTPFamily()) + delegate->m_initialCredential = CredentialStorage::getDefaultAuthenticationCredential(url); + + if (!delegate->m_initialCredential.isEmpty()) { + String authHeader = "Basic " + encodeBasicAuthorization(delegate->m_initialCredential.user(), delegate->m_initialCredential.password()); + requestWithInitialCredentials.addHTTPHeaderField("Authorization", authHeader); + } + connection = [[NSURLConnection alloc] initWithRequest:requestWithInitialCredentials.nsURLRequest() delegate:delegate startImmediately:NO]; + } [connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:WebCoreSynchronousLoaderRunLoopMode]; [connection start]; @@ -1005,7 +1078,9 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen [connection release]; [delegate release]; - + + LOG(Network, "WebCoreSynchronousLoader done"); + return data; } diff --git a/WebCore/platform/network/mac/ResourceRequest.h b/WebCore/platform/network/mac/ResourceRequest.h index 5bcb33e..b09e72d 100644 --- a/WebCore/platform/network/mac/ResourceRequest.h +++ b/WebCore/platform/network/mac/ResourceRequest.h @@ -41,7 +41,7 @@ namespace WebCore { class ResourceRequest : public ResourceRequestBase { public: ResourceRequest(const String& url) - : ResourceRequestBase(KURL(url), UseProtocolCachePolicy) + : ResourceRequestBase(KURL(ParsedURLString, url), UseProtocolCachePolicy) { } diff --git a/WebCore/platform/network/mac/ResourceRequestMac.mm b/WebCore/platform/network/mac/ResourceRequestMac.mm index 6bb36a0..c4355b2 100644 --- a/WebCore/platform/network/mac/ResourceRequestMac.mm +++ b/WebCore/platform/network/mac/ResourceRequestMac.mm @@ -61,7 +61,7 @@ void ResourceRequest::doUpdateResourceRequest() if (NSString* method = [m_nsRequest.get() HTTPMethod]) m_httpMethod = method; - m_allowHTTPCookies = [m_nsRequest.get() HTTPShouldHandleCookies]; + m_allowCookies = [m_nsRequest.get() HTTPShouldHandleCookies]; NSDictionary *headers = [m_nsRequest.get() allHTTPHeaderFields]; NSEnumerator *e = [headers keyEnumerator]; @@ -113,7 +113,7 @@ void ResourceRequest::doUpdatePlatformRequest() [nsRequest setMainDocumentURL:firstPartyForCookies()]; if (!httpMethod().isEmpty()) [nsRequest setHTTPMethod:httpMethod()]; - [nsRequest setHTTPShouldHandleCookies:allowHTTPCookies()]; + [nsRequest setHTTPShouldHandleCookies:allowCookies()]; HTTPHeaderMap::const_iterator end = httpHeaderFields().end(); for (HTTPHeaderMap::const_iterator it = httpHeaderFields().begin(); it != end; ++it) diff --git a/WebCore/platform/network/mac/WebCoreURLResponse.h b/WebCore/platform/network/mac/WebCoreURLResponse.h index 0a9a7c4..8d43a21 100644 --- a/WebCore/platform/network/mac/WebCoreURLResponse.h +++ b/WebCore/platform/network/mac/WebCoreURLResponse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,7 +27,9 @@ */ @interface NSURLResponse (WebCoreURLResponse) --(NSString *)_webcore_reportedMIMEType; +-(void)adjustMIMETypeIfNecessary; @end -void swizzleMIMETypeMethodIfNecessary(); +@interface NSURLResponse (Details) +- (void)_setMIMEType:(NSString *)type; +@end diff --git a/WebCore/platform/network/mac/WebCoreURLResponse.mm b/WebCore/platform/network/mac/WebCoreURLResponse.mm index f025769..9be4714 100644 --- a/WebCore/platform/network/mac/WebCoreURLResponse.mm +++ b/WebCore/platform/network/mac/WebCoreURLResponse.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -327,23 +327,6 @@ static NSDictionary *createExtensionToMIMETypeMap() ]; } -static IMP oldNSURLResponseMIMETypeIMP = 0; -static NSString *webNSURLResponseMIMEType(id, SEL); - -void swizzleMIMETypeMethodIfNecessary() -{ - if (!oldNSURLResponseMIMETypeIMP) { - Method nsURLResponseMIMETypeMethod = class_getInstanceMethod([NSURLResponse class], @selector(MIMEType)); - ASSERT(nsURLResponseMIMETypeMethod); -#ifdef BUILDING_ON_TIGER - oldNSURLResponseMIMETypeIMP = nsURLResponseMIMETypeMethod->method_imp; - nsURLResponseMIMETypeMethod->method_imp = (IMP)webNSURLResponseMIMEType; -#else - oldNSURLResponseMIMETypeIMP = method_setImplementation(nsURLResponseMIMETypeMethod, (IMP)webNSURLResponseMIMEType); -#endif - } -} - static NSString *mimeTypeFromUTITree(CFStringRef uti) { // Check if this UTI has a MIME type. @@ -379,10 +362,12 @@ static NSString *mimeTypeFromUTITree(CFStringRef uti) return nil; } -static NSString *webNSURLResponseMIMEType(id self, SEL _cmd) +@implementation NSURLResponse (WebCoreURLResponse) + +-(void)adjustMIMETypeIfNecessary { - ASSERT(oldNSURLResponseMIMETypeIMP); - NSString *result = oldNSURLResponseMIMETypeIMP(self, _cmd); + NSString *result = [self MIMEType]; + NSString *originalResult = result; #ifdef BUILDING_ON_TIGER // When content sniffing is disabled, Tiger's CFNetwork automatically returns application/octet-stream for certain @@ -418,7 +403,7 @@ static NSString *webNSURLResponseMIMEType(id self, SEL _cmd) #ifndef BUILDING_ON_TIGER // <rdar://problem/5321972> Plain text document from HTTP server detected as application/octet-stream // Make the best guess when deciding between "generic binary" and "generic text" using a table of known binary MIME types. - if ([result isEqualToString:@"application/octet-stream"] && [self respondsToSelector:@selector(allHeaderFields)] && [[[self allHeaderFields] objectForKey:@"Content-Type"] hasPrefix:@"text/plain"]) { + if ([result isEqualToString:@"application/octet-stream"] && [self respondsToSelector:@selector(allHeaderFields)] && [[[self performSelector:@selector(allHeaderFields)] objectForKey:@"Content-Type"] hasPrefix:@"text/plain"]) { static NSSet *binaryExtensions = createBinaryExtensionsSet(); if (![binaryExtensions containsObject:[[[self suggestedFilename] pathExtension] lowercaseString]]) result = @"text/plain"; @@ -432,15 +417,8 @@ static NSString *webNSURLResponseMIMEType(id self, SEL _cmd) result = @"application/xml"; #endif - return result; -} - -@implementation NSURLResponse (WebCoreURLResponse) - --(NSString *)_webcore_reportedMIMEType -{ - swizzleMIMETypeMethodIfNecessary(); - return oldNSURLResponseMIMETypeIMP(self, @selector(_webcore_realMIMEType)); + if (result != originalResult) + [self _setMIMEType:result]; } @end diff --git a/WebCore/platform/network/qt/DnsPrefetchHelper.cpp b/WebCore/platform/network/qt/DnsPrefetchHelper.cpp new file mode 100644 index 0000000..e687976 --- /dev/null +++ b/WebCore/platform/network/qt/DnsPrefetchHelper.cpp @@ -0,0 +1,35 @@ +/* + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "DnsPrefetchHelper.h" + +#include "CString.h" + +namespace WebCore { +// this is called on mouse over a href and on page loading +void prefetchDNS(const String& hostname) +{ + if (QWebSettings::globalSettings()->testAttribute(QWebSettings::DnsPrefetchEnabled)) { + static DnsPrefetchHelper dnsPrefetchHelper; + dnsPrefetchHelper.lookup(QString(hostname)); + } +} + +} diff --git a/WebCore/platform/network/qt/DnsPrefetchHelper.h b/WebCore/platform/network/qt/DnsPrefetchHelper.h new file mode 100644 index 0000000..0d98fcb --- /dev/null +++ b/WebCore/platform/network/qt/DnsPrefetchHelper.h @@ -0,0 +1,75 @@ +/* + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef DNSPREFETCHHELPER_H +#define DNSPREFETCHHELPER_H + +#include <QObject> +#include <QCache> +#include <QHostInfo> +#include <QSet> +#include <QString> +#include <QTime> +#include "qwebsettings.h" + +namespace WebCore { + + class DnsPrefetchHelper : public QObject { + Q_OBJECT + public: + DnsPrefetchHelper() : QObject(), currentLookups(0) {}; + + public slots: + void lookup(QString hostname) + { + if (hostname.isEmpty()) + return; // this actually happens + if (currentLookups >= 10) + return; // do not launch more than 10 lookups at the same time + + QTime* entryTime = lookupCache.object(hostname); + if (entryTime && entryTime->elapsed() > 300*1000) { + // delete knowledge about lookup if it is already 300 seconds old + lookupCache.remove(hostname); + } else if (!entryTime) { + // not in cache yet, can look it up + QTime *tmpTime = new QTime(); + *tmpTime = QTime::currentTime(); + lookupCache.insert(hostname, tmpTime); + currentLookups++; + QHostInfo::lookupHost(hostname, this, SLOT(lookedUp(QHostInfo))); + } + } + + void lookedUp(const QHostInfo&) + { + // we do not cache the result, we throw it away. + // we currently rely on the OS to cache the results. If it does not do that + // then at least the ISP nameserver did it. + currentLookups--; + } + + protected: + QCache<QString, QTime> lookupCache; // 100 entries + int currentLookups; + }; + + +} + +#endif // DNSPREFETCHHELPER_H diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp index 898e5f4..7a3703d 100644 --- a/WebCore/platform/network/qt/QNetworkReplyHandler.cpp +++ b/WebCore/platform/network/qt/QNetworkReplyHandler.cpp @@ -131,10 +131,11 @@ void FormDataIODevice::slotFinished() QNetworkReplyHandler::QNetworkReplyHandler(ResourceHandle* handle, LoadMode loadMode) : QObject(0) - , m_resourceHandle(handle) , m_reply(0) + , m_resourceHandle(handle) , m_redirected(false) , m_responseSent(false) + , m_responseDataSent(false) , m_loadMode(loadMode) , m_shouldStart(true) , m_shouldFinish(false) @@ -204,6 +205,19 @@ QNetworkReply* QNetworkReplyHandler::release() return reply; } +static bool ignoreHttpError(QNetworkReply* reply, bool receivedData) +{ + int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (httpStatusCode == 401 || httpStatusCode == 407) + return true; + + if (receivedData && (httpStatusCode >= 400 && httpStatusCode < 600)) + return true; + + return false; +} + void QNetworkReplyHandler::finish() { m_shouldFinish = (m_loadMode != LoadNormal); @@ -220,23 +234,27 @@ void QNetworkReplyHandler::finish() m_reply = 0; return; } + QNetworkReply* oldReply = m_reply; + if (m_redirected) { resetState(); start(); - } else if (m_reply->error() != QNetworkReply::NoError - // a web page that returns 401/403/404 can still have content - && m_reply->error() != QNetworkReply::ContentOperationNotPermittedError - && m_reply->error() != QNetworkReply::ContentNotFoundError - && m_reply->error() != QNetworkReply::AuthenticationRequiredError - && m_reply->error() != QNetworkReply::ProxyAuthenticationRequiredError) { - QUrl url = m_reply->url(); - ResourceError error(url.host(), m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), - url.toString(), m_reply->errorString()); - client->didFail(m_resourceHandle, error); - } else { + } else if (!m_reply->error() || ignoreHttpError(m_reply, m_responseDataSent)) { client->didFinishLoading(m_resourceHandle); + } else { + QUrl url = m_reply->url(); + int httpStatusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (httpStatusCode) { + ResourceError error("HTTP", httpStatusCode, url.toString(), m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString()); + client->didFail(m_resourceHandle, error); + } else { + ResourceError error("QtNetwork", m_reply->error(), url.toString(), m_reply->errorString()); + client->didFail(m_resourceHandle, error); + } } + oldReply->deleteLater(); if (oldReply == m_reply) m_reply = 0; @@ -248,6 +266,9 @@ void QNetworkReplyHandler::sendResponseIfNeeded() if (m_shouldSendResponse) return; + if (m_reply->error()) + return; + if (m_responseSent || !m_resourceHandle) return; m_responseSent = true; @@ -271,41 +292,34 @@ void QNetworkReplyHandler::sendResponseIfNeeded() } KURL url(m_reply->url()); - String suggestedFilename = filenameFromHTTPContentDisposition(QString::fromAscii(m_reply->rawHeader("Content-Disposition"))); - - if (suggestedFilename.isEmpty()) - suggestedFilename = url.lastPathComponent(); - ResourceResponse response(url, mimeType, m_reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), - encoding, - suggestedFilename); + encoding, String()); - const bool isLocalFileReply = (m_reply->url().scheme() == QLatin1String("file")); - int statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - if (!isLocalFileReply) { - response.setHTTPStatusCode(statusCode); - response.setHTTPStatusText(m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray().constData()); + if (url.isLocalFile()) { + client->didReceiveResponse(m_resourceHandle, response); + return; } - else if (m_reply->error() == QNetworkReply::ContentNotFoundError) - response.setHTTPStatusCode(404); + // The status code is equal to 0 for protocols not in the HTTP family. + int statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - /* Fill in the other fields - * For local file requests remove the content length and the last-modified - * headers as required by fast/dom/xmlhttprequest-get.xhtml - */ - foreach (QByteArray headerName, m_reply->rawHeaderList()) { + if (url.protocolInHTTPFamily()) { + String suggestedFilename = filenameFromHTTPContentDisposition(QString::fromAscii(m_reply->rawHeader("Content-Disposition"))); - if (isLocalFileReply - && (headerName == "Content-Length" || headerName == "Last-Modified")) - continue; + if (!suggestedFilename.isEmpty()) + response.setSuggestedFilename(suggestedFilename); + else + response.setSuggestedFilename(url.lastPathComponent()); - response.setHTTPHeaderField(QString::fromAscii(headerName), QString::fromAscii(m_reply->rawHeader(headerName))); - } + response.setHTTPStatusCode(statusCode); + response.setHTTPStatusText(m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray().constData()); - if (isLocalFileReply) - response.setHTTPHeaderField(QString::fromAscii("Cache-Control"), QString::fromAscii("no-cache")); + // Add remaining headers. + foreach (const QByteArray& headerName, m_reply->rawHeaderList()) { + response.setHTTPHeaderField(QString::fromAscii(headerName), QString::fromAscii(m_reply->rawHeader(headerName))); + } + } QUrl redirection = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); if (redirection.isValid()) { @@ -321,9 +335,13 @@ void QNetworkReplyHandler::sendResponseIfNeeded() client->willSendRequest(m_resourceHandle, newRequest, response); m_redirected = true; m_request = newRequest.toNetworkRequest(); - } else { - client->didReceiveResponse(m_resourceHandle, response); + + ResourceHandleInternal* d = m_resourceHandle->getInternal(); + emit d->m_frame->page()->networkRequestStarted(d->m_frame, &m_request); + return; } + + client->didReceiveResponse(m_resourceHandle, response); } void QNetworkReplyHandler::forwardData() @@ -347,8 +365,10 @@ void QNetworkReplyHandler::forwardData() if (!client) return; - if (!data.isEmpty()) + if (!data.isEmpty()) { + m_responseDataSent = true; client->didReceiveData(m_resourceHandle, data.constData(), data.length(), data.length() /*FixMe*/); + } } void QNetworkReplyHandler::start() @@ -359,6 +379,8 @@ void QNetworkReplyHandler::start() QNetworkAccessManager* manager = d->m_frame->page()->networkAccessManager(); + emit d->m_frame->page()->networkRequestStarted(d->m_frame, &m_request); + const QUrl url = m_request.url(); const QString scheme = url.scheme(); // Post requests on files and data don't really make sense, but for @@ -421,6 +443,7 @@ void QNetworkReplyHandler::resetState() { m_redirected = false; m_responseSent = false; + m_responseDataSent = false; m_shouldStart = true; m_shouldFinish = false; m_shouldSendResponse = false; diff --git a/WebCore/platform/network/qt/QNetworkReplyHandler.h b/WebCore/platform/network/qt/QNetworkReplyHandler.h index f88ce8a..545119e 100644 --- a/WebCore/platform/network/qt/QNetworkReplyHandler.h +++ b/WebCore/platform/network/qt/QNetworkReplyHandler.h @@ -73,6 +73,7 @@ private: ResourceHandle* m_resourceHandle; bool m_redirected; bool m_responseSent; + bool m_responseDataSent; LoadMode m_loadMode; QNetworkAccessManager::Operation m_method; QNetworkRequest m_request; diff --git a/WebCore/platform/network/qt/ResourceRequest.h b/WebCore/platform/network/qt/ResourceRequest.h index af76f61..93dacf3 100644 --- a/WebCore/platform/network/qt/ResourceRequest.h +++ b/WebCore/platform/network/qt/ResourceRequest.h @@ -38,7 +38,7 @@ namespace WebCore { struct ResourceRequest : ResourceRequestBase { ResourceRequest(const String& url) - : ResourceRequestBase(KURL(url), UseProtocolCachePolicy) + : ResourceRequestBase(KURL(ParsedURLString, url), UseProtocolCachePolicy) { } diff --git a/WebCore/platform/network/qt/SocketStreamError.h b/WebCore/platform/network/qt/SocketStreamError.h new file mode 100644 index 0000000..f9641ad --- /dev/null +++ b/WebCore/platform/network/qt/SocketStreamError.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER 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 SocketStreamError_h +#define SocketStreamError_h + +#include "SocketStreamErrorBase.h" + +namespace WebCore { + + class SocketStreamError : public SocketStreamErrorBase { + public: + SocketStreamError() { } + explicit SocketStreamError(int errorCode) + : SocketStreamErrorBase(errorCode) + { + } + + }; + +} // namespace WebCore + +#endif // SocketStreamError_h diff --git a/WebCore/platform/network/qt/SocketStreamHandle.h b/WebCore/platform/network/qt/SocketStreamHandle.h new file mode 100644 index 0000000..64139e5 --- /dev/null +++ b/WebCore/platform/network/qt/SocketStreamHandle.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER 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 SocketStreamHandle_h +#define SocketStreamHandle_h + +#include "SocketStreamHandleBase.h" + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + + class AuthenticationChallenge; + class Credential; + class SocketStreamHandleClient; + + class SocketStreamHandle : public RefCounted<SocketStreamHandle>, public SocketStreamHandleBase { + public: + static PassRefPtr<SocketStreamHandle> create(const KURL& url, SocketStreamHandleClient* client) { return adoptRef(new SocketStreamHandle(url, client)); } + + virtual ~SocketStreamHandle(); + + protected: + virtual int platformSend(const char* data, int length); + virtual void platformClose(); + + private: + SocketStreamHandle(const KURL&, SocketStreamHandleClient*); + + // No authentication for streams per se, but proxy may ask for credentials. + void didReceiveAuthenticationChallenge(const AuthenticationChallenge&); + void receivedCredential(const AuthenticationChallenge&, const Credential&); + void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&); + void receivedCancellation(const AuthenticationChallenge&); + }; + +} // namespace WebCore + +#endif // SocketStreamHandle_h diff --git a/WebCore/platform/network/qt/SocketStreamHandleSoup.cpp b/WebCore/platform/network/qt/SocketStreamHandleSoup.cpp new file mode 100644 index 0000000..6aa33fc --- /dev/null +++ b/WebCore/platform/network/qt/SocketStreamHandleSoup.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER 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 "SocketStreamHandle.h" + +#include "KURL.h" +#include "Logging.h" +#include "NotImplemented.h" +#include "SocketStreamHandleClient.h" + +namespace WebCore { + +SocketStreamHandle::SocketStreamHandle(const KURL& url, SocketStreamHandleClient* client) + : SocketStreamHandleBase(url, client) +{ + LOG(Network, "SocketStreamHandle %p new client %p", this, m_client); + notImplemented(); +} + +SocketStreamHandle::~SocketStreamHandle() +{ + LOG(Network, "SocketStreamHandle %p delete", this); + setClient(0); + notImplemented(); +} + +int SocketStreamHandle::platformSend(const char*, int) +{ + LOG(Network, "SocketStreamHandle %p platformSend", this); + notImplemented(); + return 0; +} + +void SocketStreamHandle::platformClose() +{ + LOG(Network, "SocketStreamHandle %p platformClose", this); + notImplemented(); +} + +void SocketStreamHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge&) +{ + notImplemented(); +} + +void SocketStreamHandle::receivedCredential(const AuthenticationChallenge&, const Credential&) +{ + notImplemented(); +} + +void SocketStreamHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&) +{ + notImplemented(); +} + +void SocketStreamHandle::receivedCancellation(const AuthenticationChallenge&) +{ + notImplemented(); +} + +} // namespace WebCore diff --git a/WebCore/platform/network/soup/CookieJarSoup.cpp b/WebCore/platform/network/soup/CookieJarSoup.cpp index 705fdf2..3eb578a 100644 --- a/WebCore/platform/network/soup/CookieJarSoup.cpp +++ b/WebCore/platform/network/soup/CookieJarSoup.cpp @@ -21,6 +21,7 @@ #include "config.h" #include "CookieJarSoup.h" +#include "Cookie.h" #include "CString.h" #include "Document.h" #include "KURL.h" @@ -86,4 +87,16 @@ bool cookiesEnabled(const Document* /*document*/) return defaultCookieJar(); } +bool getRawCookies(const Document*, const KURL&, Vector<Cookie>& rawCookies) +{ + // FIXME: Not yet implemented + rawCookies.clear(); + return false; // return true when implemented +} + +void deleteCookie(const Document*, const KURL&, const String&) +{ + // FIXME: Not yet implemented +} + } diff --git a/WebCore/platform/network/soup/ResourceHandleSoup.cpp b/WebCore/platform/network/soup/ResourceHandleSoup.cpp index 4a22d8a..2177bd2 100644 --- a/WebCore/platform/network/soup/ResourceHandleSoup.cpp +++ b/WebCore/platform/network/soup/ResourceHandleSoup.cpp @@ -118,7 +118,7 @@ void WebCoreSynchronousLoader::run() g_main_loop_run(m_mainLoop); } -static void cleanupGioOperation(ResourceHandleInternal* handle); +static void cleanupGioOperation(ResourceHandle* handle, bool isDestroying); static bool startData(ResourceHandle* handle, String urlString); static bool startGio(ResourceHandle* handle, KURL url); @@ -129,8 +129,6 @@ ResourceHandleInternal::~ResourceHandleInternal() m_msg = 0; } - cleanupGioOperation(this); - if (m_idleHandler) { g_source_remove(m_idleHandler); m_idleHandler = 0; @@ -142,6 +140,21 @@ ResourceHandle::~ResourceHandle() if (d->m_msg) g_signal_handlers_disconnect_matched(d->m_msg, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this); + + cleanupGioOperation(this, true); +} + +// All other kinds of redirections, except for the *304* status code +// (SOUP_STATUS_NOT_MODIFIED) which needs to be fed into WebCore, will be +// handled by soup directly. +static gboolean statusWillBeHandledBySoup(guint statusCode) +{ + if (SOUP_STATUS_IS_TRANSPORT_ERROR(statusCode) + || (SOUP_STATUS_IS_REDIRECTION(statusCode) && (statusCode != SOUP_STATUS_NOT_MODIFIED)) + || (statusCode == SOUP_STATUS_UNAUTHORIZED)) + return true; + + return false; } static void fillResponseFromMessage(SoupMessage* msg, ResourceResponse* response) @@ -185,6 +198,7 @@ static void restartedCallback(SoupMessage* msg, gpointer data) ResourceRequest request = handle->request(); ResourceResponse response; request.setURL(newURL); + request.setHTTPMethod(msg->method); fillResponseFromMessage(msg, &response); if (d->client()) d->client()->willSendRequest(handle, request, response); @@ -204,22 +218,25 @@ static void gotHeadersCallback(SoupMessage* msg, gpointer data) // we got, when we finish downloading. soup_message_body_set_accumulate(msg->response_body, FALSE); - if (msg->status_code == SOUP_STATUS_NOT_MODIFIED) { - RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data); - if (!handle) - return; - ResourceHandleInternal* d = handle->getInternal(); - if (d->m_cancelled) - return; - ResourceHandleClient* client = handle->client(); - if (!client) - return; + RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data); - fillResponseFromMessage(msg, &d->m_response); - client->didReceiveResponse(handle.get(), d->m_response); - } + // The content-sniffed callback will handle the response if WebCore + // require us to sniff. + if(!handle || statusWillBeHandledBySoup(msg->status_code) || handle->shouldContentSniff()) + return; + + ResourceHandleInternal* d = handle->getInternal(); + if (d->m_cancelled) + return; + ResourceHandleClient* client = handle->client(); + if (!client) + return; + + fillResponseFromMessage(msg, &d->m_response); + client->didReceiveResponse(handle.get(), d->m_response); } +// This callback will not be called if the content sniffer is disabled in startHttp. static void contentSniffedCallback(SoupMessage* msg, const char* sniffedType, GHashTable *params, gpointer data) { if (sniffedType) { @@ -229,13 +246,7 @@ static void contentSniffedCallback(SoupMessage* msg, const char* sniffedType, GH soup_message_headers_set_content_type(msg->response_headers, sniffedType, params); } - // The 304 status code (SOUP_STATUS_NOT_MODIFIED) needs to be fed - // into WebCore, as opposed to other kinds of redirections, which - // are handled by soup directly, so we special-case it here and in - // gotChunk. - if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code) - || (SOUP_STATUS_IS_REDIRECTION(msg->status_code) && (msg->status_code != SOUP_STATUS_NOT_MODIFIED)) - || (msg->status_code == SOUP_STATUS_UNAUTHORIZED)) + if (statusWillBeHandledBySoup(msg->status_code)) return; RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data); @@ -254,9 +265,7 @@ static void contentSniffedCallback(SoupMessage* msg, const char* sniffedType, GH static void gotChunkCallback(SoupMessage* msg, SoupBuffer* chunk, gpointer data) { - if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code) - || (SOUP_STATUS_IS_REDIRECTION(msg->status_code) && (msg->status_code != SOUP_STATUS_NOT_MODIFIED)) - || (msg->status_code == SOUP_STATUS_UNAUTHORIZED)) + if (statusWillBeHandledBySoup(msg->status_code)) return; RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data); @@ -276,7 +285,7 @@ static void gotChunkCallback(SoupMessage* msg, SoupBuffer* chunk, gpointer data) // Doesn't get called for redirects. static void finishedCallback(SoupSession *session, SoupMessage* msg, gpointer data) { - RefPtr<ResourceHandle>handle = adoptRef(static_cast<ResourceHandle*>(data)); + RefPtr<ResourceHandle> handle = adoptRef(static_cast<ResourceHandle*>(data)); // TODO: maybe we should run this code even if there's no client? if (!handle) return; @@ -410,6 +419,13 @@ static SoupSession* createSoupSession() return soup_session_async_new(); } +// Values taken from http://stevesouders.com/ua/index.php following +// the rule "Do What Every Other Modern Browser Is Doing". They seem +// to significantly improve page loading time compared to soup's +// default values. +#define MAX_CONNECTIONS 60 +#define MAX_CONNECTIONS_PER_HOST 6 + static void ensureSessionIsInitialized(SoupSession* session) { if (g_object_get_data(G_OBJECT(session), "webkit-init")) @@ -427,27 +443,34 @@ static void ensureSessionIsInitialized(SoupSession* session) g_object_unref(logger); } + g_object_set(session, + SOUP_SESSION_MAX_CONNS, MAX_CONNECTIONS, + SOUP_SESSION_MAX_CONNS_PER_HOST, MAX_CONNECTIONS_PER_HOST, + NULL); + g_object_set_data(G_OBJECT(session), "webkit-init", reinterpret_cast<void*>(0xdeadbeef)); } -static bool startHttp(ResourceHandle* handle, String urlString) +static bool startHttp(ResourceHandle* handle) { ASSERT(handle); - + SoupSession* session = handle->defaultSession(); ensureSessionIsInitialized(session); ResourceHandleInternal* d = handle->getInternal(); - d->m_msg = handle->request().toSoupMessage(); - if (!d->m_msg) { - ResourceError resourceError(g_quark_to_string(SOUP_HTTP_ERROR), - SOUP_STATUS_MALFORMED, - urlString, - handle->request().httpMethod()); - d->client()->didFail(handle, resourceError); + ResourceRequest request(handle->request()); + KURL url(request.url()); + url.removeFragmentIdentifier(); + request.setURL(url); + + d->m_msg = request.toSoupMessage(); + if (!d->m_msg) return false; - } + + if(!handle->shouldContentSniff()) + soup_message_disable_feature(d->m_msg, SOUP_TYPE_CONTENT_SNIFFER); g_signal_connect(d->m_msg, "restarted", G_CALLBACK(restartedCallback), handle); g_signal_connect(d->m_msg, "got-headers", G_CALLBACK(gotHeadersCallback), handle); @@ -491,14 +514,7 @@ static bool startHttp(ResourceHandle* handle, String urlString) g_free(fileName); if (error) { - ResourceError resourceError(g_quark_to_string(SOUP_HTTP_ERROR), - d->m_msg->status_code, - urlString, - String::fromUTF8(error->message)); g_error_free(error); - - d->client()->didFail(handle, resourceError); - g_signal_handlers_disconnect_matched(d->m_msg, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, handle); g_object_unref(d->m_msg); @@ -562,12 +578,16 @@ bool ResourceHandle::start(Frame* frame) if (equalIgnoringCase(protocol, "data")) return startData(this, urlString); - if (equalIgnoringCase(protocol, "http") || equalIgnoringCase(protocol, "https")) - return startHttp(this, urlString); + if (equalIgnoringCase(protocol, "http") || equalIgnoringCase(protocol, "https")) { + if (startHttp(this)) + return true; + } - if (equalIgnoringCase(protocol, "file") || equalIgnoringCase(protocol, "ftp") || equalIgnoringCase(protocol, "ftps")) + if (equalIgnoringCase(protocol, "file") || equalIgnoringCase(protocol, "ftp") || equalIgnoringCase(protocol, "ftps")) { // FIXME: should we be doing any other protocols here? - return startGio(this, url); + if (startGio(this, url)) + return true; + } // Error must not be reported immediately this->scheduleFailure(InvalidURLFailure); @@ -625,8 +645,10 @@ void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, S // GIO-based loader -static void cleanupGioOperation(ResourceHandleInternal* d) +static void cleanupGioOperation(ResourceHandle* handle, bool isDestroying = false) { + ResourceHandleInternal* d = handle->getInternal(); + if (d->m_gfile) { g_object_set_data(G_OBJECT(d->m_gfile), "webkit-resource", 0); g_object_unref(d->m_gfile); @@ -648,11 +670,14 @@ static void cleanupGioOperation(ResourceHandleInternal* d) g_free(d->m_buffer); d->m_buffer = 0; } + + if (!isDestroying) + handle->deref(); } static void closeCallback(GObject* source, GAsyncResult* res, gpointer) { - ResourceHandle* handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource")); + RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource")); if (!handle) return; @@ -660,13 +685,12 @@ static void closeCallback(GObject* source, GAsyncResult* res, gpointer) ResourceHandleClient* client = handle->client(); g_input_stream_close_finish(d->m_inputStream, res, 0); - cleanupGioOperation(d); - client->didFinishLoading(handle); + cleanupGioOperation(handle.get()); + client->didFinishLoading(handle.get()); } static void readCallback(GObject* source, GAsyncResult* res, gpointer) { - // didReceiveData may cancel the load, which may release the last reference. RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource")); if (!handle) return; @@ -675,7 +699,7 @@ static void readCallback(GObject* source, GAsyncResult* res, gpointer) ResourceHandleClient* client = handle->client(); if (d->m_cancelled || !client) { - cleanupGioOperation(d); + cleanupGioOperation(handle.get()); return; } @@ -690,7 +714,7 @@ static void readCallback(GObject* source, GAsyncResult* res, gpointer) error ? String::fromUTF8(error->message) : String()); g_free(uri); g_error_free(error); - cleanupGioOperation(d); + cleanupGioOperation(handle.get()); client->didFail(handle.get(), resourceError); return; } @@ -704,8 +728,9 @@ static void readCallback(GObject* source, GAsyncResult* res, gpointer) d->m_total += bytesRead; client->didReceiveData(handle.get(), d->m_buffer, bytesRead, d->m_total); + // didReceiveData may cancel the load, which may release the last reference. if (d->m_cancelled) { - cleanupGioOperation(d); + cleanupGioOperation(handle.get()); return; } @@ -716,7 +741,7 @@ static void readCallback(GObject* source, GAsyncResult* res, gpointer) static void openCallback(GObject* source, GAsyncResult* res, gpointer) { - ResourceHandle* handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource")); + RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource")); if (!handle) return; @@ -724,7 +749,7 @@ static void openCallback(GObject* source, GAsyncResult* res, gpointer) ResourceHandleClient* client = handle->client(); if (d->m_cancelled || !client) { - cleanupGioOperation(d); + cleanupGioOperation(handle.get()); return; } @@ -738,8 +763,8 @@ static void openCallback(GObject* source, GAsyncResult* res, gpointer) error ? String::fromUTF8(error->message) : String()); g_free(uri); g_error_free(error); - cleanupGioOperation(d); - client->didFail(handle, resourceError); + cleanupGioOperation(handle.get()); + client->didFail(handle.get(), resourceError); return; } @@ -747,7 +772,8 @@ static void openCallback(GObject* source, GAsyncResult* res, gpointer) d->m_bufferSize = 8192; d->m_buffer = static_cast<char*>(g_malloc(d->m_bufferSize)); d->m_total = 0; - g_object_set_data(G_OBJECT(d->m_inputStream), "webkit-resource", handle); + + g_object_set_data(G_OBJECT(d->m_inputStream), "webkit-resource", handle.get()); g_input_stream_read_async(d->m_inputStream, d->m_buffer, d->m_bufferSize, G_PRIORITY_DEFAULT, d->m_cancellable, readCallback, 0); @@ -755,7 +781,7 @@ static void openCallback(GObject* source, GAsyncResult* res, gpointer) static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer) { - ResourceHandle* handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource")); + RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource")); if (!handle) return; @@ -763,7 +789,7 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer) ResourceHandleClient* client = handle->client(); if (d->m_cancelled) { - cleanupGioOperation(d); + cleanupGioOperation(handle.get()); return; } @@ -790,8 +816,8 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer) error ? String::fromUTF8(error->message) : String()); g_free(uri); g_error_free(error); - cleanupGioOperation(d); - client->didFail(handle, resourceError); + cleanupGioOperation(handle.get()); + client->didFail(handle.get(), resourceError); return; } @@ -804,8 +830,8 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer) uri, String()); g_free(uri); - cleanupGioOperation(d); - client->didFail(handle, resourceError); + cleanupGioOperation(handle.get()); + client->didFail(handle.get(), resourceError); return; } @@ -816,7 +842,12 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer) g_file_info_get_modification_time(info, &tv); response.setLastModifiedDate(tv.tv_sec); - client->didReceiveResponse(handle, response); + client->didReceiveResponse(handle.get(), response); + + if (d->m_cancelled) { + cleanupGioOperation(handle.get()); + return; + } g_file_read_async(d->m_gfile, G_PRIORITY_DEFAULT, d->m_cancellable, openCallback, 0); @@ -827,13 +858,8 @@ static bool startGio(ResourceHandle* handle, KURL url) ResourceHandleInternal* d = handle->getInternal(); - if (handle->request().httpMethod() != "GET" && handle->request().httpMethod() != "POST") { - ResourceError error(g_quark_to_string(SOUP_HTTP_ERROR), - SOUP_STATUS_METHOD_NOT_ALLOWED, - url.string(), handle->request().httpMethod()); - d->client()->didFail(handle, error); + if (handle->request().httpMethod() != "GET" && handle->request().httpMethod() != "POST") return false; - } // GIO doesn't know how to handle refs and queries, so remove them // TODO: use KURL.fileSystemPath after KURLGtk and FileSystemGtk are @@ -852,6 +878,10 @@ static bool startGio(ResourceHandle* handle, KURL url) #endif d->m_gfile = g_file_new_for_uri(url.string().utf8().data()); g_object_set_data(G_OBJECT(d->m_gfile), "webkit-resource", handle); + + // balanced by a deref() in cleanupGioOperation, which should always run + handle->ref(); + d->m_cancellable = g_cancellable_new(); g_file_query_info_async(d->m_gfile, G_FILE_ATTRIBUTE_STANDARD_TYPE "," diff --git a/WebCore/platform/network/soup/ResourceRequest.h b/WebCore/platform/network/soup/ResourceRequest.h index 82b4eb9..42b7baa 100644 --- a/WebCore/platform/network/soup/ResourceRequest.h +++ b/WebCore/platform/network/soup/ResourceRequest.h @@ -36,7 +36,7 @@ namespace WebCore { struct ResourceRequest : ResourceRequestBase { ResourceRequest(const String& url) - : ResourceRequestBase(KURL(url), UseProtocolCachePolicy) + : ResourceRequestBase(KURL(ParsedURLString, url), UseProtocolCachePolicy) { } diff --git a/WebCore/platform/network/soup/ResourceRequestSoup.cpp b/WebCore/platform/network/soup/ResourceRequestSoup.cpp index f2011bb..0d4e0f9 100644 --- a/WebCore/platform/network/soup/ResourceRequestSoup.cpp +++ b/WebCore/platform/network/soup/ResourceRequestSoup.cpp @@ -66,11 +66,20 @@ void ResourceRequest::updateFromSoupMessage(SoupMessage* soupMessage) while (soup_message_headers_iter_next(&headersIter, &headerName, &headerValue)) m_httpHeaderFields.set(String::fromUTF8(headerName), String::fromUTF8(headerValue)); - m_httpBody = FormData::create(soupMessage->request_body->data, soupMessage->request_body->length); + if (soupMessage->request_body->data) + m_httpBody = FormData::create(soupMessage->request_body->data, soupMessage->request_body->length); - // FIXME: m_allowHTTPCookies and m_firstPartyForCookies should + // FIXME: m_allowCookies and m_firstPartyForCookies should // probably be handled here and on doUpdatePlatformRequest // somehow. } +unsigned initializeMaximumHTTPConnectionCountPerHost() +{ + // Soup has its own queue control; it wants to have all requests + // given to it, so that it is able to look ahead, and schedule + // them in a good way. + return 10000; +} + } diff --git a/WebCore/platform/network/soup/ResourceResponse.h b/WebCore/platform/network/soup/ResourceResponse.h index b8cb586..5fa31a0 100644 --- a/WebCore/platform/network/soup/ResourceResponse.h +++ b/WebCore/platform/network/soup/ResourceResponse.h @@ -28,6 +28,8 @@ #include "ResourceResponseBase.h" +#include <libsoup/soup.h> + namespace WebCore { class ResourceResponse : public ResourceResponseBase { @@ -42,6 +44,8 @@ public: { } + SoupMessage* toSoupMessage() const; + private: friend class ResourceResponseBase; diff --git a/WebCore/platform/network/soup/ResourceResponseSoup.cpp b/WebCore/platform/network/soup/ResourceResponseSoup.cpp new file mode 100644 index 0000000..293577f --- /dev/null +++ b/WebCore/platform/network/soup/ResourceResponseSoup.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2009 Gustavo Noronha Silva + * Copyright (C) 2009 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; 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 "ResourceResponse.h" + +#include "CString.h" +#include "PlatformString.h" + +using namespace std; + +namespace WebCore { + +SoupMessage* ResourceResponse::toSoupMessage() const +{ + // This GET here is just because SoupMessage wants it, we dn't really know. + SoupMessage* soupMessage = soup_message_new("GET", url().string().utf8().data()); + if (!soupMessage) + return 0; + + soupMessage->status_code = httpStatusCode(); + + HTTPHeaderMap headers = httpHeaderFields(); + SoupMessageHeaders* soupHeaders = soupMessage->response_headers; + if (!headers.isEmpty()) { + HTTPHeaderMap::const_iterator end = headers.end(); + for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it) + soup_message_headers_append(soupHeaders, it->first.string().utf8().data(), it->second.utf8().data()); + } + + // Body data is not in the message. + return soupMessage; +} + +} diff --git a/WebCore/platform/network/soup/SocketStreamError.h b/WebCore/platform/network/soup/SocketStreamError.h new file mode 100644 index 0000000..f9641ad --- /dev/null +++ b/WebCore/platform/network/soup/SocketStreamError.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER 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 SocketStreamError_h +#define SocketStreamError_h + +#include "SocketStreamErrorBase.h" + +namespace WebCore { + + class SocketStreamError : public SocketStreamErrorBase { + public: + SocketStreamError() { } + explicit SocketStreamError(int errorCode) + : SocketStreamErrorBase(errorCode) + { + } + + }; + +} // namespace WebCore + +#endif // SocketStreamError_h diff --git a/WebCore/platform/network/soup/SocketStreamHandle.h b/WebCore/platform/network/soup/SocketStreamHandle.h new file mode 100644 index 0000000..64139e5 --- /dev/null +++ b/WebCore/platform/network/soup/SocketStreamHandle.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER 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 SocketStreamHandle_h +#define SocketStreamHandle_h + +#include "SocketStreamHandleBase.h" + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + + class AuthenticationChallenge; + class Credential; + class SocketStreamHandleClient; + + class SocketStreamHandle : public RefCounted<SocketStreamHandle>, public SocketStreamHandleBase { + public: + static PassRefPtr<SocketStreamHandle> create(const KURL& url, SocketStreamHandleClient* client) { return adoptRef(new SocketStreamHandle(url, client)); } + + virtual ~SocketStreamHandle(); + + protected: + virtual int platformSend(const char* data, int length); + virtual void platformClose(); + + private: + SocketStreamHandle(const KURL&, SocketStreamHandleClient*); + + // No authentication for streams per se, but proxy may ask for credentials. + void didReceiveAuthenticationChallenge(const AuthenticationChallenge&); + void receivedCredential(const AuthenticationChallenge&, const Credential&); + void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&); + void receivedCancellation(const AuthenticationChallenge&); + }; + +} // namespace WebCore + +#endif // SocketStreamHandle_h diff --git a/WebCore/platform/network/soup/SocketStreamHandleSoup.cpp b/WebCore/platform/network/soup/SocketStreamHandleSoup.cpp new file mode 100644 index 0000000..6aa33fc --- /dev/null +++ b/WebCore/platform/network/soup/SocketStreamHandleSoup.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER 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 "SocketStreamHandle.h" + +#include "KURL.h" +#include "Logging.h" +#include "NotImplemented.h" +#include "SocketStreamHandleClient.h" + +namespace WebCore { + +SocketStreamHandle::SocketStreamHandle(const KURL& url, SocketStreamHandleClient* client) + : SocketStreamHandleBase(url, client) +{ + LOG(Network, "SocketStreamHandle %p new client %p", this, m_client); + notImplemented(); +} + +SocketStreamHandle::~SocketStreamHandle() +{ + LOG(Network, "SocketStreamHandle %p delete", this); + setClient(0); + notImplemented(); +} + +int SocketStreamHandle::platformSend(const char*, int) +{ + LOG(Network, "SocketStreamHandle %p platformSend", this); + notImplemented(); + return 0; +} + +void SocketStreamHandle::platformClose() +{ + LOG(Network, "SocketStreamHandle %p platformClose", this); + notImplemented(); +} + +void SocketStreamHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge&) +{ + notImplemented(); +} + +void SocketStreamHandle::receivedCredential(const AuthenticationChallenge&, const Credential&) +{ + notImplemented(); +} + +void SocketStreamHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&) +{ + notImplemented(); +} + +void SocketStreamHandle::receivedCancellation(const AuthenticationChallenge&) +{ + notImplemented(); +} + +} // namespace WebCore diff --git a/WebCore/platform/network/win/CookieJarCFNetWin.cpp b/WebCore/platform/network/win/CookieJarCFNetWin.cpp index af9e3f3..33b795a 100644 --- a/WebCore/platform/network/win/CookieJarCFNetWin.cpp +++ b/WebCore/platform/network/win/CookieJarCFNetWin.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "CookieJar.h" +#include "Cookie.h" #include "CookieStorageWin.h" #include "Document.h" #include "KURL.h" @@ -113,4 +114,60 @@ bool cookiesEnabled(const Document* /*document*/) return policy == CFHTTPCookieStorageAcceptPolicyOnlyFromMainDocumentDomain || policy == CFHTTPCookieStorageAcceptPolicyAlways; } +bool getRawCookies(const Document*, const KURL& url, Vector<Cookie>& rawCookies) +{ + rawCookies.clear(); + CFHTTPCookieStorageRef cookieStorage = currentCookieStorage(); + if (!cookieStorage) + return false; + + RetainPtr<CFURLRef> urlCF(AdoptCF, url.createCFURL()); + + bool sendSecureCookies = url.protocolIs("https"); + RetainPtr<CFArrayRef> cookiesCF(AdoptCF, CFHTTPCookieStorageCopyCookiesForURL(cookieStorage, urlCF.get(), sendSecureCookies)); + + CFIndex count = CFArrayGetCount(cookiesCF.get()); + rawCookies.reserveCapacity(count); + + for (CFIndex i = 0; i < count; i++) { + CFHTTPCookieRef cookie = (CFHTTPCookieRef)CFArrayGetValueAtIndex(cookiesCF.get(), i); + String name = CFHTTPCookieGetName(cookie); + String value = CFHTTPCookieGetValue(cookie); + String domain = CFHTTPCookieGetDomain(cookie); + String path = CFHTTPCookieGetPath(cookie); + + double expires = (CFDateGetAbsoluteTime(CFHTTPCookieGetExpiratonDate(cookie)) + kCFAbsoluteTimeIntervalSince1970) * 1000; + + bool httpOnly = CFHTTPCookieIsHTTPOnly(cookie); + bool secure = CFHTTPCookieIsSecure(cookie); + bool session = false; // FIXME: Need API for if a cookie is a session cookie. + + rawCookies.uncheckedAppend(Cookie(name, value, domain, path, expires, httpOnly, secure, session)); + } + + return true; +} + +void deleteCookie(const Document*, const KURL& url, const String& name) +{ + CFHTTPCookieStorageRef cookieStorage = currentCookieStorage(); + if (!cookieStorage) + return; + + RetainPtr<CFURLRef> urlCF(AdoptCF, url.createCFURL()); + + bool sendSecureCookies = url.protocolIs("https"); + RetainPtr<CFArrayRef> cookiesCF(AdoptCF, CFHTTPCookieStorageCopyCookiesForURL(cookieStorage, urlCF.get(), sendSecureCookies)); + + CFIndex count = CFArrayGetCount(cookiesCF.get()); + for (CFIndex i = 0; i < count; i++) { + CFHTTPCookieRef cookie = (CFHTTPCookieRef)CFArrayGetValueAtIndex(cookiesCF.get(), i); + String cookieName = CFHTTPCookieGetName(cookie); + if (cookieName == name) { + CFHTTPCookieStorageDeleteCookie(cookieStorage, cookie); + break; + } + } +} + } diff --git a/WebCore/platform/network/win/CookieJarWin.cpp b/WebCore/platform/network/win/CookieJarWin.cpp index 41d12d9..6576e07 100644 --- a/WebCore/platform/network/win/CookieJarWin.cpp +++ b/WebCore/platform/network/win/CookieJarWin.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "CookieJar.h" +#include "Cookie.h" #include "KURL.h" #include "PlatformString.h" #include "Document.h" @@ -35,7 +36,6 @@ namespace WebCore { - void setCookies(Document* /*document*/, const KURL& url, const String& value) { // FIXME: Deal with document->firstPartyForCookies(). @@ -64,4 +64,16 @@ bool cookiesEnabled(const Document* /*document*/) return true; } +bool getRawCookies(const Document*, const KURL&, Vector<Cookie>& rawCookies) +{ + // FIXME: Not yet implemented + rawCookies.clear(); + return false; // return true when implemented +} + +void deleteCookie(const Document*, const KURL&, const String&) +{ + // FIXME: Not yet implemented +} + } diff --git a/WebCore/platform/qt/ClipboardQt.cpp b/WebCore/platform/qt/ClipboardQt.cpp index 666ad18..9d2c452 100644 --- a/WebCore/platform/qt/ClipboardQt.cpp +++ b/WebCore/platform/qt/ClipboardQt.cpp @@ -239,8 +239,6 @@ static CachedImage* getCachedImage(Element* element) void ClipboardQt::declareAndWriteDragImage(Element* element, const KURL& url, const String& title, Frame* frame) { ASSERT(frame); - Q_UNUSED(url); - Q_UNUSED(title); //WebCore::writeURL(m_writableDataObject.get(), url, title, true, false); if (!m_writableData) @@ -262,8 +260,10 @@ void ClipboardQt::declareAndWriteDragImage(Element* element, const KURL& url, co return; QList<QUrl> urls; + urls.append(url); urls.append(fullURL); + m_writableData->setText(title); m_writableData->setUrls(urls); #ifndef QT_NO_CLIPBOARD if (!isForDragging()) diff --git a/WebCore/platform/qt/ContextMenuQt.cpp b/WebCore/platform/qt/ContextMenuQt.cpp index 063a46b..9b1a054 100644 --- a/WebCore/platform/qt/ContextMenuQt.cpp +++ b/WebCore/platform/qt/ContextMenuQt.cpp @@ -61,7 +61,7 @@ void ContextMenu::insertItem(unsigned position, ContextMenuItem& item) m_items.insert(position, item); } -void ContextMenu::setPlatformDescription(PlatformMenuDescription menu) +void ContextMenu::setPlatformDescription(PlatformMenuDescription) { // doesn't make sense } diff --git a/WebCore/platform/qt/CookieJarQt.cpp b/WebCore/platform/qt/CookieJarQt.cpp index 40d9309..a27a06e 100644 --- a/WebCore/platform/qt/CookieJarQt.cpp +++ b/WebCore/platform/qt/CookieJarQt.cpp @@ -28,6 +28,7 @@ #include "config.h" #include "CookieJar.h" +#include "Cookie.h" #include "Document.h" #include "KURL.h" #include "PlatformString.h" @@ -47,6 +48,8 @@ namespace WebCore { #if QT_VERSION >= 0x040400 static QNetworkCookieJar *cookieJar(const Document *document) { + if (!document) + return 0; Frame *frame = document->frame(); if (!frame) return 0; @@ -128,6 +131,18 @@ bool cookiesEnabled(const Document* document) #endif } +bool getRawCookies(const Document*, const KURL&, Vector<Cookie>& rawCookies) +{ + // FIXME: Not yet implemented + rawCookies.clear(); + return false; // return true when implemented +} + +void deleteCookie(const Document*, const KURL&, const String&) +{ + // FIXME: Not yet implemented +} + } // vim: ts=4 sw=4 et diff --git a/WebCore/platform/qt/DragDataQt.cpp b/WebCore/platform/qt/DragDataQt.cpp index 7b1eff8..b0611e6 100644 --- a/WebCore/platform/qt/DragDataQt.cpp +++ b/WebCore/platform/qt/DragDataQt.cpp @@ -119,7 +119,7 @@ bool DragData::containsURL() const return m_platformDragData->hasUrls(); } -String DragData::asURL(String* title) const +String DragData::asURL(String*) const { if (!m_platformDragData) return String(); @@ -128,7 +128,7 @@ String DragData::asURL(String* title) const if (urls.isEmpty()) return String(); - return urls.first().toString(); + return encodeWithURLEscapeSequences(urls.first().toString()); } PassRefPtr<DocumentFragment> DragData::asFragment(Document* doc) const diff --git a/WebCore/platform/qt/FileSystemQt.cpp b/WebCore/platform/qt/FileSystemQt.cpp index 28d3ca7..4093fad 100644 --- a/WebCore/platform/qt/FileSystemQt.cpp +++ b/WebCore/platform/qt/FileSystemQt.cpp @@ -81,7 +81,7 @@ bool makeAllDirectories(const String& path) String pathByAppendingComponent(const String& path, const String& component) { - return QDir(path).filePath(component); + return QDir::toNativeSeparators(QDir(path).filePath(component)); } String homeDirectoryPath() @@ -117,7 +117,9 @@ Vector<String> listDirectory(const String& path, const String& filter) CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle) { - QFile *temp = new QTemporaryFile(QLatin1String(prefix)); + QTemporaryFile* tempFile = new QTemporaryFile(QLatin1String(prefix)); + tempFile->setAutoRemove(false); + QFile* temp = tempFile; if (temp->open(QIODevice::ReadWrite)) { handle = temp; return String(temp->fileName()).utf8(); diff --git a/WebCore/platform/qt/Localizations.cpp b/WebCore/platform/qt/Localizations.cpp index d1853fc..77cac57 100644 --- a/WebCore/platform/qt/Localizations.cpp +++ b/WebCore/platform/qt/Localizations.cpp @@ -362,5 +362,111 @@ String mediaElementLiveBroadcastStateText() return QCoreApplication::translate("QWebPage", "Live Broadcast", "Media controller status message when watching a live broadcast"); } +#if ENABLE(VIDEO) + +String localizedMediaControlElementString(const String& name) +{ + if (name == "AudioElement") + return QCoreApplication::translate("QWebPage", "Audio Element", "Media controller element"); + if (name == "VideoElement") + return QCoreApplication::translate("QWebPage", "Video Element", "Media controller element"); + if (name == "MuteButton") + return QCoreApplication::translate("QWebPage", "Mute Button", "Media controller element"); + if (name == "UnMuteButton") + return QCoreApplication::translate("QWebPage", "Unmute Button", "Media controller element"); + if (name == "PlayButton") + return QCoreApplication::translate("QWebPage", "Play Button", "Media controller element"); + if (name == "PauseButton") + return QCoreApplication::translate("QWebPage", "Pause Button", "Media controller element"); + if (name == "Slider") + return QCoreApplication::translate("QWebPage", "Slider", "Media controller element"); + if (name == "SliderThumb") + return QCoreApplication::translate("QWebPage", "Slider Thumb", "Media controller element"); + if (name == "RewindButton") + return QCoreApplication::translate("QWebPage", "Rewind Button", "Media controller element"); + if (name == "ReturnToRealtimeButton") + return QCoreApplication::translate("QWebPage", "Return to Real-time Button", "Media controller element"); + if (name == "CurrentTimeDisplay") + return QCoreApplication::translate("QWebPage", "Elapsed Time", "Media controller element"); + if (name == "TimeRemainingDisplay") + return QCoreApplication::translate("QWebPage", "Remaining Time", "Media controller element"); + if (name == "StatusDisplay") + return QCoreApplication::translate("QWebPage", "Status Display", "Media controller element"); + if (name == "FullscreenButton") + return QCoreApplication::translate("QWebPage", "Fullscreen Button", "Media controller element"); + if (name == "SeekForwardButton") + return QCoreApplication::translate("QWebPage", "Seek Forward Button", "Media controller element"); + if (name == "SeekBackButton") + return QCoreApplication::translate("QWebPage", "Seek Back Button", "Media controller element"); + + return String(); +} + +String localizedMediaControlElementHelpText(const String& name) +{ + if (name == "AudioElement") + return QCoreApplication::translate("QWebPage", "Audio element playback controls and status display", "Media controller element"); + if (name == "VideoElement") + return QCoreApplication::translate("QWebPage", "Video element playback controls and status display", "Media controller element"); + if (name == "MuteButton") + return QCoreApplication::translate("QWebPage", "Mute audio tracks", "Media controller element"); + if (name == "UnMuteButton") + return QCoreApplication::translate("QWebPage", "Unmute audio tracks", "Media controller element"); + if (name == "PlayButton") + return QCoreApplication::translate("QWebPage", "Begin playback", "Media controller element"); + if (name == "PauseButton") + return QCoreApplication::translate("QWebPage", "Pause playback", "Media controller element"); + if (name == "Slider") + return QCoreApplication::translate("QWebPage", "Movie time scrubber", "Media controller element"); + if (name == "SliderThumb") + return QCoreApplication::translate("QWebPage", "Movie time scrubber thumb", "Media controller element"); + if (name == "RewindButton") + return QCoreApplication::translate("QWebPage", "Rewind movie", "Media controller element"); + if (name == "ReturnToRealtimeButton") + return QCoreApplication::translate("QWebPage", "Return streaming movie to real-time", "Media controller element"); + if (name == "CurrentTimeDisplay") + return QCoreApplication::translate("QWebPage", "Current movie time", "Media controller element"); + if (name == "TimeRemainingDisplay") + return QCoreApplication::translate("QWebPage", "Remaining movie time", "Media controller element"); + if (name == "StatusDisplay") + return QCoreApplication::translate("QWebPage", "Current movie status", "Media controller element"); + if (name == "FullscreenButton") + return QCoreApplication::translate("QWebPage", "Play movie in full-screen mode", "Media controller element"); + if (name == "SeekForwardButton") + return QCoreApplication::translate("QWebPage", "Seek quickly back", "Media controller element"); + if (name == "SeekBackButton") + return QCoreApplication::translate("QWebPage", "Seek quickly forward", "Media controller element"); + + ASSERT_NOT_REACHED(); + return String(); +} + +String localizedMediaTimeDescription(float time) +{ + if (!isfinite(time)) + return QCoreApplication::translate("QWebPage", "Indefinite time", "Media time description"); + + int seconds = (int)fabsf(time); + int days = seconds / (60 * 60 * 24); + int hours = seconds / (60 * 60); + int minutes = (seconds / 60) % 60; + seconds %= 60; + + if (days) { + return QCoreApplication::translate("QWebPage", "%1 days %2 hours %3 minutes %4 seconds", "Media time description").arg(days).arg(hours).arg(minutes).arg(seconds); + } + + if (hours) { + return QCoreApplication::translate("QWebPage", "%1 hours %2 minutes %3 seconds", "Media time description").arg(hours).arg(minutes).arg(seconds); + } + + if (minutes) { + return QCoreApplication::translate("QWebPage", "%1 minutes %2 seconds", "Media time description").arg(minutes).arg(seconds); + } + + return QCoreApplication::translate("QWebPage", "%1 seconds", "Media time description").arg(seconds); +} +#endif // ENABLE(VIDEO) + } // vim: ts=4 sw=4 et diff --git a/WebCore/platform/qt/PasteboardQt.cpp b/WebCore/platform/qt/PasteboardQt.cpp index 969de62..209a573 100644 --- a/WebCore/platform/qt/PasteboardQt.cpp +++ b/WebCore/platform/qt/PasteboardQt.cpp @@ -119,6 +119,18 @@ PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefP return 0; } +void Pasteboard::writePlainText(const String& text) +{ +#ifndef QT_NO_CLIPBOARD + QMimeData* md = new QMimeData; + QString qtext = text; + qtext.replace(QChar(0xa0), QLatin1Char(' ')); + md->setText(qtext); + QApplication::clipboard()->setMimeData(md, m_selectionMode ? + QClipboard::Selection : QClipboard::Clipboard); +#endif +} + void Pasteboard::writeURL(const KURL& _url, const String&, Frame*) { ASSERT(!_url.isEmpty()); diff --git a/WebCore/platform/qt/PlatformKeyboardEventQt.cpp b/WebCore/platform/qt/PlatformKeyboardEventQt.cpp index 935882a..37ea681 100644 --- a/WebCore/platform/qt/PlatformKeyboardEventQt.cpp +++ b/WebCore/platform/qt/PlatformKeyboardEventQt.cpp @@ -217,7 +217,7 @@ static int windowsKeyCodeForKeyEvent(unsigned int keycode, bool isKeypad = false case Qt::Key_F9: return VK_F9; case Qt::Key_F10: - return VK_F11; + return VK_F10; case Qt::Key_F11: return VK_F11; case Qt::Key_F12: diff --git a/WebCore/platform/qt/PlatformMouseEventQt.cpp b/WebCore/platform/qt/PlatformMouseEventQt.cpp index 6c1d82d..e486e68 100644 --- a/WebCore/platform/qt/PlatformMouseEventQt.cpp +++ b/WebCore/platform/qt/PlatformMouseEventQt.cpp @@ -31,9 +31,46 @@ #include <wtf/CurrentTime.h> #include <QMouseEvent> +#include <QGraphicsSceneMouseEvent> namespace WebCore { +PlatformMouseEvent::PlatformMouseEvent(QGraphicsSceneMouseEvent* event, int clickCount) +{ + m_timestamp = WTF::currentTime(); + + switch (event->type()) { + case QEvent::GraphicsSceneMouseDoubleClick: + case QEvent::GraphicsSceneMousePress: + m_eventType = MouseEventPressed; + break; + case QEvent::GraphicsSceneMouseRelease: + m_eventType = MouseEventReleased; + break; + case QEvent::GraphicsSceneMouseMove: + default: + m_eventType = MouseEventMoved; + } + + m_position = IntPoint(event->pos().toPoint()); + m_globalPosition = IntPoint(event->screenPos()); + + if (event->button() == Qt::LeftButton || (event->buttons() & Qt::LeftButton)) + m_button = LeftButton; + else if (event->button() == Qt::RightButton || (event->buttons() & Qt::RightButton)) + m_button = RightButton; + else if (event->button() == Qt::MidButton || (event->buttons() & Qt::MidButton)) + m_button = MiddleButton; + else + m_button = NoButton; + + m_clickCount = clickCount; + m_shiftKey = (event->modifiers() & Qt::ShiftModifier) != 0; + m_ctrlKey = (event->modifiers() & Qt::ControlModifier) != 0; + m_altKey = (event->modifiers() & Qt::AltModifier) != 0; + m_metaKey = (event->modifiers() & Qt::MetaModifier) != 0; +} + PlatformMouseEvent::PlatformMouseEvent(QInputEvent* event, int clickCount) { m_timestamp = WTF::currentTime(); diff --git a/WebCore/platform/qt/PlatformScreenQt.cpp b/WebCore/platform/qt/PlatformScreenQt.cpp index 5dc0963..7ba8350 100644 --- a/WebCore/platform/qt/PlatformScreenQt.cpp +++ b/WebCore/platform/qt/PlatformScreenQt.cpp @@ -36,42 +36,54 @@ #include "FrameView.h" #include "HostWindow.h" #include "Widget.h" +#include "QWebPageClient.h" #include <QApplication> #include <QDesktopWidget> namespace WebCore { +static int screenNumber(Widget* w) +{ + if (!w) + return 0; + + QWebPageClient* client = w->root()->hostWindow()->platformPageClient(); + return client ? client->screenNumber() : 0; +} + int screenDepth(Widget* w) { - QDesktopWidget* d = QApplication::desktop(); - QWidget *view = w ? w->root()->hostWindow()->platformWindow() : 0; - int screenNumber = view ? d->screenNumber(view) : 0; - return d->screen(screenNumber)->depth(); + return QApplication::desktop()->screen(screenNumber(w))->depth(); } int screenDepthPerComponent(Widget* w) { - QWidget *view = w ? w->root()->hostWindow()->platformWindow() : 0; - return view ? view->depth() : QApplication::desktop()->screen(0)->depth(); + if (w) { + QWebPageClient* client = w->root()->hostWindow()->platformPageClient(); + + if (client) { + QWidget* view = QWidget::find(client->winId()); + if (view) + return view->depth(); + } + } + return QApplication::desktop()->screen(0)->depth(); } bool screenIsMonochrome(Widget* w) { - QDesktopWidget* d = QApplication::desktop(); - QWidget *view = w ? w->root()->hostWindow()->platformWindow(): 0; - int screenNumber = view ? d->screenNumber(view) : 0; - return d->screen(screenNumber)->numColors() < 2; + return QApplication::desktop()->screen(screenNumber(w))->numColors() < 2; } FloatRect screenRect(Widget* w) { - QRect r = QApplication::desktop()->screenGeometry(w ? w->root()->hostWindow()->platformWindow(): 0); + QRect r = QApplication::desktop()->screenGeometry(screenNumber(w)); return FloatRect(r.x(), r.y(), r.width(), r.height()); } FloatRect screenAvailableRect(Widget* w) { - QRect r = QApplication::desktop()->availableGeometry(w ? w->root()->hostWindow()->platformWindow(): 0); + QRect r = QApplication::desktop()->availableGeometry(screenNumber(w)); return FloatRect(r.x(), r.y(), r.width(), r.height()); } diff --git a/WebCore/platform/qt/PopupMenuQt.cpp b/WebCore/platform/qt/PopupMenuQt.cpp index 11dfe41..b44f2ec 100644 --- a/WebCore/platform/qt/PopupMenuQt.cpp +++ b/WebCore/platform/qt/PopupMenuQt.cpp @@ -30,6 +30,7 @@ #include "FrameView.h" #include "HostWindow.h" #include "PopupMenuClient.h" +#include "QWebPageClient.h" #include "QWebPopup.h" #include <QAction> @@ -59,7 +60,7 @@ void PopupMenu::clear() m_popup->clear(); } -void PopupMenu::populate(const IntRect& r) +void PopupMenu::populate(const IntRect&) { clear(); Q_ASSERT(client()); @@ -85,13 +86,13 @@ void PopupMenu::populate(const IntRect& r) void PopupMenu::show(const IntRect& r, FrameView* v, int index) { - QWidget* window = v->hostWindow()->platformWindow(); + QWebPageClient* client = v->hostWindow()->platformPageClient(); populate(r); QRect rect = r; rect.moveTopLeft(v->contentsToWindow(r.topLeft())); rect.setHeight(m_popup->sizeHint().height()); - m_popup->setParent(window); + m_popup->setParent(QWidget::find(client->winId())); m_popup->setGeometry(rect); m_popup->setCurrentIndex(index); m_popup->exec(); diff --git a/WebCore/platform/qt/QWebPageClient.h b/WebCore/platform/qt/QWebPageClient.h new file mode 100644 index 0000000..09f7886 --- /dev/null +++ b/WebCore/platform/qt/QWebPageClient.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef QWebPageClient_h +#define QWebPageClient_h + +#include <QRect> + +class QWebPageClient { +public: + virtual void scroll(int dx, int dy, const QRect&) = 0; + virtual void update(const QRect&) = 0; + + inline void resetCursor() + { +#ifndef QT_NO_CURSOR + if (!cursor().bitmap() && cursor().shape() == m_lastCursor.shape()) + return; + updateCursor(m_lastCursor); +#endif + } + + inline void setCursor(const QCursor& cursor) + { +#ifndef QT_NO_CURSOR + m_lastCursor = cursor; + if (!cursor.bitmap() && cursor.shape() == this->cursor().shape()) + return; + updateCursor(cursor); +#endif + } + + virtual int screenNumber() const = 0; + virtual WId winId() const = 0; + + virtual QObject* pluginParent() const = 0; + +protected: +#ifndef QT_NO_CURSOR + virtual QCursor cursor() const = 0; + virtual void updateCursor(const QCursor& cursor) = 0; +#endif + +private: +#ifndef QT_NO_CURSOR + QCursor m_lastCursor; +#endif +}; + +#endif diff --git a/WebCore/platform/qt/QWebPopup.cpp b/WebCore/platform/qt/QWebPopup.cpp index f437c27..d077079 100644 --- a/WebCore/platform/qt/QWebPopup.cpp +++ b/WebCore/platform/qt/QWebPopup.cpp @@ -71,7 +71,7 @@ void QWebPopup::hidePopup() return; m_popupVisible = false; - m_client->hidePopup(); + m_client->popupDidHide(); } void QWebPopup::activeChanged(int index) diff --git a/WebCore/platform/qt/RenderThemeQt.cpp b/WebCore/platform/qt/RenderThemeQt.cpp index 3fe67b2..b61d356 100644 --- a/WebCore/platform/qt/RenderThemeQt.cpp +++ b/WebCore/platform/qt/RenderThemeQt.cpp @@ -44,6 +44,7 @@ #include "Page.h" #include "RenderBox.h" #include "RenderTheme.h" +#include "UserAgentStyleSheets.h" #include "qwebpage.h" #include <QApplication> @@ -172,7 +173,7 @@ bool RenderThemeQt::supportsHover(const RenderStyle*) const return true; } -bool RenderThemeQt::supportsFocusRing(const RenderStyle* style) const +bool RenderThemeQt::supportsFocusRing(const RenderStyle*) const { return true; // Qt provides this through the style } @@ -274,7 +275,7 @@ Color RenderThemeQt::platformInactiveSelectionForegroundColor() const return pal.brush(QPalette::Inactive, QPalette::HighlightedText).color(); } -void RenderThemeQt::systemFont(int propId, FontDescription& fontDescription) const +void RenderThemeQt::systemFont(int, FontDescription&) const { // no-op } @@ -387,7 +388,7 @@ bool RenderThemeQt::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i return paintButton(o, i, r); } -void RenderThemeQt::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const +void RenderThemeQt::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element*) const { // Ditch the border. style->resetBorder(); @@ -572,7 +573,7 @@ bool RenderThemeQt::paintMenuList(RenderObject* o, const RenderObject::PaintInfo QStyleOptionComboBox opt; if (p.widget) opt.initFrom(p.widget); - ControlPart appearance = applyTheme(opt, o); + applyTheme(opt, o); const QPoint topLeft = r.topLeft(); p.painter->translate(topLeft); @@ -584,8 +585,7 @@ bool RenderThemeQt::paintMenuList(RenderObject* o, const RenderObject::PaintInfo return false; } -void RenderThemeQt::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, - Element* e) const +void RenderThemeQt::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle* style, Element*) const { // WORKAROUND because html.css specifies -webkit-border-radius for <select> so we override it here // see also http://bugs.webkit.org/show_bug.cgi?id=18399 @@ -772,13 +772,7 @@ ControlPart RenderThemeQt::applyTheme(QStyleOption& option, RenderObject* o) con String RenderThemeQt::extraMediaControlsStyleSheet() { - QFile platformStyleSheet(QLatin1String(":/webcore/css/mediaControls-extras.css")); - if (platformStyleSheet.open(QFile::ReadOnly)) { - QByteArray sheetData = platformStyleSheet.readAll(); - return QString::fromUtf8(sheetData.constData(), sheetData.length()); - } - - return String(); + return String(mediaControlsQtUserAgentStyleSheet, sizeof(mediaControlsQtUserAgentStyleSheet)); } // Helper class to transform the painter's world matrix to the object's content area, scaled to 0,0,100,100 @@ -887,13 +881,13 @@ bool RenderThemeQt::paintMediaPlayButton(RenderObject* o, const RenderObject::Pa return false; } -bool RenderThemeQt::paintMediaSeekBackButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +bool RenderThemeQt::paintMediaSeekBackButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { // We don't want to paint this at the moment. return false; } -bool RenderThemeQt::paintMediaSeekForwardButton(RenderObject* o, const RenderObject::PaintInfo& paintInfo, const IntRect& r) +bool RenderThemeQt::paintMediaSeekForwardButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { // We don't want to paint this at the moment. return false; diff --git a/WebCore/platform/qt/ScrollViewQt.cpp b/WebCore/platform/qt/ScrollViewQt.cpp index 48885d3..ccbd751 100644 --- a/WebCore/platform/qt/ScrollViewQt.cpp +++ b/WebCore/platform/qt/ScrollViewQt.cpp @@ -53,7 +53,7 @@ void ScrollView::adjustWidgetsPreventingBlittingCount(int delta) parent()->adjustWidgetsPreventingBlittingCount(delta); } -void ScrollView::platformAddChild(Widget* child) +void ScrollView::platformAddChild(Widget*) { adjustWidgetsPreventingBlittingCount(1); } diff --git a/WebCore/platform/qt/SearchPopupMenuQt.cpp b/WebCore/platform/qt/SearchPopupMenuQt.cpp index 7822b2c..187a5de 100644 --- a/WebCore/platform/qt/SearchPopupMenuQt.cpp +++ b/WebCore/platform/qt/SearchPopupMenuQt.cpp @@ -29,11 +29,11 @@ SearchPopupMenu::SearchPopupMenu(PopupMenuClient* client) { } -void SearchPopupMenu::saveRecentSearches(const AtomicString& name, const Vector<String>& searchItems) +void SearchPopupMenu::saveRecentSearches(const AtomicString&, const Vector<String>&) { } -void SearchPopupMenu::loadRecentSearches(const AtomicString& name, Vector<String>& searchItems) +void SearchPopupMenu::loadRecentSearches(const AtomicString&, Vector<String>&) { } diff --git a/WebCore/platform/qt/TemporaryLinkStubs.cpp b/WebCore/platform/qt/TemporaryLinkStubs.cpp index 8ef598f..814f961 100644 --- a/WebCore/platform/qt/TemporaryLinkStubs.cpp +++ b/WebCore/platform/qt/TemporaryLinkStubs.cpp @@ -100,7 +100,7 @@ void getSupportedKeySizes(Vector<String>&) notImplemented(); } -String signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String &challengeString, const KURL &url) +String signedPublicKeyAndChallengeString(unsigned, const String&, const KURL&) { return String(); } @@ -114,11 +114,6 @@ float userIdleTime() } #endif -void prefetchDNS(const String& hostname) -{ - notImplemented(); -} - } // vim: ts=4 sw=4 et diff --git a/WebCore/platform/qt/WheelEventQt.cpp b/WebCore/platform/qt/WheelEventQt.cpp index 9534f20..66118e1 100644 --- a/WebCore/platform/qt/WheelEventQt.cpp +++ b/WebCore/platform/qt/WheelEventQt.cpp @@ -25,9 +25,48 @@ #include <qapplication.h> #include <QWheelEvent> +#include <QGraphicsSceneWheelEvent> namespace WebCore { +void PlatformWheelEvent::applyDelta(int delta, Qt::Orientation orientation) +{ + if (orientation == Qt::Horizontal) { + m_deltaX = (delta / 120); + m_deltaY = 0; + } else { + m_deltaX = 0; + m_deltaY = (delta / 120); + } + + m_wheelTicksX = m_deltaX; + m_wheelTicksY = m_deltaY; + + // Use the same single scroll step as QTextEdit + // (in QTextEditPrivate::init [h,v]bar->setSingleStep) + static const float cDefaultQtScrollStep = 20.f; + m_deltaX *= QApplication::wheelScrollLines() * cDefaultQtScrollStep; + m_deltaY *= QApplication::wheelScrollLines() * cDefaultQtScrollStep; +} + +PlatformWheelEvent::PlatformWheelEvent(QGraphicsSceneWheelEvent* e) +#ifdef QT_NO_WHEELEVENT +{ + Q_UNUSED(e); +} +#else + : m_position(e->pos().toPoint()) + , m_globalPosition(e->screenPos()) + , m_granularity(ScrollByPixelWheelEvent) + , m_isAccepted(false) + , m_shiftKey(e->modifiers() & Qt::ShiftModifier) + , m_ctrlKey(e->modifiers() & Qt::ControlModifier) + , m_altKey(e->modifiers() & Qt::AltModifier) + , m_metaKey(e->modifiers() & Qt::MetaModifier) +{ + applyDelta(e->delta(), e->orientation()); +} +#endif // QT_NO_WHEELEVENT PlatformWheelEvent::PlatformWheelEvent(QWheelEvent* e) #ifdef QT_NO_WHEELEVENT @@ -44,21 +83,7 @@ PlatformWheelEvent::PlatformWheelEvent(QWheelEvent* e) , m_altKey(e->modifiers() & Qt::AltModifier) , m_metaKey(e->modifiers() & Qt::MetaModifier) { - if (e->orientation() == Qt::Horizontal) { - m_deltaX = (e->delta() / 120); - m_deltaY = 0; - } else { - m_deltaX = 0; - m_deltaY = (e->delta() / 120); - } - m_wheelTicksX = m_deltaX; - m_wheelTicksY = m_deltaY; - - // use the same single scroll step as QTextEdit (in - // QTextEditPrivate::init [h,v]bar->setSingleStep ) - static const float cDefaultQtScrollStep = 20.f; - m_deltaX *= QApplication::wheelScrollLines() * cDefaultQtScrollStep; - m_deltaY *= QApplication::wheelScrollLines() * cDefaultQtScrollStep; + applyDelta(e->delta(), e->orientation()); } #endif // QT_NO_WHEELEVENT diff --git a/WebCore/platform/qt/WidgetQt.cpp b/WebCore/platform/qt/WidgetQt.cpp index 0fb6c37..e9c99a4 100644 --- a/WebCore/platform/qt/WidgetQt.cpp +++ b/WebCore/platform/qt/WidgetQt.cpp @@ -30,6 +30,7 @@ */ #include "config.h" +#include "Widget.h" #include "Cursor.h" #include "Font.h" @@ -37,8 +38,8 @@ #include "HostWindow.h" #include "IntRect.h" #include "ScrollView.h" -#include "Widget.h" #include "NotImplemented.h" +#include "QWebPageClient.h" #include "qwebframe.h" #include "qwebframe_p.h" @@ -81,15 +82,10 @@ void Widget::setFocus() void Widget::setCursor(const Cursor& cursor) { #ifndef QT_NO_CURSOR - QWidget* widget = root()->hostWindow()->platformWindow(); - - if (!widget) - return; - - if (!cursor.impl().bitmap() && widget->cursor().shape() == cursor.impl().shape()) - return; + QWebPageClient* pageClient = root()->hostWindow()->platformPageClient(); - QCoreApplication::postEvent(widget, new SetCursorEvent(cursor.impl())); + if (pageClient) + pageClient->setCursor(cursor.impl()); #endif } @@ -105,7 +101,7 @@ void Widget::hide() platformWidget()->hide(); } -void Widget::paint(GraphicsContext *, const IntRect &rect) +void Widget::paint(GraphicsContext*, const IntRect&) { } diff --git a/WebCore/platform/sql/SQLValue.cpp b/WebCore/platform/sql/SQLValue.cpp index 7e178f9..0ad643e 100644 --- a/WebCore/platform/sql/SQLValue.cpp +++ b/WebCore/platform/sql/SQLValue.cpp @@ -32,10 +32,10 @@ namespace WebCore { SQLValue::SQLValue(const SQLValue& val) + : m_type(val.m_type) + , m_number(val.m_number) + , m_string(val.m_string.threadsafeCopy()) { - m_number = val.m_number; - m_string = val.m_string.copy(); - m_type = val.m_type; } String SQLValue::string() const @@ -43,7 +43,7 @@ String SQLValue::string() const ASSERT(m_type == StringValue); // Must return a copy since ref-shared Strings are not thread safe - return m_string.copy(); + return m_string.threadsafeCopy(); } double SQLValue::number() const diff --git a/WebCore/platform/sql/SQLValue.h b/WebCore/platform/sql/SQLValue.h index 7d85051..0f854fc 100644 --- a/WebCore/platform/sql/SQLValue.h +++ b/WebCore/platform/sql/SQLValue.h @@ -38,9 +38,9 @@ namespace WebCore { public: enum Type { NullValue, NumberValue, StringValue }; - SQLValue() : m_type(NullValue) { } + SQLValue() : m_type(NullValue), m_number(0.0) { } SQLValue(double number) : m_type(NumberValue), m_number(number) { } - SQLValue(const String& s) : m_type(StringValue), m_string(s) { } + SQLValue(const String& s) : m_type(StringValue), m_number(0.0), m_string(s) { } SQLValue(const SQLValue&); Type type() const { return m_type; } diff --git a/WebCore/platform/sql/SQLiteTransaction.cpp b/WebCore/platform/sql/SQLiteTransaction.cpp index 0a236be..a4b2ac8 100644 --- a/WebCore/platform/sql/SQLiteTransaction.cpp +++ b/WebCore/platform/sql/SQLiteTransaction.cpp @@ -30,9 +30,10 @@ namespace WebCore { -SQLiteTransaction::SQLiteTransaction(SQLiteDatabase& db) +SQLiteTransaction::SQLiteTransaction(SQLiteDatabase& db, bool readOnly) : m_db(db) , m_inProgress(false) + , m_readOnly(readOnly) { } @@ -46,7 +47,17 @@ void SQLiteTransaction::begin() { if (!m_inProgress) { ASSERT(!m_db.m_transactionInProgress); - m_inProgress = m_db.executeCommand("BEGIN;"); + // Call BEGIN IMMEDIATE for a write transaction to acquire + // a RESERVED lock on the DB file. Otherwise, another write + // transaction (on another connection) could make changes + // to the same DB file before this transaction gets to execute + // any statements. If that happens, this transaction will fail. + // http://www.sqlite.org/lang_transaction.html + // http://www.sqlite.org/lockingv3.html#locking + if (m_readOnly) + m_inProgress = m_db.executeCommand("BEGIN;"); + else + m_inProgress = m_db.executeCommand("BEGIN IMMEDIATE;"); m_db.m_transactionInProgress = m_inProgress; } } diff --git a/WebCore/platform/sql/SQLiteTransaction.h b/WebCore/platform/sql/SQLiteTransaction.h index cf5a180..557d81c 100644 --- a/WebCore/platform/sql/SQLiteTransaction.h +++ b/WebCore/platform/sql/SQLiteTransaction.h @@ -35,7 +35,7 @@ class SQLiteDatabase; class SQLiteTransaction : public Noncopyable { public: - SQLiteTransaction(SQLiteDatabase& db); + SQLiteTransaction(SQLiteDatabase& db, bool readOnly = false); ~SQLiteTransaction(); void begin(); @@ -47,10 +47,9 @@ public: private: SQLiteDatabase& m_db; bool m_inProgress; - + bool m_readOnly; }; } // namespace WebCore #endif // SQLiteTransation_H - diff --git a/WebCore/platform/sql/chromium/SQLiteFileSystemChromium.cpp b/WebCore/platform/sql/chromium/SQLiteFileSystemChromium.cpp index dc79fd0..3cf961f 100644 --- a/WebCore/platform/sql/chromium/SQLiteFileSystemChromium.cpp +++ b/WebCore/platform/sql/chromium/SQLiteFileSystemChromium.cpp @@ -55,10 +55,10 @@ int SQLiteFileSystem::openDatabase(const String& fileName, sqlite3** database) return sqlite3_open16(path.charactersWithNullTermination(), database); } - // open databases using Chromium's VFS + // open databases using the default VFS + // in renderers, it should be Chromium's VFS; in the browser process it should be SQLite's default VFS return sqlite3_open_v2(fileName.utf8().data(), database, - SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, - "chromium_vfs"); + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, 0); } String SQLiteFileSystem::getFileNameForNewDatabase( @@ -99,9 +99,7 @@ bool SQLiteFileSystem::deleteEmptyDatabaseDirectory(const String&) bool SQLiteFileSystem::deleteDatabaseFile(const String& fileName) { - // return true if and only if the error code returned by - // ChromiumBridge::deleteDatabase() is 0 - return (!ChromiumBridge::databaseDeleteFile(fileName)); + return (ChromiumBridge::databaseDeleteFile(fileName) == SQLITE_OK); } long long SQLiteFileSystem::getDatabaseFileSize(const String& fileName) diff --git a/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumPosix.cpp b/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumPosix.cpp new file mode 100644 index 0000000..2960a5f --- /dev/null +++ b/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumPosix.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2009 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER 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 "SQLiteFileSystem.h" + +#include "ChromiumBridge.h" +#include <sqlite3.h> + +#include <fcntl.h> +#include <string.h> +#include <unistd.h> + +using namespace WebCore; + +// Defined in Chromium's codebase in third_party/sqlite/src/os_unix.c +extern "C" { +void initUnixFile(sqlite3_file* file); +int fillInUnixFile(sqlite3_vfs* vfs, int fd, int dirfd, sqlite3_file* file, const char* fileName, int noLock); +} + +// Chromium's Posix implementation of SQLite VFS +namespace { + +// Opens a file. +// +// vfs - pointer to the sqlite3_vfs object. +// fileName - the name of the file. +// id - the structure that will manipulate the newly opened file. +// desiredFlags - the desired open mode flags. +// usedFlags - the actual open mode flags that were used. +int chromiumOpen(sqlite3_vfs* vfs, const char* fileName, + sqlite3_file* id, int desiredFlags, int* usedFlags) +{ + initUnixFile(id); + int dirfd = -1; + int fd = ChromiumBridge::databaseOpenFile(fileName, desiredFlags, &dirfd); + if (fd < 0) { + if (desiredFlags & SQLITE_OPEN_READWRITE) { + int newFlags = (desiredFlags & ~(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)) | SQLITE_OPEN_READONLY; + return chromiumOpen(vfs, fileName, id, newFlags, usedFlags); + } else + return SQLITE_CANTOPEN; + } + if (usedFlags) + *usedFlags = desiredFlags; + + fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); + if (dirfd >= 0) + fcntl(dirfd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); + + // The mask 0x00007F00 gives us the 7 bits that determine the type of the file SQLite is trying to open. + int fileType = desiredFlags & 0x00007F00; + int noLock = (fileType != SQLITE_OPEN_MAIN_DB); + return fillInUnixFile(vfs, fd, dirfd, id, fileName, noLock); +} + +// Deletes the given file. +// +// vfs - pointer to the sqlite3_vfs object. +// fileName - the name of the file. +// syncDir - determines if the directory to which this file belongs +// should be synched after the file is deleted. +int chromiumDelete(sqlite3_vfs*, const char* fileName, int syncDir) +{ + return ChromiumBridge::databaseDeleteFile(fileName, syncDir); +} + +// Check the existance and status of the given file. +// +// vfs - pointer to the sqlite3_vfs object. +// fileName - the name of the file. +// flag - the type of test to make on this file. +// res - the result. +int chromiumAccess(sqlite3_vfs*, const char* fileName, int flag, int* res) +{ + int attr = static_cast<int>(ChromiumBridge::databaseGetFileAttributes(fileName)); + if (attr < 0) { + *res = 0; + return SQLITE_OK; + } + + switch (flag) { + case SQLITE_ACCESS_EXISTS: + *res = 1; // if the file doesn't exist, attr < 0 + break; + case SQLITE_ACCESS_READWRITE: + *res = (attr & W_OK) && (attr & R_OK); + break; + case SQLITE_ACCESS_READ: + *res = (attr & R_OK); + break; + default: + return SQLITE_ERROR; + } + + return SQLITE_OK; +} + +// Turns a relative pathname into a full pathname. +// +// vfs - pointer to the sqlite3_vfs object. +// relativePath - the relative path. +// bufSize - the size of the output buffer in bytes. +// absolutePath - the output buffer where the absolute path will be stored. +int chromiumFullPathname(sqlite3_vfs* vfs, const char* relativePath, + int, char* absolutePath) +{ + // The renderer process doesn't need to know the absolute path of the file + sqlite3_snprintf(vfs->mxPathname, absolutePath, "%s", relativePath); + return SQLITE_OK; +} + +#ifndef SQLITE_OMIT_LOAD_EXTENSION +// Returns NULL, thus disallowing loading libraries in the renderer process. +// +// vfs - pointer to the sqlite3_vfs object. +// fileName - the name of the shared library file. +void* chromiumDlOpen(sqlite3_vfs*, const char*) +{ + return 0; +} +#else +#define chromiumDlOpen 0 +#endif // SQLITE_OMIT_LOAD_EXTENSION + +} // namespace + +namespace WebCore { + +void SQLiteFileSystem::registerSQLiteVFS() +{ + // FIXME: Make sure there aren't any unintended consequences when VFS code is called in the browser process. + if (!ChromiumBridge::sandboxEnabled()) { + ASSERT_NOT_REACHED(); + return; + } + + sqlite3_vfs* unix_vfs = sqlite3_vfs_find("unix"); + static sqlite3_vfs chromium_vfs = { + 1, + unix_vfs->szOsFile, + unix_vfs->mxPathname, + 0, + "chromium_vfs", + unix_vfs->pAppData, + chromiumOpen, + chromiumDelete, + chromiumAccess, + chromiumFullPathname, + chromiumDlOpen, + unix_vfs->xDlError, + unix_vfs->xDlSym, + unix_vfs->xDlClose, + unix_vfs->xRandomness, + unix_vfs->xSleep, + unix_vfs->xCurrentTime, + unix_vfs->xGetLastError + }; + sqlite3_vfs_register(&chromium_vfs, 1); +} + +} // namespace WebCore diff --git a/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumWin.cpp b/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumWin.cpp index b357d4a..153793b 100644 --- a/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumWin.cpp +++ b/WebCore/platform/sql/chromium/SQLiteFileSystemChromiumWin.cpp @@ -35,6 +35,8 @@ #include <sqlite3.h> #include <windows.h> +using namespace WebCore; + // Defined in Chromium's codebase in third_party/sqlite/src/os_win.c extern "C" { int chromium_sqlite3_initialize_win_sqlite3_file(sqlite3_file* file, HANDLE handle); @@ -53,7 +55,7 @@ namespace { int chromiumOpen(sqlite3_vfs*, const char* fileName, sqlite3_file* id, int desiredFlags, int* usedFlags) { - HANDLE h = WebCore::ChromiumBridge::databaseOpenFile(fileName, desiredFlags); + HANDLE h = ChromiumBridge::databaseOpenFile(fileName, desiredFlags); if (h == INVALID_HANDLE_VALUE) { if (desiredFlags & SQLITE_OPEN_READWRITE) { int newFlags = (desiredFlags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE; @@ -80,10 +82,7 @@ int chromiumOpen(sqlite3_vfs*, const char* fileName, // should be synched after the file is deleted. int chromiumDelete(sqlite3_vfs*, const char* fileName, int) { - bool deleted = WebCore::ChromiumBridge::databaseDeleteFile(fileName); - DWORD rc = WebCore::ChromiumBridge::databaseGetFileAttributes(fileName); - return ((rc == INVALID_FILE_ATTRIBUTES) && deleted ? - SQLITE_OK : SQLITE_IOERR_DELETE); + return ChromiumBridge::databaseDeleteFile(fileName); } // Check the existance and status of the given file. @@ -94,7 +93,7 @@ int chromiumDelete(sqlite3_vfs*, const char* fileName, int) // res - the result. int chromiumAccess(sqlite3_vfs*, const char* fileName, int flag, int* res) { - DWORD attr = WebCore::ChromiumBridge::databaseGetFileAttributes(fileName); + DWORD attr = ChromiumBridge::databaseGetFileAttributes(fileName); switch (flag) { case SQLITE_ACCESS_READ: case SQLITE_ACCESS_EXISTS: @@ -156,7 +155,7 @@ void SQLiteFileSystem::registerSQLiteVFS() win32_vfs->mxPathname, 0, "chromium_vfs", - 0, + win32_vfs->pAppData, chromiumOpen, chromiumDelete, chromiumAccess, diff --git a/WebCore/platform/text/CString.cpp b/WebCore/platform/text/CString.cpp index 90990f8..25f5fa1 100644 --- a/WebCore/platform/text/CString.cpp +++ b/WebCore/platform/text/CString.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2006, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/WebCore/platform/text/CString.h b/WebCore/platform/text/CString.h index f084ddf..b9030d6 100644 --- a/WebCore/platform/text/CString.h +++ b/WebCore/platform/text/CString.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2006, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/WebCore/platform/text/PlatformString.h b/WebCore/platform/text/PlatformString.h index 6d5384f..8d19c17 100644 --- a/WebCore/platform/text/PlatformString.h +++ b/WebCore/platform/text/PlatformString.h @@ -56,6 +56,10 @@ QT_END_NAMESPACE class wxString; #endif +#if PLATFORM(HAIKU) +class BString; +#endif + namespace WebCore { class CString; @@ -189,16 +193,13 @@ public: bool percentage(int& percentage) const; - // Makes a deep copy. Helpful only if you need to use a String on another thread. + // Returns a StringImpl suitable for use on another thread. + String crossThreadString() const; + // Makes a deep copy. Helpful only if you need to use a String on another thread + // (use crossThreadString if the method call doesn't need to be threadsafe). // Since the underlying StringImpl objects are immutable, there's no other reason // to ever prefer copy() over plain old assignment. - String copy() const; - - // Makes a deep copy like copy() but only for a substring. - // (This ensures that you always get something suitable for a thread while subtring - // may not. For example, in the empty string case, StringImpl::substring returns - // empty() which is not safe for another thread.) - String substringCopy(unsigned pos, unsigned len = UINT_MAX) const; + String threadsafeCopy() const; bool isNull() const { return !m_impl; } bool isEmpty() const; @@ -229,6 +230,11 @@ public: operator wxString() const; #endif +#if PLATFORM(HAIKU) + String(const BString&); + operator BString() const; +#endif + #ifndef NDEBUG Vector<char> ascii() const; #endif @@ -245,6 +251,14 @@ public: // Determines the writing direction using the Unicode Bidi Algorithm rules P2 and P3. WTF::Unicode::Direction defaultWritingDirection() const { return m_impl ? m_impl->defaultWritingDirection() : WTF::Unicode::LeftToRight; } + // Counts the number of grapheme clusters. A surrogate pair or a sequence + // of a non-combining character and following combining characters is + // counted as 1 grapheme cluster. + unsigned numGraphemeClusters() const; + // Returns the number of characters which will be less than or equal to + // the specified grapheme cluster length. + unsigned numCharactersInGraphemeClusters(unsigned) const; + private: RefPtr<StringImpl> m_impl; }; diff --git a/WebCore/platform/text/RegularExpression.cpp b/WebCore/platform/text/RegularExpression.cpp index 6329b3b..9b063c9 100644 --- a/WebCore/platform/text/RegularExpression.cpp +++ b/WebCore/platform/text/RegularExpression.cpp @@ -32,7 +32,7 @@ namespace WebCore { -class RegularExpression::Private : public RefCounted<Private> { +class RegularExpression::Private : public RefCounted<RegularExpression::Private> { public: static PassRefPtr<Private> create(const String& pattern, TextCaseSensitivity); ~Private(); diff --git a/WebCore/platform/text/String.cpp b/WebCore/platform/text/String.cpp index 2730939..bef2674 100644 --- a/WebCore/platform/text/String.cpp +++ b/WebCore/platform/text/String.cpp @@ -25,6 +25,7 @@ #include "CString.h" #include "FloatConversion.h" #include "StringBuffer.h" +#include "TextBreakIterator.h" #include "TextEncoding.h" #include <wtf/dtoa.h> #include <limits> @@ -262,13 +263,6 @@ String String::substring(unsigned pos, unsigned len) const return m_impl->substring(pos, len); } -String String::substringCopy(unsigned pos, unsigned len) const -{ - if (!m_impl) - return String(); - return m_impl->substringCopy(pos, len); -} - String String::lower() const { if (!m_impl) @@ -589,11 +583,18 @@ float String::toFloat(bool* ok) const return m_impl->toFloat(ok); } -String String::copy() const +String String::threadsafeCopy() const +{ + if (!m_impl) + return String(); + return m_impl->threadsafeCopy(); +} + +String String::crossThreadString() const { if (!m_impl) return String(); - return m_impl->copy(); + return m_impl->crossThreadString(); } bool String::isEmpty() const @@ -921,6 +922,31 @@ PassRefPtr<SharedBuffer> utf8Buffer(const String& string) return SharedBuffer::adoptVector(buffer); } +unsigned String::numGraphemeClusters() const +{ + TextBreakIterator* it = characterBreakIterator(characters(), length()); + if (!it) + return length(); + + unsigned num = 0; + while (textBreakNext(it) != TextBreakDone) + ++num; + return num; +} + +unsigned String::numCharactersInGraphemeClusters(unsigned numGraphemeClusters) const +{ + TextBreakIterator* it = characterBreakIterator(characters(), length()); + if (!it) + return min(length(), numGraphemeClusters); + + for (unsigned i = 0; i < numGraphemeClusters; ++i) { + if (textBreakNext(it) == TextBreakDone) + return length(); + } + return textBreakCurrent(it); +} + } // namespace WebCore #ifndef NDEBUG diff --git a/WebCore/platform/text/StringImpl.cpp b/WebCore/platform/text/StringImpl.cpp index 8b749c7..c3ab4be 100644 --- a/WebCore/platform/text/StringImpl.cpp +++ b/WebCore/platform/text/StringImpl.cpp @@ -57,7 +57,7 @@ static inline void deleteUCharVector(const UChar* p) } // Some of the factory methods create buffers using fastMalloc. -// We must ensure that ll allocations of StringImpl are allocated using +// We must ensure that all allocations of StringImpl are allocated using // fastMalloc so that we don't have mis-matched frees. We accomplish // this by overriding the new and delete operators. void* StringImpl::operator new(size_t size, void* address) @@ -79,10 +79,9 @@ void StringImpl::operator delete(void* address) // This constructor is used only to create the empty string. StringImpl::StringImpl() - : m_length(0) - , m_data(0) + : m_data(0) + , m_length(0) , m_hash(0) - , m_bufferIsInternal(false) { // Ensure that the hash is computed so that AtomicStringHash can call existingHash() // with impunity. The empty string is special because it is never entered into @@ -90,52 +89,10 @@ StringImpl::StringImpl() hash(); } -// This is one of the most common constructors, but it's also used for the copy() -// operation. Because of that, it's the one constructor that doesn't assert the -// length is non-zero, since we support copying the empty string. -inline StringImpl::StringImpl(const UChar* characters, unsigned length) - : m_length(length) - , m_hash(0) - , m_bufferIsInternal(false) -{ - UChar* data = newUCharVector(length); - memcpy(data, characters, length * sizeof(UChar)); - m_data = data; -} - -inline StringImpl::StringImpl(const StringImpl& str, WithTerminatingNullCharacter) - : m_length(str.m_length) - , m_hash(str.m_hash) - , m_bufferIsInternal(false) -{ - m_sharedBufferAndFlags.setFlag(HasTerminatingNullCharacter); - UChar* data = newUCharVector(str.m_length + 1); - memcpy(data, str.m_data, str.m_length * sizeof(UChar)); - data[str.m_length] = 0; - m_data = data; -} - -inline StringImpl::StringImpl(const char* characters, unsigned length) - : m_length(length) - , m_hash(0) - , m_bufferIsInternal(false) -{ - ASSERT(characters); - ASSERT(length); - - UChar* data = newUCharVector(length); - for (unsigned i = 0; i != length; ++i) { - unsigned char c = characters[i]; - data[i] = c; - } - m_data = data; -} - inline StringImpl::StringImpl(UChar* characters, unsigned length, AdoptBuffer) - : m_length(length) - , m_data(characters) + : m_data(characters) + , m_length(length) , m_hash(0) - , m_bufferIsInternal(false) { ASSERT(characters); ASSERT(length); @@ -143,9 +100,9 @@ inline StringImpl::StringImpl(UChar* characters, unsigned length, AdoptBuffer) // This constructor is only for use by AtomicString. StringImpl::StringImpl(const UChar* characters, unsigned length, unsigned hash) - : m_length(length) + : m_data(0) + , m_length(length) , m_hash(hash) - , m_bufferIsInternal(false) { ASSERT(hash); ASSERT(characters); @@ -159,9 +116,9 @@ StringImpl::StringImpl(const UChar* characters, unsigned length, unsigned hash) // This constructor is only for use by AtomicString. StringImpl::StringImpl(const char* characters, unsigned length, unsigned hash) - : m_length(length) + : m_data(0) + , m_length(length) , m_hash(hash) - , m_bufferIsInternal(false) { ASSERT(hash); ASSERT(characters); @@ -180,7 +137,7 @@ StringImpl::~StringImpl() { if (inTable()) AtomicString::remove(this); - if (!m_bufferIsInternal) { + if (!bufferIsInternal()) { SharedUChar* sharedBuffer = m_sharedBufferAndFlags.get(); if (sharedBuffer) sharedBuffer->deref(); @@ -218,15 +175,6 @@ PassRefPtr<StringImpl> StringImpl::substring(unsigned start, unsigned length) return create(m_data + start, length); } -PassRefPtr<StringImpl> StringImpl::substringCopy(unsigned start, unsigned length) -{ - start = min(start, m_length); - length = min(length, m_length - start); - if (!length) - return adoptRef(new StringImpl); - return create(m_data + start, length); -} - UChar32 StringImpl::characterStartingAt(unsigned i) { if (U16_IS_SINGLE(m_data[i])) @@ -1007,10 +955,9 @@ PassRefPtr<StringImpl> StringImpl::createUninitialized(unsigned length, UChar*& // struct as well as the data which it contains. This removes one // heap allocation from this call. size_t size = sizeof(StringImpl) + length * sizeof(UChar); - char* buffer = static_cast<char*>(fastMalloc(size)); - data = reinterpret_cast<UChar*>(buffer + sizeof(StringImpl)); - StringImpl* string = new (buffer) StringImpl(data, length, AdoptBuffer()); - string->m_bufferIsInternal = true; + StringImpl* string = static_cast<StringImpl*>(fastMalloc(size)); + data = reinterpret_cast<UChar*>(string + 1); + string = new (string) StringImpl(data, length, AdoptBuffer()); return adoptRef(string); } @@ -1071,18 +1018,43 @@ JSC::UString StringImpl::ustring() PassRefPtr<StringImpl> StringImpl::createWithTerminatingNullCharacter(const StringImpl& string) { - return adoptRef(new StringImpl(string, WithTerminatingNullCharacter())); + // Use createUninitialized instead of 'new StringImpl' so that the string and its buffer + // get allocated in a single malloc block. + UChar* data; + int length = string.m_length; + RefPtr<StringImpl> terminatedString = createUninitialized(length + 1, data); + memcpy(data, string.m_data, length * sizeof(UChar)); + data[length] = 0; + terminatedString->m_length--; + terminatedString->m_hash = string.m_hash; + terminatedString->m_sharedBufferAndFlags.setFlag(HasTerminatingNullCharacter); + return terminatedString.release(); } -PassRefPtr<StringImpl> StringImpl::copy() +PassRefPtr<StringImpl> StringImpl::threadsafeCopy() const { - // Using the constructor directly to make sure that per-thread empty string instance isn't returned. - return adoptRef(new StringImpl(m_data, m_length)); + // Special-case empty strings to make sure that per-thread empty string instance isn't returned. + if (m_length == 0) + return adoptRef(new StringImpl); + return create(m_data, m_length); +} + +PassRefPtr<StringImpl> StringImpl::crossThreadString() +{ + SharedUChar* shared = sharedBuffer(); + if (shared) { + RefPtr<StringImpl> impl = adoptRef(new StringImpl(const_cast<UChar*>(m_data), m_length, AdoptBuffer())); + impl->m_sharedBufferAndFlags.set(shared->crossThreadCopy().releaseRef()); + return impl.release(); + } + + // If no shared buffer is available, create a copy. + return threadsafeCopy(); } StringImpl::SharedUChar* StringImpl::sharedBuffer() { - if (m_length < minLengthToShare || m_bufferIsInternal) + if (m_length < minLengthToShare || bufferIsInternal()) return 0; if (!m_sharedBufferAndFlags.get()) diff --git a/WebCore/platform/text/StringImpl.h b/WebCore/platform/text/StringImpl.h index 8b4e82d..f3256cc 100644 --- a/WebCore/platform/text/StringImpl.h +++ b/WebCore/platform/text/StringImpl.h @@ -67,15 +67,10 @@ class StringImpl : public RefCounted<StringImpl> { private: friend class ThreadGlobalData; StringImpl(); - StringImpl(const UChar*, unsigned length); - StringImpl(const char*, unsigned length); struct AdoptBuffer { }; StringImpl(UChar*, unsigned length, AdoptBuffer); - struct WithTerminatingNullCharacter { }; - StringImpl(const StringImpl&, WithTerminatingNullCharacter); - // For AtomicString. StringImpl(const UChar*, unsigned length, unsigned hash); StringImpl(const char*, unsigned length, unsigned hash); @@ -114,15 +109,12 @@ public: static unsigned computeHash(const UChar*, unsigned len); static unsigned computeHash(const char*); - // Makes a deep copy. Helpful only if you need to use a String on another thread. + // Returns a StringImpl suitable for use on another thread. + PassRefPtr<StringImpl> crossThreadString(); + // Makes a deep copy. Helpful only if you need to use a String on another thread + // (use crossThreadString if the method call doesn't need to be threadsafe). // Since StringImpl objects are immutable, there's no other reason to make a copy. - PassRefPtr<StringImpl> copy(); - - // Makes a deep copy like copy() but only for a substring. - // (This ensures that you always get something suitable for a thread while subtring - // may not. For example, in the empty string case, substring returns empty() which - // is not safe for another thread.) - PassRefPtr<StringImpl> substringCopy(unsigned pos, unsigned len = UINT_MAX); + PassRefPtr<StringImpl> threadsafeCopy() const; PassRefPtr<StringImpl> substring(unsigned pos, unsigned len = UINT_MAX); @@ -166,7 +158,7 @@ public: int reverseFind(UChar, int index); int reverseFind(StringImpl*, int index, bool caseSensitive = true); - bool startsWith(StringImpl* m_data, bool caseSensitive = true) { return reverseFind(m_data, 0, caseSensitive) == 0; } + bool startsWith(StringImpl* str, bool caseSensitive = true) { return reverseFind(str, 0, caseSensitive) == 0; } bool endsWith(StringImpl*, bool caseSensitive = true); PassRefPtr<StringImpl> replace(UChar, UChar); @@ -196,21 +188,22 @@ private: void* operator new(size_t size, void* address); static PassRefPtr<StringImpl> createStrippingNullCharactersSlowCase(const UChar*, unsigned length); + + // The StringImpl struct and its data may be allocated within a single heap block. + // In this case, the m_data pointer is an "internal buffer", and does not need to be deallocated. + bool bufferIsInternal() { return m_data == reinterpret_cast<const UChar*>(this + 1); } enum StringImplFlags { HasTerminatingNullCharacter, InTable, }; - unsigned m_length; const UChar* m_data; + unsigned m_length; mutable unsigned m_hash; PtrAndFlags<SharedUChar, StringImplFlags> m_sharedBufferAndFlags; - - // In some cases, we allocate the StringImpl struct and its data - // within a single heap buffer. In this case, the m_data pointer - // is an "internal buffer", and does not need to be deallocated. - bool m_bufferIsInternal; + // There is a fictitious variable-length UChar array at the end, which is used + // as the internal buffer by the createUninitialized and create methods. }; bool equal(StringImpl*, StringImpl*); diff --git a/WebCore/platform/text/TextEncoding.cpp b/WebCore/platform/text/TextEncoding.cpp index b76f739..c5c8cfd 100644 --- a/WebCore/platform/text/TextEncoding.cpp +++ b/WebCore/platform/text/TextEncoding.cpp @@ -264,6 +264,7 @@ const TextEncoding& UTF32LittleEndianEncoding() const TextEncoding& UTF8Encoding() { static TextEncoding globalUTF8Encoding("UTF-8"); + ASSERT(globalUTF8Encoding.isValid()); return globalUTF8Encoding; } diff --git a/WebCore/platform/text/TextEncodingRegistry.cpp b/WebCore/platform/text/TextEncodingRegistry.cpp index 5ab1c87..5d82511 100644 --- a/WebCore/platform/text/TextEncodingRegistry.cpp +++ b/WebCore/platform/text/TextEncodingRegistry.cpp @@ -48,7 +48,7 @@ #if PLATFORM(QT) #include "qt/TextCodecQt.h" #endif -#if PLATFORM(WINCE) +#if PLATFORM(WINCE) && !PLATFORM(QT) #include "TextCodecWince.h" #endif @@ -194,7 +194,7 @@ static void buildBaseTextCodecMaps() TextCodecICU::registerBaseCodecs(addToTextCodecMap); #endif -#if PLATFORM(WINCE) +#if PLATFORM(WINCE) && !PLATFORM(QT) TextCodecWince::registerBaseEncodingNames(addToTextEncodingNameMap); TextCodecWince::registerBaseCodecs(addToTextCodecMap); #endif @@ -217,7 +217,7 @@ static void extendTextCodecMaps() TextCodecMac::registerCodecs(addToTextCodecMap); #endif -#if PLATFORM(WINCE) +#if PLATFORM(WINCE) && !PLATFORM(QT) TextCodecWince::registerExtendedEncodingNames(addToTextEncodingNameMap); TextCodecWince::registerExtendedCodecs(addToTextCodecMap); #endif diff --git a/WebCore/platform/text/UnicodeRange.h b/WebCore/platform/text/UnicodeRange.h index 7ecf03f..2278a0e 100644 --- a/WebCore/platform/text/UnicodeRange.h +++ b/WebCore/platform/text/UnicodeRange.h @@ -35,6 +35,10 @@ #ifndef UnicodeRange_H #define UnicodeRange_H +#if PLATFORM(HAIKU) +#include "stdint.h" +#endif + #include <wtf/unicode/Unicode.h> namespace WebCore { diff --git a/WebCore/platform/text/cf/StringCF.cpp b/WebCore/platform/text/cf/StringCF.cpp index 5e12ba9..b770d0e 100644 --- a/WebCore/platform/text/cf/StringCF.cpp +++ b/WebCore/platform/text/cf/StringCF.cpp @@ -45,7 +45,7 @@ String::String(CFStringRef str) CFStringRef String::createCFString() const { if (!m_impl) - return CFSTR(""); + return static_cast<CFStringRef>(CFRetain(CFSTR(""))); return m_impl->createCFString(); } diff --git a/WebCore/platform/text/haiku/TextBreakIteratorInternalICUHaiku.cpp b/WebCore/platform/text/haiku/TextBreakIteratorInternalICUHaiku.cpp index 2c732d6..8bb8c70 100644 --- a/WebCore/platform/text/haiku/TextBreakIteratorInternalICUHaiku.cpp +++ b/WebCore/platform/text/haiku/TextBreakIteratorInternalICUHaiku.cpp @@ -26,6 +26,12 @@ namespace WebCore { +const char* currentSearchLocaleID() +{ + notImplemented(); + return ""; +} + const char* currentTextBreakLocaleID() { notImplemented(); diff --git a/WebCore/platform/text/mac/TextCodecMac.cpp b/WebCore/platform/text/mac/TextCodecMac.cpp index 93b9da2..a1750c9 100644 --- a/WebCore/platform/text/mac/TextCodecMac.cpp +++ b/WebCore/platform/text/mac/TextCodecMac.cpp @@ -36,7 +36,7 @@ #include <wtf/PassOwnPtr.h> #include <wtf/Threading.h> -using std::min; +using namespace std; namespace WebCore { @@ -141,7 +141,7 @@ OSStatus TextCodecMac::decode(const unsigned char* inputBuffer, int inputBufferL // First, fill the partial character buffer with as many bytes as are available. ASSERT(m_numBufferedBytes < sizeof(m_bufferedBytes)); const int spaceInBuffer = sizeof(m_bufferedBytes) - m_numBufferedBytes; - const int bytesToPutInBuffer = MIN(spaceInBuffer, inputBufferLength); + const int bytesToPutInBuffer = min(spaceInBuffer, inputBufferLength); ASSERT(bytesToPutInBuffer != 0); memcpy(m_bufferedBytes + m_numBufferedBytes, inputBuffer, bytesToPutInBuffer); @@ -283,28 +283,28 @@ CString TextCodecMac::encode(const UChar* characters, size_t length, Unencodable // Encoding will change the yen sign back into a backslash. String copy(characters, length); copy.replace('\\', m_backslashAsCurrencySymbol); - CFStringRef cfs = copy.createCFString(); + RetainPtr<CFStringRef> cfs(AdoptCF, copy.createCFString()); CFIndex startPos = 0; - CFIndex charactersLeft = CFStringGetLength(cfs); + CFIndex charactersLeft = CFStringGetLength(cfs.get()); Vector<char> result; size_t size = 0; UInt8 lossByte = handling == QuestionMarksForUnencodables ? '?' : 0; while (charactersLeft > 0) { CFRange range = CFRangeMake(startPos, charactersLeft); CFIndex bufferLength; - CFStringGetBytes(cfs, range, m_encoding, lossByte, false, NULL, 0x7FFFFFFF, &bufferLength); + CFStringGetBytes(cfs.get(), range, m_encoding, lossByte, false, NULL, 0x7FFFFFFF, &bufferLength); result.grow(size + bufferLength); unsigned char* buffer = reinterpret_cast<unsigned char*>(result.data() + size); - CFIndex charactersConverted = CFStringGetBytes(cfs, range, m_encoding, lossByte, false, buffer, bufferLength, &bufferLength); + CFIndex charactersConverted = CFStringGetBytes(cfs.get(), range, m_encoding, lossByte, false, buffer, bufferLength, &bufferLength); size += bufferLength; if (charactersConverted != charactersLeft) { - unsigned badChar = CFStringGetCharacterAtIndex(cfs, startPos + charactersConverted); + unsigned badChar = CFStringGetCharacterAtIndex(cfs.get(), startPos + charactersConverted); ++charactersConverted; if ((badChar & 0xFC00) == 0xD800 && charactersConverted != charactersLeft) { // is high surrogate - UniChar low = CFStringGetCharacterAtIndex(cfs, startPos + charactersConverted); + UniChar low = CFStringGetCharacterAtIndex(cfs.get(), startPos + charactersConverted); if ((low & 0xFC00) == 0xDC00) { // is low surrogate badChar <<= 10; badChar += low; @@ -322,7 +322,6 @@ CString TextCodecMac::encode(const UChar* characters, size_t length, Unencodable startPos += charactersConverted; charactersLeft -= charactersConverted; } - CFRelease(cfs); return CString(result.data(), size); } diff --git a/WebCore/platform/text/qt/TextCodecQt.cpp b/WebCore/platform/text/qt/TextCodecQt.cpp index c6c02cf..b3f75cc 100644 --- a/WebCore/platform/text/qt/TextCodecQt.cpp +++ b/WebCore/platform/text/qt/TextCodecQt.cpp @@ -94,7 +94,26 @@ TextCodecQt::~TextCodecQt() String TextCodecQt::decode(const char* bytes, size_t length, bool flush, bool /*stopOnError*/, bool& sawError) { - QString unicode = m_codec->toUnicode(bytes, length, &m_state); + // We chop input buffer to smaller buffers to avoid excessive memory consumption + // when the input buffer is big. This helps reduce peak memory consumption in + // mobile devices where system RAM is limited. +#if PLATFORM(SYMBIAN) + static const int MaxInputChunkSize = 32 * 1024; +#else + static const int MaxInputChunkSize = 1024 * 1024; +#endif + const char* buf = bytes; + const char* end = buf + length; + String unicode(""); // a non-null string is expected + + while (buf < end) { + int size = end - buf; + size = qMin(size, MaxInputChunkSize); + QString decoded = m_codec->toUnicode(buf, size, &m_state); + unicode.append(decoded); + buf += size; + } + sawError = m_state.invalidChars != 0; if (flush) { diff --git a/WebCore/platform/win/ClipboardWin.cpp b/WebCore/platform/win/ClipboardWin.cpp index 65741e4..b2e8e3e 100644 --- a/WebCore/platform/win/ClipboardWin.cpp +++ b/WebCore/platform/win/ClipboardWin.cpp @@ -117,56 +117,49 @@ static inline void pathRemoveBadFSCharacters(PWSTR psz, size_t length) static String filesystemPathFromUrlOrTitle(const String& url, const String& title, TCHAR* extension, bool isLink) { + static const size_t fsPathMaxLengthExcludingNullTerminator = MAX_PATH - 1; bool usedURL = false; - WCHAR fsPathBuffer[MAX_PATH + 1]; + WCHAR fsPathBuffer[MAX_PATH]; fsPathBuffer[0] = 0; int extensionLen = extension ? lstrlen(extension) : 0; + int fsPathMaxLengthExcludingExtension = fsPathMaxLengthExcludingNullTerminator - extensionLen; if (!title.isEmpty()) { - size_t len = min<size_t>(title.length(), MAX_PATH - extensionLen); + size_t len = min<size_t>(title.length(), fsPathMaxLengthExcludingExtension); CopyMemory(fsPathBuffer, title.characters(), len * sizeof(UChar)); fsPathBuffer[len] = 0; pathRemoveBadFSCharacters(fsPathBuffer, len); } if (!lstrlen(fsPathBuffer)) { - DWORD len = MAX_PATH; - String nullTermURL = url; + KURL kurl(ParsedURLString, 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); + // The filename for any content based drag or file url 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. + DWORD len = fsPathMaxLengthExcludingExtension; + String lastComponent = kurl.lastPathComponent(); + if (kurl.isLocalFile() || (!isLink && !lastComponent.isEmpty())) { + len = min<DWORD>(fsPathMaxLengthExcludingExtension, lastComponent.length()); + CopyMemory(fsPathBuffer, lastComponent.characters(), len * sizeof(UChar)); } 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); + len = min<DWORD>(fsPathMaxLengthExcludingExtension, url.length()); + CopyMemory(fsPathBuffer, url.characters(), len * sizeof(UChar)); } + fsPathBuffer[len] = 0; + pathRemoveBadFSCharacters(fsPathBuffer, len); } if (!extension) - return String((UChar*)fsPathBuffer); + return String(static_cast<UChar*>(fsPathBuffer)); if (!isLink && usedURL) { PathRenameExtension(fsPathBuffer, extension); - return String((UChar*)fsPathBuffer); + return String(static_cast<UChar*>(fsPathBuffer)); } - String result((UChar*)fsPathBuffer); - result += String((UChar*)extension); + String result(static_cast<UChar*>(fsPathBuffer)); + result += String(static_cast<UChar*>(extension)); return result; } @@ -522,7 +515,7 @@ bool ClipboardWin::setData(const String& type, const String& data) ClipboardDataType winType = clipboardTypeFromMIMEType(type); if (winType == ClipboardDataTypeURL) - return WebCore::writeURL(m_writableDataObject.get(), KURL(data), String(), false, true); + return WebCore::writeURL(m_writableDataObject.get(), KURL(ParsedURLString, data), String(), false, true); if (winType == ClipboardDataTypeText) { STGMEDIUM medium = {0}; diff --git a/WebCore/platform/win/CursorWin.cpp b/WebCore/platform/win/CursorWin.cpp index 2bfe7a8..5afb1ae9 100644 --- a/WebCore/platform/win/CursorWin.cpp +++ b/WebCore/platform/win/CursorWin.cpp @@ -279,7 +279,7 @@ const Cursor& rowResizeCursor() const Cursor& middlePanningCursor() { - static const Cursor c = loadCursorByName("panIcon", 7, 7); + static const Cursor c = loadCursorByName("panIcon", 8, 8); return c; } diff --git a/WebCore/platform/win/PasteboardWin.cpp b/WebCore/platform/win/PasteboardWin.cpp index 188630f..d09769a 100644 --- a/WebCore/platform/win/PasteboardWin.cpp +++ b/WebCore/platform/win/PasteboardWin.cpp @@ -111,7 +111,7 @@ void Pasteboard::clear() void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame) { clear(); - + // Put CF_HTML format on the pasteboard if (::OpenClipboard(m_owner)) { ExceptionCode ec = 0; @@ -145,6 +145,21 @@ void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, } } +void Pasteboard::writePlainText(const String& text) +{ + clear(); + + // Put plain string on the pasteboard. CF_UNICODETEXT covers CF_TEXT as well + String str = text; + replaceNewlinesWithWindowsStyleNewlines(str); + if (::OpenClipboard(m_owner)) { + HGLOBAL cbData = createGlobalData(str); + if (!::SetClipboardData(CF_UNICODETEXT, cbData)) + ::GlobalFree(cbData); + ::CloseClipboard(); + } +} + void Pasteboard::writeURL(const KURL& url, const String& titleStr, Frame* frame) { ASSERT(!url.isEmpty()); diff --git a/WebCore/platform/win/PlatformScreenWin.cpp b/WebCore/platform/win/PlatformScreenWin.cpp index 7ac4706..6e0f861 100644 --- a/WebCore/platform/win/PlatformScreenWin.cpp +++ b/WebCore/platform/win/PlatformScreenWin.cpp @@ -39,7 +39,7 @@ namespace WebCore { // Returns info for the default monitor if widget is NULL static MONITORINFOEX monitorInfoForWidget(Widget* widget) { - HWND window = widget ? widget->root()->hostWindow()->platformWindow() : 0; + HWND window = widget ? widget->root()->hostWindow()->platformPageClient() : 0; HMONITOR monitor = MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY); MONITORINFOEX monitorInfo; diff --git a/WebCore/platform/win/PopupMenuWin.cpp b/WebCore/platform/win/PopupMenuWin.cpp index e53053f..1d9eb71 100644 --- a/WebCore/platform/win/PopupMenuWin.cpp +++ b/WebCore/platform/win/PopupMenuWin.cpp @@ -40,6 +40,7 @@ #include "SimpleFontData.h" #include <tchar.h> #include <windows.h> +#include <windowsx.h> #if PLATFORM(WINCE) #include <ResDefCE.h> #define MAKEPOINTS(l) (*((POINTS FAR *)&(l))) @@ -60,8 +61,13 @@ const int optionSpacingMiddle = 1; const int popupWindowBorderWidth = 1; static LPCTSTR kPopupWindowClassName = _T("PopupWindowClass"); -static ATOM registerPopup(); -static LRESULT CALLBACK PopupWndProc(HWND, UINT, WPARAM, LPARAM); + +// This is used from within our custom message pump when we want to send a +// message to the web view and not have our message stolen and sent to +// the popup window. +static const UINT WM_HOST_WINDOW_FIRST = WM_USER; +static const UINT WM_HOST_WINDOW_CHAR = WM_USER + WM_CHAR; +static const UINT WM_HOST_WINDOW_MOUSEMOVE = WM_USER + WM_MOUSEMOVE; // FIXME: Remove this as soon as practical. static inline bool isASCIIPrintable(unsigned c) @@ -69,6 +75,15 @@ static inline bool isASCIIPrintable(unsigned c) return c >= 0x20 && c <= 0x7E; } +static void translatePoint(LPARAM& lParam, HWND from, HWND to) +{ + POINT pt; + pt.x = (short)GET_X_LPARAM(lParam); + pt.y = (short)GET_Y_LPARAM(lParam); + ::MapWindowPoints(from, to, &pt, 1); + lParam = MAKELPARAM(pt.x, pt.y); +} + PopupMenu::PopupMenu(PopupMenuClient* client) : m_popupClient(client) , m_scrollbar(0) @@ -81,6 +96,7 @@ PopupMenu::PopupMenu(PopupMenuClient* client) , m_wheelDelta(0) , m_focusedIndex(0) , m_scrollbarCapturingMouse(false) + , m_showPopup(false) { } @@ -92,44 +108,46 @@ PopupMenu::~PopupMenu() ::DeleteDC(m_DC); if (m_popup) ::DestroyWindow(m_popup); + if (m_scrollbar) + m_scrollbar->setParent(0); +} + +LPCTSTR PopupMenu::popupClassName() +{ + return kPopupWindowClassName; } -void PopupMenu::show(const IntRect& r, FrameView* v, int index) +void PopupMenu::show(const IntRect& r, FrameView* view, int index) { - calculatePositionAndSize(r, v); + calculatePositionAndSize(r, view); if (clientRect().isEmpty()) return; + HWND hostWindow = view->hostWindow()->platformPageClient(); + + if (!m_scrollbar && visibleItems() < client()->listSize()) { + // We need a scroll bar + m_scrollbar = client()->createScrollbar(this, VerticalScrollbar, SmallScrollbar); + m_scrollbar->styleChanged(); + } + if (!m_popup) { - registerPopup(); + registerClass(); DWORD exStyle = 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->hostWindow()->platformWindow(), 0, 0, 0); + m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height(), + hostWindow, 0, Page::instanceHandle(), this); if (!m_popup) return; - -#if PLATFORM(WINCE) - ::SetWindowLong(m_popup, 0, (LONG)this); -#else - ::SetWindowLongPtr(m_popup, 0, (LONG_PTR)this); -#endif + } else { + // We need to reposition the popup window. + ::MoveWindow(m_popup, m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height(), false); } - if (!m_scrollbar) - if (visibleItems() < client()->listSize()) { - // We need a scroll bar - m_scrollbar = client()->createScrollbar(this, VerticalScrollbar, SmallScrollbar); - } - - ::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; @@ -138,30 +156,127 @@ void PopupMenu::show(const IntRect& r, FrameView* v, int index) if (shouldAnimate) { RECT viewRect = {0}; - ::GetWindowRect(v->hostWindow()->platformWindow(), &viewRect); + ::GetWindowRect(hostWindow, &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; + DWORD slideDirection = (m_windowRect.y() < viewRect.top + view->contentsToWindow(r.location()).y()) ? AW_VER_NEGATIVE : AW_VER_POSITIVE; - ::AnimateWindow(m_popup, defaultAnimationDuration, AW_SLIDE | slideDirection | AW_ACTIVATE); + ::AnimateWindow(m_popup, defaultAnimationDuration, AW_SLIDE | slideDirection); } } else #endif - ::ShowWindow(m_popup, SW_SHOWNORMAL); - ::SetCapture(m_popup); + ::ShowWindow(m_popup, SW_SHOWNOACTIVATE); if (client()) { int index = client()->selectedIndex(); if (index >= 0) setFocusedIndex(index); } + + m_showPopup = true; + + // Protect the popup menu in case its owner is destroyed while we're running the message pump. + RefPtr<PopupMenu> protect(this); + + ::SetCapture(hostWindow); + + MSG msg; + HWND activeWindow; + + while (::GetMessage(&msg, 0, 0, 0)) { + switch (msg.message) { + case WM_HOST_WINDOW_MOUSEMOVE: + case WM_HOST_WINDOW_CHAR: + if (msg.hwnd == m_popup) { + // This message should be sent to the host window. + msg.hwnd = hostWindow; + msg.message -= WM_HOST_WINDOW_FIRST; + } + break; + + // Steal mouse messages. + case WM_NCMOUSEMOVE: + case WM_NCLBUTTONDOWN: + case WM_NCLBUTTONUP: + case WM_NCLBUTTONDBLCLK: + case WM_NCRBUTTONDOWN: + case WM_NCRBUTTONUP: + case WM_NCRBUTTONDBLCLK: + case WM_NCMBUTTONDOWN: + case WM_NCMBUTTONUP: + case WM_NCMBUTTONDBLCLK: + case WM_MOUSEWHEEL: + msg.hwnd = m_popup; + break; + + // These mouse messages use client coordinates so we need to convert them. + case WM_MOUSEMOVE: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_LBUTTONDBLCLK: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_RBUTTONDBLCLK: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_MBUTTONDBLCLK: { + // Translate the coordinate. + translatePoint(msg.lParam, msg.hwnd, m_popup); + + msg.hwnd = m_popup; + break; + } + + // Steal all keyboard messages. + case WM_KEYDOWN: + case WM_KEYUP: + case WM_CHAR: + case WM_DEADCHAR: + case WM_SYSKEYUP: + case WM_SYSCHAR: + case WM_SYSDEADCHAR: + msg.hwnd = m_popup; + break; + } + + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + + if (!m_popupClient) + break; + + if (!m_showPopup) + break; + activeWindow = ::GetActiveWindow(); + if (activeWindow != hostWindow && !::IsChild(activeWindow, hostWindow)) + break; + if (::GetCapture() != hostWindow) + break; + } + + if (::GetCapture() == hostWindow) + ::ReleaseCapture(); + + // We're done, hide the popup if necessary. + hide(); } void PopupMenu::hide() { + if (!m_showPopup) + return; + + m_showPopup = false; + ::ShowWindow(m_popup, SW_HIDE); + + if (client()) + client()->popupDidHide(); + + // Post a WM_NULL message to wake up the message pump if necessary. + ::PostMessage(m_popup, WM_NULL, 0, 0); } const int endOfLinePadding = 2; @@ -174,7 +289,7 @@ void PopupMenu::calculatePositionAndSize(const IntRect& r, FrameView* v) // Then, translate to screen coordinates POINT location(rScreenCoords.location()); - if (!::ClientToScreen(v->hostWindow()->platformWindow(), &location)) + if (!::ClientToScreen(v->hostWindow()->platformPageClient(), &location)) return; rScreenCoords.setLocation(location); @@ -591,12 +706,12 @@ void PopupMenu::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rec ::InvalidateRect(m_popup, &r, false); } -static ATOM registerPopup() +void PopupMenu::registerClass() { static bool haveRegisteredWindowClass = false; if (haveRegisteredWindowClass) - return true; + return; #if PLATFORM(WINCE) WNDCLASS wcex; @@ -607,7 +722,7 @@ static ATOM registerPopup() wcex.style = CS_DROPSHADOW; #endif - wcex.lpfnWndProc = PopupWndProc; + wcex.lpfnWndProc = PopupMenuWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = sizeof(PopupMenu*); // For the PopupMenu pointer wcex.hInstance = Page::instanceHandle(); @@ -620,228 +735,262 @@ static ATOM registerPopup() haveRegisteredWindowClass = true; #if PLATFORM(WINCE) - return ::RegisterClass(&wcex); + RegisterClass(&wcex); #else - return ::RegisterClassEx(&wcex); + RegisterClassEx(&wcex); #endif } -const int smoothScrollAnimationDuration = 5000; -static LRESULT CALLBACK PopupWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) + +LRESULT CALLBACK PopupMenu::PopupMenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - LRESULT lResult = 0; #if PLATFORM(WINCE) LONG longPtr = GetWindowLong(hWnd, 0); #else LONG_PTR longPtr = GetWindowLongPtr(hWnd, 0); #endif - PopupMenu* popup = reinterpret_cast<PopupMenu*>(longPtr); + + if (PopupMenu* popup = reinterpret_cast<PopupMenu*>(longPtr)) + return popup->wndProc(hWnd, message, wParam, lParam); + + if (message == WM_CREATE) { + LPCREATESTRUCT createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam); + + // Associate the PopupMenu with the window. +#if PLATFORM(WINCE) + ::SetWindowLong(hWnd, 0, (LONG)createStruct->lpCreateParams); +#else + ::SetWindowLongPtr(hWnd, 0, (LONG_PTR)createStruct->lpCreateParams); +#endif + return 0; + } + + return ::DefWindowProc(hWnd, message, wParam, lParam); +} + +const int smoothScrollAnimationDuration = 5000; + +LRESULT PopupMenu::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + LRESULT lResult = 0; switch (message) { - case WM_SIZE: - if (popup && popup->scrollbar()) { - IntSize size(LOWORD(lParam), HIWORD(lParam)); - popup->scrollbar()->setFrameRect(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(); + case WM_MOUSEACTIVATE: + return MA_NOACTIVATE; + + case WM_SIZE: { + if (!scrollbar()) + break; + + IntSize size(LOWORD(lParam), HIWORD(lParam)); + scrollbar()->setFrameRect(IntRect(size.width() - scrollbar()->width(), 0, scrollbar()->width(), size.height())); + + int visibleItems = this->visibleItems(); + scrollbar()->setEnabled(visibleItems < client()->listSize()); + scrollbar()->setSteps(1, max(1, visibleItems - 1)); + scrollbar()->setProportion(visibleItems, client()->listSize()); + 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()->hostWindow()->platformWindow(), message, wParam, lParam); - popup->client()->hidePopup(); - break; - case VK_ESCAPE: - 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()->hostWindow()->platformWindow(), message, wParam, lParam); - else - lResult = 1; - break; + if (!client()) + break; + + lResult = 0; + switch (LOWORD(wParam)) { + case VK_DOWN: + case VK_RIGHT: + down(); + break; + case VK_UP: + case VK_LEFT: + up(); + break; + case VK_HOME: + focusFirst(); + break; + case VK_END: + focusLast(); + break; + case VK_PRIOR: + if (focusedIndex() != scrollOffset()) { + // Set the selection to the first visible item + int firstVisibleItem = scrollOffset(); + up(focusedIndex() - firstVisibleItem); + } else { + // The first visible item is selected, so move the selection back one page + up(visibleItems()); + } + break; + case VK_NEXT: { + int lastVisibleItem = scrollOffset() + visibleItems() - 1; + if (focusedIndex() != lastVisibleItem) { + // Set the selection to the last visible item + down(lastVisibleItem - focusedIndex()); + } else { + // The last visible item is selected, so move the selection forward one page + down(visibleItems()); + } + break; } + case VK_TAB: + ::SendMessage(client()->hostWindow()->platformPageClient(), message, wParam, lParam); + hide(); + break; + case VK_ESCAPE: + hide(); + break; + default: + if (isASCIIPrintable(wParam)) + // Send the keydown to the WebView so it can be used for type-to-select. + // Since we know that the virtual key is ASCII printable, it's OK to convert this to + // a WM_CHAR message. (We don't want to call TranslateMessage because that will post a + // WM_CHAR message that will be stolen and redirected to the popup HWND. + ::PostMessage(m_popup, WM_HOST_WINDOW_CHAR, 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; - } + case WM_CHAR: { + if (!client()) + break; + + lResult = 0; + int index; + switch (wParam) { + case 0x0D: // Enter/Return + hide(); + index = focusedIndex(); + ASSERT(index >= 0); + client()->valueChanged(index); + break; + case 0x1B: // Escape + hide(); + 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()->frameRect(); - 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()->mouseMoved(event); - break; - } + } + case WM_MOUSEMOVE: { + IntPoint mousePoint(MAKEPOINTS(lParam)); + if (scrollbar()) { + IntRect scrollBarRect = scrollbar()->frameRect(); + if (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())); + scrollbar()->mouseMoved(event); + break; } + } - BOOL shouldHotTrack = FALSE; + BOOL shouldHotTrack = FALSE; #if !PLATFORM(WINCE) - ::SystemParametersInfo(SPI_GETHOTTRACKING, 0, &shouldHotTrack, 0); + ::SystemParametersInfo(SPI_GETHOTTRACKING, 0, &shouldHotTrack, 0); #endif - RECT bounds; - GetClientRect(popup->popupHandle(), &bounds); - if ((shouldHotTrack || wParam & MK_LBUTTON) && ::PtInRect(&bounds, mousePoint)) - popup->setFocusedIndex(popup->listIndexAtPoint(mousePoint), true); + RECT bounds; + GetClientRect(popupHandle(), &bounds); + if (!::PtInRect(&bounds, mousePoint) && !(wParam & MK_LBUTTON) && client()) { + // When the mouse is not inside the popup menu and the left button isn't down, just + // repost the message to the web view. - // 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; - } + // Translate the coordinate. + translatePoint(lParam, m_popup, client()->hostWindow()->platformPageClient()); + + ::PostMessage(m_popup, WM_HOST_WINDOW_MOUSEMOVE, wParam, lParam); + break; } + + if ((shouldHotTrack || wParam & MK_LBUTTON) && ::PtInRect(&bounds, mousePoint)) + setFocusedIndex(listIndexAtPoint(mousePoint), true); + break; - case WM_LBUTTONDOWN: - if (popup) { - ::SetCapture(popup->popupHandle()); - IntPoint mousePoint(MAKEPOINTS(lParam)); - if (popup->scrollbar()) { - IntRect scrollBarRect = popup->scrollbar()->frameRect(); - 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()->mouseDown(event); - popup->setScrollbarCapturingMouse(true); - break; - } + } + case WM_LBUTTONDOWN: { + IntPoint mousePoint(MAKEPOINTS(lParam)); + if (scrollbar()) { + IntRect scrollBarRect = scrollbar()->frameRect(); + 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())); + scrollbar()->mouseDown(event); + setScrollbarCapturingMouse(true); + break; } - - popup->setFocusedIndex(popup->listIndexAtPoint(mousePoint), true); } + + // If the mouse is inside the window, update the focused index. Otherwise, + // hide the popup. + RECT bounds; + GetClientRect(m_popup, &bounds); + if (::PtInRect(&bounds, mousePoint)) + setFocusedIndex(listIndexAtPoint(mousePoint), true); + else + hide(); break; - case WM_LBUTTONUP: - if (popup) { - IntPoint mousePoint(MAKEPOINTS(lParam)); - if (popup->scrollbar()) { - ::ReleaseCapture(); - IntRect scrollBarRect = popup->scrollbar()->frameRect(); - 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()->mouseUp(); - // FIXME: This is a hack to work around Scrollbar 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); + } + case WM_LBUTTONUP: { + IntPoint mousePoint(MAKEPOINTS(lParam)); + if (scrollbar()) { + IntRect scrollBarRect = scrollbar()->frameRect(); + if (scrollbarCapturingMouse() || scrollBarRect.contains(mousePoint)) { + 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())); + scrollbar()->mouseUp(); + // FIXME: This is a hack to work around Scrollbar not invalidating correctly when it doesn't have a parent widget + RECT r = scrollBarRect; + ::InvalidateRect(popupHandle(), &r, TRUE); + break; } } + // Only hide the popup if the mouse is inside the popup window. + RECT bounds; + GetClientRect(popupHandle(), &bounds); + if (client() && ::PtInRect(&bounds, mousePoint)) { + hide(); + int index = focusedIndex(); + if (index >= 0) + 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; + } + + case WM_MOUSEWHEEL: { + if (!scrollbar()) + break; - popup->scrollbar()->scroll(i > 0 ? ScrollUp : ScrollDown, ScrollByLine, abs(i)); + int i = 0; + for (incrementWheelDelta(GET_WHEEL_DELTA_WPARAM(wParam)); abs(wheelDelta()) >= WHEEL_DELTA; reduceWheelDelta(WHEEL_DELTA)) { + if (wheelDelta() > 0) + ++i; + else + --i; } + 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; - } + } + + case WM_PAINT: { + PAINTSTRUCT paintInfo; + ::BeginPaint(popupHandle(), &paintInfo); + paint(paintInfo.rcPaint, paintInfo.hdc); + ::EndPaint(popupHandle(), &paintInfo); + lResult = 0; break; + } #if !PLATFORM(WINCE) case WM_PRINTCLIENT: - if (popup) - popup->paint(popup->clientRect(), (HDC)wParam); + paint(clientRect(), (HDC)wParam); break; #endif default: diff --git a/WebCore/platform/win/SharedBufferWin.cpp b/WebCore/platform/win/SharedBufferWin.cpp index ce93402..1839c99 100644 --- a/WebCore/platform/win/SharedBufferWin.cpp +++ b/WebCore/platform/win/SharedBufferWin.cpp @@ -38,8 +38,8 @@ PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String& fi 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()); + if (_wfopen_s(&fileDescriptor, nullifiedPath.charactersWithNullTermination(), TEXT("rb")) || !fileDescriptor) { + LOG_ERROR("Failed to open file %s to create shared buffer, errno(%i)", filePath.ascii().data(), errno); return 0; } diff --git a/WebCore/platform/win/SharedTimerWin.cpp b/WebCore/platform/win/SharedTimerWin.cpp index da27a53..bc634f9 100644 --- a/WebCore/platform/win/SharedTimerWin.cpp +++ b/WebCore/platform/win/SharedTimerWin.cpp @@ -27,6 +27,7 @@ #include "SharedTimer.h" #include "Page.h" +#include "Settings.h" #include "Widget.h" #include <wtf/Assertions.h> #include <wtf/CurrentTime.h> @@ -160,35 +161,38 @@ void setSharedTimerFireTime(double fireTime) intervalInMS = (unsigned)interval; } - if (interval < highResolutionThresholdMsec) { - if (!highResTimerActive) { - highResTimerActive = true; - timeBeginPeriod(timerResolution); - } - SetTimer(timerWindowHandle, endHighResTimerID, stopHighResTimerInMsec, 0); - } - initializeOffScreenTimerWindow(); bool timerSet = false; - DWORD queueStatus = LOWORD(GetQueueStatus(QS_PAINT | QS_MOUSEBUTTON | QS_KEY | QS_RAWINPUT)); - - // Win32 has a tri-level queue with application messages > user input > WM_PAINT/WM_TIMER. - - // If the queue doesn't contains input events, we use a higher priorty timer event posting mechanism. - if (!(queueStatus & (QS_MOUSEBUTTON | QS_KEY | QS_RAWINPUT))) { - if (intervalInMS < USER_TIMER_MINIMUM && !processingCustomTimerMessage && !(queueStatus & QS_PAINT)) { - // Call PostMessage immediately if the timer is already expired, unless a paint is pending. - // (we prioritize paints over timers) - if (InterlockedIncrement(&pendingTimers) == 1) - PostMessage(timerWindowHandle, timerFiredMessage, 0, 0); - timerSet = true; - } else { - // Otherwise, delay the PostMessage via a CreateTimerQueueTimer - if (!timerQueue) - timerQueue = CreateTimerQueue(); - if (timer) - DeleteTimerQueueTimer(timerQueue, timer, 0); - timerSet = CreateTimerQueueTimer(&timer, timerQueue, queueTimerProc, 0, intervalInMS, 0, WT_EXECUTEINTIMERTHREAD | WT_EXECUTEONLYONCE); + + if (Settings::shouldUseHighResolutionTimers()) { + if (interval < highResolutionThresholdMsec) { + if (!highResTimerActive) { + highResTimerActive = true; + timeBeginPeriod(timerResolution); + } + SetTimer(timerWindowHandle, endHighResTimerID, stopHighResTimerInMsec, 0); + } + + DWORD queueStatus = LOWORD(GetQueueStatus(QS_PAINT | QS_MOUSEBUTTON | QS_KEY | QS_RAWINPUT)); + + // Win32 has a tri-level queue with application messages > user input > WM_PAINT/WM_TIMER. + + // If the queue doesn't contains input events, we use a higher priorty timer event posting mechanism. + if (!(queueStatus & (QS_MOUSEBUTTON | QS_KEY | QS_RAWINPUT))) { + if (intervalInMS < USER_TIMER_MINIMUM && !processingCustomTimerMessage && !(queueStatus & QS_PAINT)) { + // Call PostMessage immediately if the timer is already expired, unless a paint is pending. + // (we prioritize paints over timers) + if (InterlockedIncrement(&pendingTimers) == 1) + PostMessage(timerWindowHandle, timerFiredMessage, 0, 0); + timerSet = true; + } else { + // Otherwise, delay the PostMessage via a CreateTimerQueueTimer + if (!timerQueue) + timerQueue = CreateTimerQueue(); + if (timer) + DeleteTimerQueueTimer(timerQueue, timer, 0); + timerSet = CreateTimerQueueTimer(&timer, timerQueue, queueTimerProc, 0, intervalInMS, 0, WT_EXECUTEINTIMERTHREAD | WT_EXECUTEONLYONCE); + } } } diff --git a/WebCore/platform/wince/CursorWince.cpp b/WebCore/platform/wince/CursorWince.cpp new file mode 100644 index 0000000..e35f1f9 --- /dev/null +++ b/WebCore/platform/wince/CursorWince.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2008-2009 Torch Mobile 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 "Cursor.h" + +namespace WebCore { + +struct AllCursors { + AllCursors() + { + for (int i = 0; i < NumCursorTypes; ++i) + m_cursors[i] = (CursorType) i; + } + Cursor m_cursors[NumCursorTypes]; +}; + +static const Cursor& getCursor(CursorType type) +{ + static AllCursors allCursors; + return allCursors.m_cursors[type]; +} + +Cursor::Cursor(const Cursor& other) +: m_impl(other.m_impl) +{ +} + +Cursor::Cursor(Image* img, const IntPoint& hotspot) +: m_impl(CursorNone) +{ +} + +Cursor::~Cursor() +{ +} + +Cursor& Cursor::operator=(const Cursor& other) +{ + m_impl = other.m_impl; + return *this; +} + +Cursor::Cursor(PlatformCursor c) +: m_impl(c) +{ +} + +const Cursor& noneCursor() { return getCursor(CursorNone); } +const Cursor& pointerCursor() { return getCursor(CursorPointer); } +const Cursor& crossCursor() { return getCursor(CursorCross); } +const Cursor& handCursor() { return getCursor(CursorHand); } +const Cursor& iBeamCursor() { return getCursor(CursorBeam); } +const Cursor& waitCursor() { return getCursor(CursorWait); } +const Cursor& helpCursor() { return getCursor(CursorHelp); } +const Cursor& moveCursor() { return getCursor(CursorMove); } +const Cursor& eastResizeCursor() { return getCursor(CursorEastResize); } +const Cursor& northResizeCursor() { return getCursor(CursorNorthResize); } +const Cursor& northEastResizeCursor() { return getCursor(CursorNorthEastResize); } +const Cursor& northWestResizeCursor() { return getCursor(CursorNorthWestResize); } +const Cursor& southResizeCursor() { return getCursor(CursorSouthResize); } +const Cursor& southEastResizeCursor() { return getCursor(CursorSouthEastResize); } +const Cursor& southWestResizeCursor() { return getCursor(CursorSouthWestResize); } +const Cursor& westResizeCursor() { return getCursor(CursorWestResize); } +const Cursor& northSouthResizeCursor() { return getCursor(CursorNorthSouthResize); } +const Cursor& eastWestResizeCursor() { return getCursor(CursorEastWestResize); } +const Cursor& northEastSouthWestResizeCursor() { return getCursor(CursorNorthEastSouthWestResize); } +const Cursor& northWestSouthEastResizeCursor() { return getCursor(CursorNorthWestSouthEastResize); } +const Cursor& columnResizeCursor() { return getCursor(CursorColumnResize); } +const Cursor& rowResizeCursor() { return getCursor(CursorRowResize); } +const Cursor& verticalTextCursor() { return getCursor(CursorVerticalText); } +const Cursor& cellCursor() { return getCursor(CursorCell); } +const Cursor& contextMenuCursor() { return getCursor(CursorContextMenu); } +const Cursor& noDropCursor() { return getCursor(CursorNoDrop); } +const Cursor& notAllowedCursor() { return getCursor(CursorNotAllowed); } +const Cursor& progressCursor() { return getCursor(CursorProgress); } +const Cursor& aliasCursor() { return getCursor(CursorAlias); } +const Cursor& zoomInCursor() { return getCursor(CursorZoomIn); } +const Cursor& zoomOutCursor() { return getCursor(CursorZoomOut); } +const Cursor& copyCursor() { return getCursor(CursorCopy); } +const Cursor& middlePanningCursor() { return crossCursor(); } +const Cursor& eastPanningCursor() { return crossCursor(); } +const Cursor& northPanningCursor() { return crossCursor(); } +const Cursor& northEastPanningCursor() { return crossCursor(); } +const Cursor& northWestPanningCursor() { return crossCursor(); } +const Cursor& southPanningCursor() { return crossCursor(); } +const Cursor& southEastPanningCursor() { return crossCursor(); } +const Cursor& southWestPanningCursor() { return crossCursor(); } +const Cursor& westPanningCursor() { return crossCursor(); } +const Cursor& grabbingCursor() { return moveCursor(); } +const Cursor& grabCursor() { return moveCursor(); } + +} diff --git a/WebCore/platform/wince/DragDataWince.cpp b/WebCore/platform/wince/DragDataWince.cpp new file mode 100644 index 0000000..881d7d4 --- /dev/null +++ b/WebCore/platform/wince/DragDataWince.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2007-2008 Torch Mobile, 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 "DragData.h" + +#include "Clipboard.h" +#include "DocumentFragment.h" +#include "PlatformString.h" + +namespace WebCore { + +PassRefPtr<Clipboard> DragData::createClipboard(ClipboardAccessPolicy policy) const +{ + return 0; +} + +bool DragData::containsURL() const +{ + return false; +} + +String DragData::asURL(String* title) const +{ + return String(); +} + +bool DragData::containsFiles() const +{ + return false; +} + +void DragData::asFilenames(Vector<String>&) const +{ +} + +bool DragData::containsPlainText() const +{ + return false; +} + +String DragData::asPlainText() const +{ + return String(); +} + +bool DragData::containsColor() const +{ + return false; +} + +bool DragData::canSmartReplace() const +{ + return false; +} + +bool DragData::containsCompatibleContent() const +{ + return false; +} + +PassRefPtr<DocumentFragment> DragData::asFragment(Document* doc) const +{ + return 0; +} + +Color DragData::asColor() const +{ + return Color(); +} + +} + diff --git a/WebCore/platform/wince/DragImageWince.cpp b/WebCore/platform/wince/DragImageWince.cpp new file mode 100644 index 0000000..4d60f80 --- /dev/null +++ b/WebCore/platform/wince/DragImageWince.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007-2008 Torch Mobile, 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 "DragImage.h" + +#include "CachedImage.h" +#include "GraphicsContext.h" +#include "Image.h" + +#include <windows.h> + +namespace WebCore { + +IntSize dragImageSize(DragImageRef) +{ + return IntSize(0, 0); +} + +void deleteDragImage(DragImageRef image) +{ + if (image) + ::DeleteObject(image); +} + +DragImageRef scaleDragImage(DragImageRef, FloatSize) +{ + return 0; +} + +DragImageRef dissolveDragImageToFraction(DragImageRef image, float) +{ + return image; +} + +DragImageRef createDragImageFromImage(Image*) +{ + return 0; +} + +DragImageRef createDragImageIconForCachedImage(CachedImage*) +{ + return 0; +} + +} diff --git a/WebCore/platform/wince/EditorWince.cpp b/WebCore/platform/wince/EditorWince.cpp new file mode 100644 index 0000000..02af780 --- /dev/null +++ b/WebCore/platform/wince/EditorWince.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2007-2008 Torch Mobile, 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 "Editor.h" + +#include "ClipboardWince.h" +#include "Document.h" +#include "EditorClient.h" +#include "Element.h" +#include "HtmlEditing.h" +#include "TextIterator.h" +#include "visible_units.h" + +#include <windows.h> +#define _SYS_GUID_OPERATORS_ + +namespace WebCore { + +PassRefPtr<Clipboard> Editor::newGeneralClipboard(ClipboardAccessPolicy policy) +{ + return adoptRef(new ClipboardWince(policy, false)); +} + +} // namespace WebCore diff --git a/WebCore/platform/wince/FileChooserWince.cpp b/WebCore/platform/wince/FileChooserWince.cpp new file mode 100644 index 0000000..07c99b1 --- /dev/null +++ b/WebCore/platform/wince/FileChooserWince.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007-2009 Torch Mobile, Inc. + * + * 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 "Chrome.h" +#include "ChromeClient.h" +#include "Document.h" +#include "Frame.h" +#include "Icon.h" +#include "LocalizedStrings.h" +#include "Page.h" +#include "StringTruncator.h" + +namespace WebCore { + +String pathGetFileName(const String& path); + +String FileChooser::basenameForWidth(const Font& font, int width) const +{ + if (width <= 0) + return String(); + + String string; + if (m_filenames.isEmpty()) + string = fileButtonNoFileSelectedLabel(); + else if (m_filenames.size() == 1) { + String tmpFilename = m_filenames[0]; + string = pathGetFileName(tmpFilename); + } else + return StringTruncator::rightTruncate(String::number(m_filenames.size()) + " files", width, font, false); + + return StringTruncator::centerTruncate(string, width, font, false); +} + +} diff --git a/WebCore/platform/wince/FileSystemWince.cpp b/WebCore/platform/wince/FileSystemWince.cpp new file mode 100644 index 0000000..2bb4dd5 --- /dev/null +++ b/WebCore/platform/wince/FileSystemWince.cpp @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2008 Collabora, Ltd. All rights reserved. + * Copyright (C) 2007-2009 Torch Mobile, Inc. + * + * 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 "PlatformString.h" + +#include <windows.h> +#include <wincrypt.h> + +namespace WebCore { + +static bool getFileInfo(const String& path, BY_HANDLE_FILE_INFORMATION& fileInfo) +{ + String filename = path; + HANDLE hFile = CreateFile(filename.charactersWithNullTermination(), GENERIC_READ, FILE_SHARE_READ, 0 + , OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0); + + if (hFile == INVALID_HANDLE_VALUE) + return false; + + bool rtn = GetFileInformationByHandle(hFile, &fileInfo) ? true : false; + + CloseHandle(hFile); + return rtn; +} + +bool getFileSize(const String& path, long long& result) +{ + BY_HANDLE_FILE_INFORMATION fileInformation; + if (!getFileInfo(path, fileInformation)) + return false; + + ULARGE_INTEGER fileSize; + fileSize.LowPart = fileInformation.nFileSizeLow; + fileSize.HighPart = fileInformation.nFileSizeHigh; + + result = fileSize.QuadPart; + + return true; +} + +bool getFileModificationTime(const String& path, time_t& result) +{ + BY_HANDLE_FILE_INFORMATION fileInformation; + if (!getFileInfo(path, fileInformation)) + return false; + + ULARGE_INTEGER t; + memcpy(&t, &fileInformation.ftLastWriteTime, sizeof(t)); + + result = t.QuadPart * 0.0000001 - 11644473600.0; + + return true; +} + +bool fileExists(const String& path) +{ + String filename = path; + HANDLE hFile = CreateFile(filename.charactersWithNullTermination(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE + , 0, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0); + + CloseHandle(hFile); + + return hFile != INVALID_HANDLE_VALUE; +} + +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) +{ + if (component.isEmpty()) + return path; + + Vector<UChar, MAX_PATH> buffer; + + buffer.append(path.characters(), path.length()); + + if (buffer.last() != L'\\' && buffer.last() != L'/' + && component[0] != L'\\' && component[0] != L'/') + buffer.append(L'\\'); + + buffer.append(component.characters(), component.length()); + + return String(buffer.data(), buffer.size()); +} + +CString fileSystemRepresentation(const String&) +{ + return ""; +} + +bool makeAllDirectories(const String& path) +{ + int lastDivPos = max(path.reverseFind('/'), path.reverseFind('\\')); + int endPos = path.length(); + if (lastDivPos == path.length() - 1) { + endPos -= 1; + lastDivPos = max(path.reverseFind('/', lastDivPos), path.reverseFind('\\', lastDivPos)); + } + + if (lastDivPos > 0) { + if (!makeAllDirectories(path.substring(0, lastDivPos))) + return false; + } + + String folder(path.substring(0, endPos)); + CreateDirectory(folder.charactersWithNullTermination(), 0); + + DWORD fileAttr = GetFileAttributes(folder.charactersWithNullTermination()); + return fileAttr != 0xFFFFFFFF && (fileAttr & FILE_ATTRIBUTE_DIRECTORY); +} + +String homeDirectoryPath() +{ + notImplemented(); + return ""; +} + +String pathGetFileName(const String& path) +{ + return path.substring(max(path.reverseFind('/'), path.reverseFind('\\')) + 1); +} + +String directoryName(const String& path) +{ + notImplemented(); + return String(); +} + +CString openTemporaryFile(const char*, PlatformFileHandle& handle) +{ + handle = INVALID_HANDLE_VALUE; + + wchar_t tempPath[MAX_PATH]; + int tempPathLength = ::GetTempPath(_countof(tempPath), tempPath); + if (tempPathLength <= 0 || tempPathLength > _countof(tempPath)) + return CString(); + + HCRYPTPROV hCryptProv = 0; + if (!CryptAcquireContext(&hCryptProv, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + return CString(); + + String proposedPath; + while (1) { + + wchar_t tempFile[] = L"XXXXXXXX.tmp"; // Use 8.3 style name (more characters aren't helpful due to 8.3 short file names) + const int randomPartLength = 8; + if (!CryptGenRandom(hCryptProv, randomPartLength * 2, reinterpret_cast<BYTE*>(tempFile))) + break; + + // Limit to valid filesystem characters, also excluding others that could be problematic, like punctuation. + // don't include both upper and lowercase since Windows file systems are typically not case sensitive. + const char validChars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + for (int i = 0; i < randomPartLength; ++i) + tempFile[i] = validChars[tempFile[i] % (sizeof(validChars) - 1)]; + + ASSERT(wcslen(tempFile) * 2 == sizeof(tempFile) - 2); + + proposedPath = pathByAppendingComponent(String(tempPath), String(tempFile)); + + // use CREATE_NEW to avoid overwriting an existing file with the same name + handle = CreateFile(proposedPath.charactersWithNullTermination(), GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); + if (!isHandleValid(handle) && GetLastError() == ERROR_ALREADY_EXISTS) + continue; + + break; + } + + CryptReleaseContext(hCryptProv, 0); + + if (!isHandleValid(handle)) + return CString(); + + return proposedPath.latin1(); +} + +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 String(L"\\"); +} + +String roamingUserSpecificStorageDirectory() +{ + return String(L"\\"); +} + +Vector<String> listDirectory(const String& path, const String& filter) +{ + Vector<String> entries; + + Vector<UChar, 256> pattern; + pattern.append(path.characters(), path.length()); + if (pattern.last() != L'/' && pattern.last() != L'\\') + pattern.append(L'\\'); + + String root(pattern.data(), pattern.size()); + pattern.append(filter.characters(), filter.length()); + pattern.append(0); + + WIN32_FIND_DATA findData; + HANDLE hFind = FindFirstFile(pattern.data(), &findData); + if (INVALID_HANDLE_VALUE != hFind) { + do { + // FIXEME: should we also add the folders? This function + // is so far only called by PluginDatabase.cpp to list + // all plugins in a folder, where it's not supposed to list sub-folders. + if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + entries.append(root + findData.cFileName); + } while (FindNextFile(hFind, &findData)); + FindClose(hFind); + } + + return entries; +} + +} diff --git a/WebCore/platform/wince/KURLWince.cpp b/WebCore/platform/wince/KURLWince.cpp new file mode 100644 index 0000000..5ca1e4b --- /dev/null +++ b/WebCore/platform/wince/KURLWince.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2009 Torch Mobile 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 "KURL.h" + +namespace WebCore { + +String KURL::fileSystemPath() const +{ + return path(); +} + +} diff --git a/WebCore/platform/wince/KeygenWince.cpp b/WebCore/platform/wince/KeygenWince.cpp new file mode 100644 index 0000000..b0f4d63 --- /dev/null +++ b/WebCore/platform/wince/KeygenWince.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2008-2009 Torch Mobile 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 "SSLKeyGenerator.h" + +#include "Base64.h" +#include "CString.h" + +#include <windows.h> +#include <wincrypt.h> + +namespace WebCore { + +void WebCore::getSupportedKeySizes(Vector<String>& v) +{ + v.append("High Grade"); + v.append("Medium Grade"); +} + +String WebCore::signedPublicKeyAndChallengeString(unsigned index, const String& challenge, const KURL& url) +{ + String keyString; + + HCRYPTPROV hContext = 0; + HCRYPTKEY hKey = 0; + PCERT_PUBLIC_KEY_INFO pPubInfo = 0; + + // Try to delete it if it exists already + CryptAcquireContext(&hContext, _T("keygen_container"), MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_DELETEKEYSET); + + do { + if (!CryptAcquireContext(&hContext, _T("keygen_container"), MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET)) + break; + + DWORD dwPubInfoLength = 0; + if (!CryptGenKey(hContext, AT_KEYEXCHANGE, 0, &hKey) || !CryptExportPublicKeyInfo(hContext, AT_KEYEXCHANGE, X509_ASN_ENCODING, 0, &dwPubInfoLength)) + break; + + // Use malloc instead of new, because malloc guarantees to return a pointer aligned for all data types. + pPubInfo = reinterpret_cast<PCERT_PUBLIC_KEY_INFO>(fastMalloc(dwPubInfoLength)); + + if (!CryptExportPublicKeyInfo(hContext, AT_KEYEXCHANGE, X509_ASN_ENCODING, pPubInfo, &dwPubInfoLength)) + break; + + CERT_KEYGEN_REQUEST_INFO requestInfo = { 0 }; + requestInfo.dwVersion = CERT_KEYGEN_REQUEST_V1; + requestInfo.pwszChallengeString = L""; + requestInfo.SubjectPublicKeyInfo = *pPubInfo; + + String localChallenge = challenge; + + // Windows API won't write to our buffer, although it's not declared with const. + requestInfo.pwszChallengeString = const_cast<wchar_t*>(localChallenge.charactersWithNullTermination()); + + CRYPT_ALGORITHM_IDENTIFIER signAlgo = { 0 }; + signAlgo.pszObjId = szOID_RSA_SHA1RSA; + + DWORD dwEncodedLength; + if (!CryptSignAndEncodeCertificate(hContext, AT_KEYEXCHANGE, X509_ASN_ENCODING, X509_KEYGEN_REQUEST_TO_BE_SIGNED, &requestInfo, &signAlgo, 0, 0, &dwEncodedLength)) + break; + + Vector<char> binary(dwEncodedLength); + if (!CryptSignAndEncodeCertificate(hContext, AT_KEYEXCHANGE, X509_ASN_ENCODING, X509_KEYGEN_REQUEST_TO_BE_SIGNED, &requestInfo, &signAlgo, 0, reinterpret_cast<LPBYTE>(binary.data()), &dwEncodedLength)) + break; + + Vector<char> base64; + base64Encode(binary, base64); + keyString = String(base64.data(), base64.size()); + + } while(0); + + if (pPubInfo) + fastFree(pPubInfo); + + if (hKey) + CryptDestroyKey(hKey); + + if (hContext) + CryptReleaseContext(hContext, 0); + + return keyString; +} + +} // namespace WebCore diff --git a/WebCore/platform/wince/MIMETypeRegistryWince.cpp b/WebCore/platform/wince/MIMETypeRegistryWince.cpp new file mode 100644 index 0000000..2ecde48 --- /dev/null +++ b/WebCore/platform/wince/MIMETypeRegistryWince.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007-2009 Torch Mobile, Inc. + * + * 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 <windows.h> +#include <winreg.h> + +namespace WebCore { + +static String mimeTypeForExtension(const String& extension) +{ + String ext = "." + extension; + WCHAR contentTypeStr[256]; + DWORD contentTypeStrLen = sizeof(contentTypeStr); + DWORD valueType; + + HKEY key; + String result; + if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CLASSES_ROOT, ext.charactersWithNullTermination(), 0, 0, &key)) + return result; + + if (ERROR_SUCCESS == RegQueryValueEx(key, L"Content Type", 0, &valueType, (LPBYTE)contentTypeStr, &contentTypeStrLen) && valueType == REG_SZ) + result = String(contentTypeStr, contentTypeStrLen / sizeof(contentTypeStr[0]) - 1); + + RegCloseKey(key); + + return result; +} + +static HashMap<String, String> mimetypeMap; + +static void initMIMETypeEntensionMap() +{ + 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"); + mimetypeMap.add("css", "text/css"); + // FIXME: Custom font works only when MIME is "text/plain" + mimetypeMap.add("ttf", "text/plain"); // "font/ttf" + mimetypeMap.add("otf", "text/plain"); // "font/otf" +#if ENABLE(WML) + mimetypeMap.add("wml", "text/vnd.wap.wml"); +#endif +#if ENABLE(WBXML) + mimetypeMap.add("wbxml", "application/vnd.wap.wmlc"); +#endif + } +} + +String MIMETypeRegistry::getPreferredExtensionForMIMEType(const String& type) +{ + if (type.isEmpty()) + return String(); + + // Avoid conflicts with "ttf" and "otf" + if (equalIgnoringCase(type, "text/plain")) + return "txt"; + + initMIMETypeEntensionMap(); + + for (HashMap<String, String>::iterator i = mimetypeMap.begin(); i != mimetypeMap.end(); ++i) { + if (equalIgnoringCase(i->second, type)) + return i->first; + } + +#if ENABLE(XHTMLMP) + if (equalIgnoringCase("application/vnd.wap.xhtml+xml", type)) + return String("xml"); +#endif + + return String(); +} + +String MIMETypeRegistry::getMIMETypeForExtension(const String &ext) +{ + if (ext.isEmpty()) + return String(); + + initMIMETypeEntensionMap(); + + String result = mimetypeMap.get(ext.lower()); + if (result.isEmpty()) { + result = mimeTypeForExtension(ext); + if (!result.isEmpty()) + mimetypeMap.add(ext, result); + } + return result.isEmpty() ? "unknown/unknown" : result; +} + +} diff --git a/WebCore/platform/wince/PasteboardWince.cpp b/WebCore/platform/wince/PasteboardWince.cpp new file mode 100644 index 0000000..16f4968 --- /dev/null +++ b/WebCore/platform/wince/PasteboardWince.cpp @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007-2009 Torch Mobile, Inc. + * + * 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 "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; + +extern HDC hScreenDC; + +static LRESULT CALLBACK PasteboardOwnerWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + LRESULT lresult = 0; + LONG longPtr = GetWindowLong(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_DESTROY: + 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 + WNDCLASS wc = {0}; + memset(&wc, 0, sizeof(wc)); + wc.lpfnWndProc = PasteboardOwnerWndProc; + wc.hInstance = Page::instanceHandle(); + wc.lpszClassName = L"PasteboardOwnerWindowClass"; + ::RegisterClass(&wc); + + 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(), 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, 0); + ::CloseClipboard(); + } + } +} + +void Pasteboard::writePlainText(const String& text) +{ + clear(); + + // Put plain string on the pasteboard. CF_UNICODETEXT covers CF_TEXT as well + String str = text; + replaceNewlinesWithWindowsStyleNewlines(str); + if (::OpenClipboard(m_owner)) { + HGLOBAL cbData = createGlobalData(str); + if (!::SetClipboardData(CF_UNICODETEXT, cbData)) + ::GlobalFree(cbData); + ::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(); + + RefPtr<SharedBitmap> sourceBmp = image->nativeImageForCurrentFrame(); + if (!sourceBmp) + return; + + IntRect rect(0, 0, sourceBmp->width(), sourceBmp->height()); + BitmapInfo bmpInfo; + void* pixels; + HBITMAP resultBitmap = sourceBmp->clipBitmap(rect, true, bmpInfo, pixels); + if (!resultBitmap) + return; + + if (::OpenClipboard(m_owner)) { + ::SetClipboardData(CF_BITMAP, resultBitmap); + ::CloseClipboard(); + } else + DeleteObject(resultBitmap); +} + +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; +} + +bool Pasteboard::hasData() +{ + return hasDataInFormat(CF_UNICODETEXT) || hasDataInFormat(CF_TEXT); +} + +bool Pasteboard::hasDataInFormat(unsigned int format) +{ + return ::IsClipboardFormatAvailable(format); +} + +} // namespace WebCore diff --git a/WebCore/platform/wince/SearchPopupMenuWince.cpp b/WebCore/platform/wince/SearchPopupMenuWince.cpp new file mode 100644 index 0000000..ca11292 --- /dev/null +++ b/WebCore/platform/wince/SearchPopupMenuWince.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2009 Torch Mobile 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" + +namespace WebCore { + +SearchPopupMenu::SearchPopupMenu(PopupMenuClient* client) +: PopupMenu(client) +{ +} + +bool SearchPopupMenu::enabled() +{ + return false; +} + +void SearchPopupMenu::saveRecentSearches(const AtomicString& name, const Vector<String>& searchItems) +{ + if (name.isEmpty()) + return; + + notImplemented(); +} + +void SearchPopupMenu::loadRecentSearches(const AtomicString& name, Vector<String>& searchItems) +{ + if (name.isEmpty()) + return; + + notImplemented(); +} + +} diff --git a/WebCore/platform/wince/SharedTimerWince.cpp b/WebCore/platform/wince/SharedTimerWince.cpp new file mode 100644 index 0000000..ca2f104 --- /dev/null +++ b/WebCore/platform/wince/SharedTimerWince.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2007-2008 Torch Mobile, Inc. + * + * 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> +#include <wtf/CurrentTime.h> +#include <windows.h> + +namespace JSC { +extern void* g_stackBase; +} + +namespace WebCore { + +enum { + TimerIdNone = 0, + TimerIdAuto, + TimerIdManual, +}; +static UINT timerID = TimerIdNone; + +static void (*sharedTimerFiredFunction)(); + +static HWND timerWindowHandle = 0; +const LPCWSTR kTimerWindowClassName = L"TimerWindowClass"; + +LRESULT CALLBACK TimerWindowWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int dummy; + JSC::g_stackBase = &dummy; + + if (message == WM_TIMER) { + if (timerID != TimerIdNone) + sharedTimerFiredFunction(); + } else if (message == WM_USER) { + if (timerID = TimerIdManual) { + sharedTimerFiredFunction(); + PostMessage(hWnd, WM_USER, 0, 0); + } + } else { + JSC::g_stackBase = 0; + return DefWindowProc(hWnd, message, wParam, lParam); + } + JSC::g_stackBase = 0; + return 0; +} + +static void initializeOffScreenTimerWindow() +{ + if (timerWindowHandle) + return; + + WNDCLASS wcex = {0}; + wcex.lpfnWndProc = TimerWindowWndProc; + wcex.hInstance = Page::instanceHandle(); + wcex.lpszClassName = kTimerWindowClassName; + RegisterClass(&wcex); + + timerWindowHandle = CreateWindow(kTimerWindowClassName, 0, 0, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, HWND_MESSAGE, 0, Page::instanceHandle(), 0); +} + +void setSharedTimerFiredFunction(void (*f)()) +{ + sharedTimerFiredFunction = f; +} + +#define USER_TIMER_MAXIMUM 0x7FFFFFFF +#define USER_TIMER_MINIMUM 0x0000000A + +void setSharedTimerFireTime(double fireTime) +{ + ASSERT(sharedTimerFiredFunction); + + double interval = (fireTime - currentTime()) * 1000.; + unsigned intervalInMS = interval < USER_TIMER_MINIMUM + ? USER_TIMER_MINIMUM + : interval > USER_TIMER_MAXIMUM + ? USER_TIMER_MAXIMUM + : static_cast<unsigned>(interval); + + if (timerID == TimerIdAuto) { + KillTimer(timerWindowHandle, TimerIdAuto); + timerID = TimerIdNone; + } + + initializeOffScreenTimerWindow(); + if (SetTimer(timerWindowHandle, TimerIdAuto, intervalInMS, 0)) + timerID = TimerIdAuto; + else if (timerID != TimerIdManual) + PostMessage(timerWindowHandle, WM_USER, 0, 0); +} + +void stopSharedTimer() +{ + if (timerID == TimerIdAuto) + KillTimer(timerWindowHandle, TimerIdAuto); + + timerID = TimerIdNone; +} + +} diff --git a/WebCore/platform/wince/SystemTimeWince.cpp b/WebCore/platform/wince/SystemTimeWince.cpp new file mode 100644 index 0000000..70b705b --- /dev/null +++ b/WebCore/platform/wince/SystemTimeWince.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2007-2008 Torch Mobile, Inc. + * + * 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 <windows.h> + +namespace WebCore { + +float userIdleTime() +{ + return FLT_MAX; +} + +} diff --git a/WebCore/platform/wx/CursorWx.cpp b/WebCore/platform/wx/CursorWx.cpp index 7175b01..ed7f86b 100644 --- a/WebCore/platform/wx/CursorWx.cpp +++ b/WebCore/platform/wx/CursorWx.cpp @@ -298,4 +298,10 @@ const Cursor& grabbingCursor() return pointerCursor(); } +const Cursor& moveCursor() +{ + static Cursor c = new wxCursor(wxCURSOR_SIZING); + return c; +} + } diff --git a/WebCore/platform/wx/FileChooserWx.cpp b/WebCore/platform/wx/FileChooserWx.cpp new file mode 100644 index 0000000..34065f3 --- /dev/null +++ b/WebCore/platform/wx/FileChooserWx.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FileChooser.h" + +#include "NotImplemented.h" + +namespace WebCore { + +String FileChooser::basenameForWidth(const Font&, int width) const +{ + notImplemented(); + return String(); +} + +} + diff --git a/WebCore/platform/wx/FileSystemWx.cpp b/WebCore/platform/wx/FileSystemWx.cpp index 7de425e..109278f 100644 --- a/WebCore/platform/wx/FileSystemWx.cpp +++ b/WebCore/platform/wx/FileSystemWx.cpp @@ -40,50 +40,50 @@ namespace WebCore { bool fileExists(const String& path) { - notImplemented(); - return true; + return wxFileName::FileExists(path); } bool deleteFile(const String& path) { - notImplemented(); - return false; + return wxRemoveFile(path); } bool deleteEmptyDirectory(const String& path) { - notImplemented(); - return false; + return wxFileName::Rmdir(path); } bool getFileSize(const String& path, long long& resultSize) { - notImplemented(); + wxULongLong size = wxFileName::GetSize(path); + if (wxInvalidSize != size) { + // TODO: why is FileSystem::getFileSize signed? + resultSize = (long long)size.GetValue(); + return true; + } + return false; } -bool getFileModificationTime(const String&, time_t&) +bool getFileModificationTime(const String& path, time_t& t) { - notImplemented(); - return false; + t = wxFileName(path).GetModificationTime().GetTicks(); + return true; } bool makeAllDirectories(const String& path) { - notImplemented(); - return false; + return wxFileName::Mkdir(path, 0777, wxPATH_MKDIR_FULL); } String pathByAppendingComponent(const String& path, const String& component) { - notImplemented(); - return String(); + return wxFileName(path, component).GetFullPath(); } String homeDirectoryPath() { - notImplemented(); - return String(); + return wxFileName::GetHomeDir(); } String pathGetFileName(const String& path) @@ -93,8 +93,7 @@ String pathGetFileName(const String& path) String directoryName(const String& path) { - notImplemented(); - return String(); + return wxFileName(path).GetPath(); } CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle) diff --git a/WebCore/platform/wx/KURLWx.cpp b/WebCore/platform/wx/KURLWx.cpp new file mode 100644 index 0000000..a2be103 --- /dev/null +++ b/WebCore/platform/wx/KURLWx.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "KURL.h" + +#include "NotImplemented.h" + +namespace WebCore { + +String KURL::fileSystemPath() const +{ + notImplemented(); + return String(); +} + +} + diff --git a/WebCore/platform/wx/PasteboardWx.cpp b/WebCore/platform/wx/PasteboardWx.cpp index 67697de..207c63c 100644 --- a/WebCore/platform/wx/PasteboardWx.cpp +++ b/WebCore/platform/wx/PasteboardWx.cpp @@ -52,13 +52,20 @@ Pasteboard* Pasteboard::generalPasteboard() void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame) { - if (wxTheClipboard->Open()) - { + if (wxTheClipboard->Open()) { wxTheClipboard->SetData( new wxTextDataObject(frame->selectedText()) ); wxTheClipboard->Close(); } } +void Pasteboard::writePlainText(const String& text) +{ + if (wxTheClipboard->Open()) { + wxTheClipboard->SetData( new wxTextDataObject(text) ); + wxTheClipboard->Close(); + } +} + bool Pasteboard::canSmartReplace() { notImplemented(); @@ -92,8 +99,7 @@ PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefP void Pasteboard::writeURL(const KURL& url, const String&, Frame*) { - if (wxTheClipboard->Open()) - { + if (wxTheClipboard->Open()) { wxTheClipboard->SetData( new wxTextDataObject( url.string() ) ); wxTheClipboard->Close(); } diff --git a/WebCore/platform/wx/PopupMenuWx.cpp b/WebCore/platform/wx/PopupMenuWx.cpp index 660282c..9b0deba 100644 --- a/WebCore/platform/wx/PopupMenuWx.cpp +++ b/WebCore/platform/wx/PopupMenuWx.cpp @@ -88,7 +88,7 @@ void PopupMenu::OnMenuItemSelected(wxCommandEvent& event) { if (client()) { client()->valueChanged(event.GetId() - s_menuStartId); - client()->hidePopup(); + client()->popupDidHide(); } // TODO: Do we need to call Disconnect here? Do we have a ref to the native window still? } diff --git a/WebCore/platform/wx/RenderThemeWx.cpp b/WebCore/platform/wx/RenderThemeWx.cpp index f2ced9e..c66ff87 100644 --- a/WebCore/platform/wx/RenderThemeWx.cpp +++ b/WebCore/platform/wx/RenderThemeWx.cpp @@ -29,6 +29,7 @@ #include "Document.h" #include "FrameView.h" #include "GraphicsContext.h" +#include "HostWindow.h" #include "NotImplemented.h" #include "RenderView.h" @@ -138,6 +139,15 @@ PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page) return rt; } +wxWindow* nativeWindowForRenderObject(RenderObject* o) +{ + FrameView* frameView = o->view()->frameView(); + ASSERT(frameView); + ASSERT(frameView->hostWindow()); + return frameView->hostWindow()->platformPageClient(); +} + + bool RenderThemeWx::isControlStyled(const RenderStyle* style, const BorderData& border, const FillLayer& background, const Color& backgroundColor) const { @@ -251,10 +261,23 @@ void RenderThemeWx::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* s bool RenderThemeWx::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { - wxWindow* window = o->view()->frameView()->platformWidget(); + wxWindow* window = nativeWindowForRenderObject(o); wxDC* dc = static_cast<wxDC*>(i.context->platformContext()); int flags = 0; + IntRect rect = r; + +#if USE(WXGC) + double xtrans = 0; + double ytrans = 0; + + wxGCDC* gcdc = static_cast<wxGCDC*>(dc); + wxGraphicsContext* gc = gcdc->GetGraphicsContext(); + gc->GetTransform().TransformPoint(&xtrans, &ytrans); + rect.setX(r.x() + (int)xtrans); + rect.setY(r.y() + (int)ytrans); +#endif + if (!isEnabled(o)) flags |= wxCONTROL_DISABLED; @@ -266,20 +289,22 @@ bool RenderThemeWx::paintButton(RenderObject* o, const RenderObject::PaintInfo& flags |= wxCONTROL_PRESSED; if (part == PushButtonPart || part == ButtonPart) - wxRendererNative::Get().DrawPushButton(window, *dc, r, flags); + wxRendererNative::Get().DrawPushButton(window, *dc, rect, flags); else if(part == RadioPart) { if (isChecked(o)) flags |= wxCONTROL_CHECKED; -#if wxCHECK_VERSION(2,9,0) - wxRendererNative::Get().DrawRadioButton(window, *dc, r, flags); +#if wxCHECK_VERSION(2,9,1) + wxRendererNative::Get().DrawRadioBitmap(window, *dc, r, flags); +#elif wxCHECK_VERSION(2,9,0) + wxRendererNative::Get().DrawRadioButton(window, *dc, rect, flags); #else - wxRenderer_DrawRadioButton(window, *dc, r, flags); + wxRenderer_DrawRadioButton(window, *dc, rect, flags); #endif } else if(part == CheckboxPart) { if (isChecked(o)) flags |= wxCONTROL_CHECKED; - wxRendererNative::Get().DrawCheckBox(window, *dc, r, flags); + wxRendererNative::Get().DrawCheckBox(window, *dc, rect, flags); } return false; } @@ -291,7 +316,7 @@ void RenderThemeWx::adjustTextFieldStyle(CSSStyleSelector*, RenderStyle* style, bool RenderThemeWx::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { - wxWindow* window = o->view()->frameView()->platformWidget(); + wxWindow* window = nativeWindowForRenderObject(o); wxDC* dc = static_cast<wxDC*>(i.context->platformContext()); #if wxCHECK_VERSION(2,9,0) wxRendererNative::Get().DrawTextCtrl(window, *dc, r, 0); @@ -313,7 +338,7 @@ void RenderThemeWx::adjustMenuListStyle(CSSStyleSelector*, RenderStyle* style, E bool RenderThemeWx::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { - wxWindow* window = o->view()->frameView()->platformWidget(); + wxWindow* window = nativeWindowForRenderObject(o); wxDC* dc = static_cast<wxDC*>(i.context->platformContext()); int flags = 0; @@ -342,7 +367,7 @@ void RenderThemeWx::adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, E bool RenderThemeWx::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) { - wxWindow* window = o->view()->frameView()->platformWidget(); + wxWindow* window = nativeWindowForRenderObject(o); wxDC* dc = static_cast<wxDC*>(i.context->platformContext()); int flags = 0; diff --git a/WebCore/platform/wx/SSLKeyGeneratorWx.cpp b/WebCore/platform/wx/SSLKeyGeneratorWx.cpp new file mode 100644 index 0000000..7d076e7 --- /dev/null +++ b/WebCore/platform/wx/SSLKeyGeneratorWx.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SSLKeyGenerator.h" + +#include "NotImplemented.h" + +namespace WebCore { + +void getSupportedKeySizes(Vector<String>&) +{ + notImplemented(); +} + +String signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String &challengeString, const KURL &url) +{ + return String(); +} + +} + diff --git a/WebCore/platform/wx/ScrollbarThemeWx.cpp b/WebCore/platform/wx/ScrollbarThemeWx.cpp new file mode 100644 index 0000000..6904f41 --- /dev/null +++ b/WebCore/platform/wx/ScrollbarThemeWx.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ScrollbarThemeWx.h" + +#include "HostWindow.h" +#include "NotImplemented.h" +#include "Scrollbar.h" +#include "ScrollbarClient.h" +#include "scrollbar_render.h" +#include "ScrollbarThemeComposite.h" +#include "ScrollView.h" + +#include <wx/defs.h> +#include <wx/dcgraph.h> +#include <wx/settings.h> + +const int cMacButtonOverlap = 4; + +namespace WebCore { + +ScrollbarTheme* ScrollbarTheme::nativeTheme() +{ + static ScrollbarThemeWx theme; + return &theme; +} + +ScrollbarThemeWx::~ScrollbarThemeWx() +{ +} + +int ScrollbarThemeWx::scrollbarThickness(ScrollbarControlSize size) +{ + int thickness = wxSystemSettings::GetMetric(wxSYS_VSCROLL_X); + + // fallback for when a platform doesn't define this metric + if (thickness <= 0) + thickness = 20; + + return thickness; +} + +bool ScrollbarThemeWx::hasThumb(Scrollbar* scrollbar) +{ + // This method is just called as a paint-time optimization to see if + // painting the thumb can be skipped. We don't have to be exact here. + return thumbLength(scrollbar) > 0; +} + +IntSize ScrollbarThemeWx::buttonSize(Scrollbar*) +{ +#ifdef __WXMAC__ + return IntSize(20,20); +#else + return IntSize(16,16); +#endif +} + + +IntRect ScrollbarThemeWx::backButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool) +{ + // FIXME: Handling this case is needed when there are two sets of arrow buttons + // on Mac, one at the top and one at the bottom. + if (part == BackButtonEndPart) + return IntRect(); + + IntSize size = buttonSize(scrollbar); + int x = scrollbar->x(); + int y = scrollbar->y(); + +#if __WXMAC__ + if (scrollbar->orientation() == HorizontalScrollbar) + x += scrollbar->width() - (size.width() * 2) + cMacButtonOverlap; + else + y += scrollbar->height() - (size.height() * 2) + cMacButtonOverlap; +#endif + + return IntRect(x, y, size.width(), size.height()); +} + +IntRect ScrollbarThemeWx::forwardButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool) +{ + // FIXME: Handling this case is needed when there are two sets of arrow buttons + // on Mac, one at the top and one at the bottom. + if (part == ForwardButtonStartPart) + return IntRect(); + + IntSize size = buttonSize(scrollbar); + int x, y; + if (scrollbar->orientation() == HorizontalScrollbar) { + x = scrollbar->x() + scrollbar->width() - size.width(); + y = scrollbar->y(); + } else { + x = scrollbar->x(); + y = scrollbar->y() + scrollbar->height() - size.height(); + } + return IntRect(x, y, size.width(), size.height()); +} + +IntRect ScrollbarThemeWx::trackRect(Scrollbar* scrollbar, bool) +{ + IntSize bs = buttonSize(scrollbar); + int trackStart = 0; + if (scrollbar->orientation() == HorizontalScrollbar) + trackStart = bs.width(); + else + trackStart = bs.height(); + +#if __WXMAC__ + trackStart = 0; +#endif + + int thickness = scrollbarThickness(scrollbar->controlSize()); + if (scrollbar->orientation() == HorizontalScrollbar) { + if (scrollbar->width() < 2 * thickness) + return IntRect(); + return IntRect(scrollbar->x() + trackStart, scrollbar->y(), scrollbar->width() - 2 * bs.width(), thickness); + } + if (scrollbar->height() < 2 * thickness) + return IntRect(); + return IntRect(scrollbar->x(), scrollbar->y() + trackStart, thickness, scrollbar->height() - 2 * bs.height()); +} + +void ScrollbarThemeWx::paintScrollCorner(ScrollView* view, GraphicsContext* context, const IntRect& cornerRect) +{ + // ScrollbarThemeComposite::paintScrollCorner incorrectly assumes that the + // ScrollView is a FrameView (see FramelessScrollView), so we cannot let + // that code run. For FrameView's this is correct since we don't do custom + // scrollbar corner rendering, which ScrollbarThemeComposite supports. + ScrollbarTheme::paintScrollCorner(view, context, cornerRect); +} + +bool ScrollbarThemeWx::paint(Scrollbar* scrollbar, GraphicsContext* context, const IntRect& rect) +{ + wxOrientation orientation = (scrollbar->orientation() == HorizontalScrollbar) ? wxHORIZONTAL : wxVERTICAL; + int flags = 0; + if (scrollbar->client()->isActive()) + flags |= wxCONTROL_FOCUSED; + + if (!scrollbar->enabled()) + flags |= wxCONTROL_DISABLED; + + wxDC* dc = static_cast<wxDC*>(context->platformContext()); + + context->save(); + ScrollView* root = scrollbar->root(); + ASSERT(root); + if (!root) + return false; + + wxWindow* webview = root->hostWindow()->platformPageClient(); + + wxRenderer_DrawScrollbar(webview, *dc, scrollbar->frameRect(), orientation, scrollbar->currentPos(), static_cast<wxScrollbarPart>(scrollbar->pressedPart()), + static_cast<wxScrollbarPart>(scrollbar->hoveredPart()), scrollbar->maximum(), scrollbar->pageStep(), flags); + + context->restore(); + return true; +} + +} + diff --git a/WebCore/platform/wx/ScrollbarThemeWx.h b/WebCore/platform/wx/ScrollbarThemeWx.h new file mode 100644 index 0000000..2b3bff0 --- /dev/null +++ b/WebCore/platform/wx/ScrollbarThemeWx.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ScrollbarThemeWx_h +#define ScrollbarThemeWx_h + +#include "ScrollbarTheme.h" +#include "ScrollbarThemeComposite.h" + +namespace WebCore { + +class ScrollbarThemeWx : public ScrollbarThemeComposite { +public: + virtual ~ScrollbarThemeWx(); + virtual int scrollbarThickness(ScrollbarControlSize = RegularScrollbar); + virtual bool paint(Scrollbar*, GraphicsContext*, const IntRect&); + + virtual void paintScrollCorner(ScrollView*, GraphicsContext*, const IntRect& cornerRect); + +protected: + virtual bool hasButtons(Scrollbar*) { return true; } + virtual bool hasThumb(Scrollbar*); + + virtual IntSize buttonSize(Scrollbar*); + + virtual IntRect backButtonRect(Scrollbar*, ScrollbarPart, bool painting = false); + virtual IntRect forwardButtonRect(Scrollbar*, ScrollbarPart, bool painting = false); + virtual IntRect trackRect(Scrollbar*, bool painting = false); +}; + +} +#endif diff --git a/WebCore/platform/wx/SearchPopupMenuWx.cpp b/WebCore/platform/wx/SearchPopupMenuWx.cpp new file mode 100644 index 0000000..dbbe339 --- /dev/null +++ b/WebCore/platform/wx/SearchPopupMenuWx.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SearchPopupMenu.h" + +#include "NotImplemented.h" + +namespace WebCore { + +SearchPopupMenu::SearchPopupMenu(PopupMenuClient* client) + : PopupMenu(client) +{ + notImplemented(); +} + +void SearchPopupMenu::saveRecentSearches(const AtomicString& name, const Vector<String>& searchItems) +{ + notImplemented(); +} + +void SearchPopupMenu::loadRecentSearches(const AtomicString& name, Vector<String>& searchItems) +{ + notImplemented(); +} + +bool SearchPopupMenu::enabled() +{ + return true; +} + +} + diff --git a/WebCore/platform/wx/SharedBufferWx.cpp b/WebCore/platform/wx/SharedBufferWx.cpp new file mode 100644 index 0000000..a9203ba --- /dev/null +++ b/WebCore/platform/wx/SharedBufferWx.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SharedBuffer.h" + +#include "NotImplemented.h" + +namespace WebCore { + +PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String&) +{ + notImplemented(); + return 0; +} + +} + diff --git a/WebCore/platform/wx/SystemTimeWx.cpp b/WebCore/platform/wx/SystemTimeWx.cpp new file mode 100644 index 0000000..f607cba --- /dev/null +++ b/WebCore/platform/wx/SystemTimeWx.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SystemTime.h" + +#include <float.h> + +#include "NotImplemented.h" + +namespace WebCore { + +float userIdleTime() +{ + notImplemented(); + // return an arbitrarily high userIdleTime so that releasing pages from the page cache isn't postponed + return FLT_MAX; +} + +} + diff --git a/WebCore/platform/wx/TemporaryLinkStubs.cpp b/WebCore/platform/wx/TemporaryLinkStubs.cpp index 2403527..5aa6e2c 100644 --- a/WebCore/platform/wx/TemporaryLinkStubs.cpp +++ b/WebCore/platform/wx/TemporaryLinkStubs.cpp @@ -1,3 +1,4 @@ +<<<<<<< HEAD:WebCore/platform/wx/TemporaryLinkStubs.cpp /* * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. * Copyright (C) 2008 Collabora, Ltd. All rights reserved. @@ -178,3 +179,5 @@ PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String&) { void prefetchDNS(const String& hostname) { notImplemented(); } } +======= +>>>>>>> webkit.org at 49305:WebCore/platform/wx/TemporaryLinkStubs.cpp diff --git a/WebCore/platform/wx/TextBreakIteratorInternalICUWx.cpp b/WebCore/platform/wx/TextBreakIteratorInternalICUWx.cpp new file mode 100644 index 0000000..f840e13 --- /dev/null +++ b/WebCore/platform/wx/TextBreakIteratorInternalICUWx.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "TextBreakIteratorInternalICU.h" + +namespace WebCore { + +const char* currentSearchLocaleID() +{ + return ""; +} + +const char* currentTextBreakLocaleID() +{ + return "en_us"; +} + +} + diff --git a/WebCore/platform/wx/WidgetWx.cpp b/WebCore/platform/wx/WidgetWx.cpp index bb4fd2a..a384914 100644 --- a/WebCore/platform/wx/WidgetWx.cpp +++ b/WebCore/platform/wx/WidgetWx.cpp @@ -28,6 +28,7 @@ #include "Cursor.h" #include "GraphicsContext.h" #include "IntRect.h" +#include "NotImplemented.h" #include <wx/defs.h> #include <wx/scrolwin.h> @@ -96,4 +97,9 @@ void Widget::paint(GraphicsContext*,const IntRect& r) widget->Update(); } +void Widget::setIsSelected(bool) +{ + notImplemented(); +} + } diff --git a/WebCore/platform/wx/wxcode/gtk/scrollbar_render.cpp b/WebCore/platform/wx/wxcode/gtk/scrollbar_render.cpp new file mode 100644 index 0000000..f74b076 --- /dev/null +++ b/WebCore/platform/wx/wxcode/gtk/scrollbar_render.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2009 Kevin Ollivier 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 "scrollbar_render.h" + +#include <wx/defs.h> +#include <wx/dc.h> +#include <wx/dcgraph.h> +#include <wx/renderer.h> +#include <wx/settings.h> +#include <wx/window.h> + +#include <gtk/gtk.h> + +#if wxCHECK_VERSION(2, 9, 0) + #include <wx/gtk/dc.h> +#else + #include "wx/gtk/win_gtk.h" +#endif + +int wxStyleForPart(wxScrollbarPart part, wxScrollbarPart focusPart, wxScrollbarPart hoverPart, int flags) +{ + int style = 0; + if (flags == wxCONTROL_DISABLED) + style = wxCONTROL_DISABLED; + else if (part == focusPart) + style = wxCONTROL_PRESSED; + else if (part == hoverPart) + style = wxCONTROL_CURRENT; + + return style; +} + +GtkWidget* GetButtonWidget() +{ + static GtkWidget *s_button = NULL; + static GtkWidget *s_window = NULL; + + if ( !s_button ) + { + s_window = gtk_window_new( GTK_WINDOW_POPUP ); + gtk_widget_realize( s_window ); + s_button = gtk_button_new(); + gtk_container_add( GTK_CONTAINER(s_window), s_button ); + gtk_widget_realize( s_button ); + } + + return s_button; +} + + +GdkWindow* wxGetGdkWindowForDC(wxWindow* win, wxDC& dc) +{ + GdkWindow* gdk_window = NULL; +#if wxCHECK_VERSION(2, 9, 0) + if ( dc.IsKindOf( CLASSINFO(wxGCDC) ) ) + gdk_window = win->GTKGetDrawingWindow(); + else + { + wxGTKDCImpl *impl = wxDynamicCast(dc.GetImpl(), wxGTKDCImpl); + if ( impl ) + gdk_window = impl->GetGDKWindow(); + } +#else // wx < 2.9 + // The way to get a GdkWindow* from a wxWindow is to use + // GTK_PIZZA(win->m_wxwindow)->bin_window, but this approach + // won't work when drawing to a wxMemoryDC as it has its own + // GdkWindow* for its bitmap. wxWindowDC's GetGDKWindow() was + // designed to create a solution for all DCs, but we can't + // implement it with wxGCDC since it doesn't retain its wxWindow. + // So, to work around this, we use GetGDKWindow whenever possible + // and use bin_window for wxGCDC. +#if wxUSE_GRAPHICS_CONTEXT + if ( dc.IsKindOf( CLASSINFO(wxGCDC) ) ) + gdk_window = GTK_PIZZA(win->m_wxwindow)->bin_window; + else +#endif + gdk_window = dc.GetGDKWindow(); + wxASSERT_MSG( gdk_window, + wxT("cannot use wxRendererNative on wxDC of this type") ); +#endif // wx 2.9/2.8 + + return gdk_window; +} + +void wxRenderer_DrawScrollbar(wxWindow* window, wxDC& dc, const wxRect& rect, wxOrientation orient, + int current, wxScrollbarPart focusPart, wxScrollbarPart hoverPart, int max, int step, int flags) +{ + bool horiz = orient == wxHORIZONTAL; + wxColour scrollbar_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_SCROLLBAR); + dc.SetBrush(wxBrush(scrollbar_colour)); + dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW))); + dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height); + + wxRendererNative& renderer = wxRendererNative::Get(); + int x = rect.x; + int y = rect.y; + + int buttonLength = 16; + + renderer.DrawPushButton(window, dc, wxRect(x,y,buttonLength,buttonLength), wxStyleForPart(wxSCROLLPART_BACKBTNSTART, focusPart, hoverPart, flags)); + + GtkWidget* button = GetButtonWidget(); + GdkWindow* gdk_window = wxGetGdkWindowForDC(window, dc); + + GtkArrowType arrowType = GTK_ARROW_UP; + if (horiz) + arrowType = GTK_ARROW_LEFT; + + gtk_paint_arrow( button->style, gdk_window, GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, button, "arrow", arrowType, false, x + 4, y + 4, 8, 8); + + wxRect buttonRect = rect; + int physicalLength = horiz ? rect.width : rect.height; + physicalLength -= buttonLength*2; + int thumbStart = 0; + int thumbLength = 0; + calcThumbStartAndLength(physicalLength, max + step, current, step, &thumbStart, &thumbLength); + + if (horiz) { + buttonRect.x = thumbStart + buttonLength; + buttonRect.width = thumbLength; + } else { + buttonRect.y = thumbStart + buttonLength; + buttonRect.height = thumbLength; + } + + renderer.DrawPushButton(window, dc, buttonRect, wxStyleForPart(wxSCROLLPART_THUMB, focusPart, hoverPart, flags)); + + if (horiz) + x += rect.width - buttonLength; + else + y += rect.height - buttonLength; + + renderer.DrawPushButton(window, dc, wxRect(x,y,buttonLength,buttonLength), wxStyleForPart(wxSCROLLPART_FWDBTNEND, focusPart, hoverPart, flags)); + + if (horiz) + arrowType = GTK_ARROW_RIGHT; + else + arrowType = GTK_ARROW_DOWN; + + gtk_paint_arrow( button->style, gdk_window, GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, button, "arrow", arrowType, false, x + 4, y + 4, 8, 8); +} diff --git a/WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp b/WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp index e5c60d6..c4c4d48 100644 --- a/WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp +++ b/WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp @@ -63,7 +63,7 @@ void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* CGFontRef cgFont; #ifdef wxOSX_USE_CORE_TEXT && wxOSX_USE_CORE_TEXT - cgFont = CTFontCopyGraphicsFont((CTFontRef)font->OSXGetCTFont(), NULL); + cgFont = CTFontCopyGraphicsFont((CTFontRef)wxfont->OSXGetCTFont(), NULL); #else ATSFontRef fontRef; diff --git a/WebCore/platform/wx/wxcode/mac/carbon/scrollbar_render.cpp b/WebCore/platform/wx/wxcode/mac/carbon/scrollbar_render.cpp new file mode 100644 index 0000000..5169601 --- /dev/null +++ b/WebCore/platform/wx/wxcode/mac/carbon/scrollbar_render.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2009 Kevin Ollivier 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 "scrollbar_render.h" + +#include <wx/defs.h> +#include <wx/dc.h> +#include <wx/dcgraph.h> +#include <wx/renderer.h> + +#include <Carbon/Carbon.h> + +static int wxScrollbarPartToHIPressedState(wxScrollbarPart part) +{ + switch (part) { + case wxSCROLLPART_BACKBTNSTART: + return kThemeTopOutsideArrowPressed; + case wxSCROLLPART_BACKBTNEND: + return kThemeTopOutsideArrowPressed; // This does not make much sense. For some reason the outside constant is required. + case wxSCROLLPART_FWDBTNSTART: + return kThemeTopInsideArrowPressed; + case wxSCROLLPART_FWDBTNEND: + return kThemeBottomOutsideArrowPressed; + case wxSCROLLPART_THUMB: + return kThemeThumbPressed; + default: + return 0; + } +} + +void wxRenderer_DrawScrollbar(wxWindow* WXUNUSED(window), wxDC& dc, + const wxRect& rect, wxOrientation orient, int current, + wxScrollbarPart focusPart, wxScrollbarPart hoverPart, int max, int step, int flags) +{ + const wxCoord x = rect.x; + const wxCoord y = rect.y; + const wxCoord w = rect.width; + const wxCoord h = rect.height; + + dc.SetBrush( *wxWHITE_BRUSH ); + dc.SetPen( *wxTRANSPARENT_PEN ); + dc.DrawRectangle(rect); + + dc.SetBrush( *wxTRANSPARENT_BRUSH ); + + HIRect hiRect = CGRectMake( x, y, w, h ); + + CGContextRef cgContext = NULL; + wxGraphicsContext* gc = NULL; +#if wxCHECK_VERSION(2,9,0) + wxGCDCImpl *impl = dynamic_cast<wxGCDCImpl*> (dc.GetImpl()); + if (impl) + gc = impl->GetGraphicsContext(); +#else + gc = dc.GetGraphicsContext(); +#endif + if (gc) + cgContext = (CGContextRef) gc->GetNativeContext(); + + if (cgContext) + { + HIThemeTrackDrawInfo trackInfo; + trackInfo.version = 0; + trackInfo.kind = kThemeMediumScrollBar; + trackInfo.bounds = hiRect; + trackInfo.min = 0; + trackInfo.max = max; + trackInfo.value = current; + trackInfo.trackInfo.scrollbar.viewsize = step; + trackInfo.attributes = 0; + if (orient == wxHORIZONTAL) + trackInfo.attributes |= kThemeTrackHorizontal; + trackInfo.enableState = (flags & wxCONTROL_FOCUSED) ? kThemeTrackActive : kThemeTrackInactive; + trackInfo.trackInfo.scrollbar.pressState = wxScrollbarPartToHIPressedState(focusPart); + trackInfo.attributes |= kThemeTrackShowThumb; + + if (flags & wxCONTROL_DISABLED) + trackInfo.enableState = kThemeTrackDisabled; + + HIThemeDrawTrack(&trackInfo, 0, cgContext, kHIThemeOrientationNormal); + } +} diff --git a/WebCore/platform/wx/wxcode/scrollbar_render.h b/WebCore/platform/wx/wxcode/scrollbar_render.h new file mode 100644 index 0000000..7a0ba1c --- /dev/null +++ b/WebCore/platform/wx/wxcode/scrollbar_render.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009 Kevin Ollivier 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 scrollbar_render_h +#define scrollbar_render_h + +#include <wx/defs.h> +#include <wx/dc.h> +#include <wx/renderer.h> + +enum wxScrollbarPart { + wxSCROLLPART_NONE = 0, + wxSCROLLPART_BACKBTNSTART = 1, + wxSCROLLPART_FWDBTNSTART = 1 << 1, + wxSCROLLPART_BACKTRACK = 1 << 2, + wxSCROLLPART_THUMB = 1 << 3, + wxSCROLLPART_FWDTRACK = 1 << 4, + wxSCROLLPART_BACKBTNEND = 1 << 5, + wxSCROLLPART_FWDBTNEND = 1 << 6, + wxSCROLLPART_SCROLLBARBG = 1 << 7, + wxSCROLLPART_TRACKBG = 1 << 8, + wxSCROLLPART_ALL = 0xffffffff, +}; + +void wxRenderer_DrawScrollbar(wxWindow* window, wxDC& dc, + const wxRect& rect, + wxOrientation orientation, + int current, wxScrollbarPart focusPart, wxScrollbarPart hoverPart, + int max, int step, int flags=0); + +inline void calcThumbStartAndLength(int physicalLength, int virtualLength, int current, + int step, int *thumbStart, int *thumbLength) +{ + float proportion = (float)physicalLength / virtualLength; + float scale = (float)virtualLength / physicalLength; + int thumbSize = proportion * physicalLength; + int currentPos = current / scale; + + if (thumbStart) + *thumbStart = currentPos; + + if (thumbLength) + *thumbLength = thumbSize; +} +#endif diff --git a/WebCore/platform/wx/wxcode/win/non-kerned-drawing.cpp b/WebCore/platform/wx/wxcode/win/non-kerned-drawing.cpp index d2513d7..72fcc54 100644 --- a/WebCore/platform/wx/wxcode/win/non-kerned-drawing.cpp +++ b/WebCore/platform/wx/wxcode/win/non-kerned-drawing.cpp @@ -79,13 +79,24 @@ void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* // get the native HDC handle to draw using native APIs HDC hdc = 0; + float y = point.y() - font->ascent(); + float x = point.x(); + #if USE(WXGC) + // when going from GdiPlus -> Gdi, any GdiPlus transformations are lost + // so we need to alter the coordinates to reflect their transformed point. + double xtrans = 0; + double ytrans = 0; + wxGraphicsContext* gc = dc->GetGraphicsContext(); + gc->GetTransform().TransformPoint(&xtrans, &ytrans); Gdiplus::Graphics* g; if (gc) { g = (Gdiplus::Graphics*)gc->GetNativeContext(); hdc = g->GetHDC(); } + x += (int)xtrans; + y += (int)ytrans; #else hdc = static_cast<HDC>(dc->GetHDC()); #endif @@ -95,9 +106,6 @@ void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from); const GlyphBufferAdvance* advances = glyphBuffer.advances(from); - float y = point.y() - font->ascent(); - float x = point.x(); - int* spacing = new int[numGlyphs - from]; for (unsigned i = 0; i < numGlyphs; ++i) spacing[i] = advances[i].width(); diff --git a/WebCore/platform/wx/wxcode/win/scrollbar_render.cpp b/WebCore/platform/wx/wxcode/win/scrollbar_render.cpp new file mode 100644 index 0000000..4d6bbc0 --- /dev/null +++ b/WebCore/platform/wx/wxcode/win/scrollbar_render.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2009 Kevin Ollivier 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 "scrollbar_render.h" + +#include <wx/defs.h> + +#include <wx/dc.h> +#include <wx/renderer.h> +#include <wx/window.h> + +#include <wx/msw/private.h> +#include <wx/msw/uxtheme.h> + +// constants +#define SP_BUTTON 1 +#define SP_THUMBHOR 2 +#define SP_THUMBVERT 3 +#define SP_TRACKENDHOR 4 +#define SP_TRACKENDVERT 7 +#define SP_GRIPPERHOR 8 +#define SP_GRIPPERVERT 9 + +#define TS_NORMAL 1 +#define TS_HOVER 2 +#define TS_ACTIVE 3 +#define TS_DISABLED 4 + +#define TS_UP_BUTTON 0 +#define TS_DOWN_BUTTON 4 +#define TS_LEFT_BUTTON 8 +#define TS_RIGHT_BUTTON 12 + +#if wxUSE_GRAPHICS_CONTEXT +// TODO remove this dependency (gdiplus needs the macros) +// we need to undef because the macros are being defined in WebCorePrefix.h +// but GdiPlus.h is not accepting them +#undef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) + +#undef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) + +#include <wx/dcgraph.h> +#include "gdiplus.h" +using namespace Gdiplus; +#endif // wxUSE_GRAPHICS_CONTEXT + +class GraphicsHDC +{ +public: + GraphicsHDC(wxDC* dc) + { +#if wxUSE_GRAPHICS_CONTEXT + m_graphics = NULL; + wxGCDC* gcdc = wxDynamicCast(dc, wxGCDC); + if (gcdc) { + m_graphics = (Graphics*)gcdc->GetGraphicsContext()->GetNativeContext(); + m_hdc = m_graphics->GetHDC(); + } + else +#endif + m_hdc = GetHdcOf(*dc); + } + + ~GraphicsHDC() + { +#if wxUSE_GRAPHICS_CONTEXT + if (m_graphics) + m_graphics->ReleaseHDC(m_hdc); +#endif + } + + operator HDC() const { return m_hdc; } + +private: + HDC m_hdc; +#if wxUSE_GRAPHICS_CONTEXT + Graphics* m_graphics; +#endif +}; + +int getTSStateForPart(wxScrollbarPart part, wxScrollbarPart focusPart, wxScrollbarPart hoverPart, int flags = 0) +{ + int xpState = TS_NORMAL; + if (flags & wxCONTROL_DISABLED) + xpState = TS_DISABLED; + else if (part == focusPart) + xpState = TS_ACTIVE; + else if (part == hoverPart) + xpState = TS_HOVER; + + return xpState; +} + +void wxRenderer_DrawScrollbar(wxWindow* window, wxDC& dc, + const wxRect& rect, wxOrientation orient, int current, wxScrollbarPart focusPart, wxScrollbarPart hoverPart, int max, int step, int flags) +{ + wxUxThemeEngine *engine = wxUxThemeEngine::Get(); + HTHEME hTheme = (HTHEME)engine->OpenThemeData(0, L"SCROLLBAR"); + + bool horiz = orient == wxHORIZONTAL; + int part = 0; + if (horiz) + part = SP_TRACKENDHOR; + else + part = SP_TRACKENDVERT; + + int xpState = TS_NORMAL; + RECT r; + wxCopyRectToRECT(rect, r); + + // Unlike Mac, on MSW you draw the scrollbar piece by piece. + // so we draw the track first, then the buttons + if (hTheme) + { + engine->DrawThemeBackground(hTheme, GraphicsHDC(&dc), part, xpState, &r, 0); + + int buttonSize = 16; + + part = SP_BUTTON; + xpState = getTSStateForPart(wxSCROLLPART_BACKBTNSTART, focusPart, hoverPart, flags); + xpState += horiz ? TS_LEFT_BUTTON : TS_UP_BUTTON; + RECT buttonRect = r; + buttonRect.bottom = buttonRect.top + buttonSize; + buttonRect.right = buttonRect.left + buttonSize; + engine->DrawThemeBackground(hTheme, GraphicsHDC(&dc), part, xpState, &buttonRect, 0); + + xpState = getTSStateForPart(wxSCROLLPART_FWDBTNEND, focusPart, hoverPart, flags); + xpState += horiz ? TS_RIGHT_BUTTON : TS_DOWN_BUTTON; + buttonRect = r; + buttonRect.top = buttonRect.bottom - buttonSize; + buttonRect.left = buttonRect.right - buttonSize; + engine->DrawThemeBackground(hTheme, GraphicsHDC(&dc), part, xpState, &buttonRect, 0); + + part = horiz ? SP_THUMBHOR : SP_THUMBVERT; + + int physicalLength = horiz ? rect.width : rect.height; + physicalLength -= buttonSize*2; + int thumbStart = 0; + int thumbLength = 0; + calcThumbStartAndLength(physicalLength, max + step, + current, step, &thumbStart, &thumbLength); + buttonRect = r; + if (horiz) { + buttonRect.left = thumbStart + buttonSize; + buttonRect.right = buttonRect.left + thumbLength; + } else { + buttonRect.top = thumbStart + buttonSize; + buttonRect.bottom = buttonRect.top + thumbLength; + } + + xpState = getTSStateForPart(wxSCROLLPART_THUMB, focusPart, hoverPart, flags); + engine->DrawThemeBackground(hTheme, GraphicsHDC(&dc), part, xpState, &buttonRect, 0); + + // draw the gripper + int thickness = ::GetSystemMetrics(SM_CXVSCROLL) / 2; + + buttonRect.left += ((buttonRect.right - buttonRect.left) - thickness) / 2; + buttonRect.top += ((buttonRect.bottom - buttonRect.top) - thickness) / 2; + buttonRect.right = buttonRect.left + thickness; + buttonRect.bottom = buttonRect.top + thickness; + + if (horiz) + part = SP_GRIPPERHOR; + else + part = SP_GRIPPERVERT; + + engine->DrawThemeBackground(hTheme, GraphicsHDC(&dc), part, xpState, &buttonRect, 0); + } +} |