diff options
author | Steve Block <steveblock@google.com> | 2009-12-15 10:12:09 +0000 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2009-12-17 17:41:10 +0000 |
commit | 643ca7872b450ea4efacab6188849e5aac2ba161 (patch) | |
tree | 6982576c228bcd1a7efe98afed544d840751094c /WebCore/platform/chromium | |
parent | d026980fde6eb3b01c1fe49441174e89cd1be298 (diff) | |
download | external_webkit-643ca7872b450ea4efacab6188849e5aac2ba161.zip external_webkit-643ca7872b450ea4efacab6188849e5aac2ba161.tar.gz external_webkit-643ca7872b450ea4efacab6188849e5aac2ba161.tar.bz2 |
Merge webkit.org at r51976 : Initial merge by git.
Change-Id: Ib0e7e2f0fb4bee5a186610272edf3186f0986b43
Diffstat (limited to 'WebCore/platform/chromium')
12 files changed, 733 insertions, 47 deletions
diff --git a/WebCore/platform/chromium/ChromiumBridge.h b/WebCore/platform/chromium/ChromiumBridge.h index 0c80636..3709f7c 100644 --- a/WebCore/platform/chromium/ChromiumBridge.h +++ b/WebCore/platform/chromium/ChromiumBridge.h @@ -37,6 +37,8 @@ #include "PassRefPtr.h" #include "PasteboardPrivate.h" +#include <wtf/Vector.h> + typedef struct NPObject NPObject; typedef struct _NPP NPP_t; typedef NPP_t* NPP; @@ -58,6 +60,7 @@ namespace WebCore { class String; class Widget; + struct Cookie; struct PluginInfo; // An interface to the embedding layer, which has the ability to answer @@ -82,6 +85,8 @@ namespace WebCore { // Cookies ------------------------------------------------------------ static void setCookies(const KURL& url, const KURL& firstPartyForCookies, const String& value); static String cookies(const KURL& url, const KURL& firstPartyForCookies); + static bool rawCookies(const KURL& url, const KURL& firstPartyForCookies, Vector<Cookie>*); + static void deleteCookie(const KURL& url, const String& cookieName); // DNS ---------------------------------------------------------------- static void prefetchDNS(const String& hostname); @@ -113,13 +118,13 @@ namespace WebCore { // HTML5 DB ----------------------------------------------------------- #if ENABLE(DATABASE) // 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); + static PlatformFileHandle databaseOpenFile(const String& vfsFleName, int desiredFlags, PlatformFileHandle* dirHandle = 0); // Returns a SQLite code (SQLITE_OK = 0, on success) - static int databaseDeleteFile(const String& fileName, bool syncDir = false); + static int databaseDeleteFile(const String& vfsFileName, bool syncDir = false); // Returns the attributes of the DB file - static long databaseGetFileAttributes(const String& fileName); + static long databaseGetFileAttributes(const String& vfsFileName); // Returns the size of the DB file - static long long databaseGetFileSize(const String& fileName); + static long long databaseGetFileSize(const String& vfsFileName); #endif // JavaScript --------------------------------------------------------- @@ -135,6 +140,11 @@ namespace WebCore { // LayoutTestMode ----------------------------------------------------- static bool layoutTestMode(); + // Memory ------------------------------------------------------------- + // Returns the current space allocated for the pagefile, in MB. + // That is committed size for Windows and virtual memory size for POSIX + static int memoryUsageMB(); + // MimeType ----------------------------------------------------------- static bool isSupportedImageMIMEType(const String& mimeType); static bool isSupportedJavaScriptMIMEType(const String& mimeType); @@ -148,9 +158,6 @@ namespace WebCore { static NPObject* pluginScriptableObject(Widget*); static bool popupsAllowed(NPP); - // Protocol ----------------------------------------------------------- - static String uiResourceProtocol(); // deprecated - // Resources ---------------------------------------------------------- static PassRefPtr<Image> loadPlatformImageResource(const char* name); diff --git a/WebCore/platform/chromium/ClipboardChromium.cpp b/WebCore/platform/chromium/ClipboardChromium.cpp index d330d3b..1a2caa4 100644 --- a/WebCore/platform/chromium/ClipboardChromium.cpp +++ b/WebCore/platform/chromium/ClipboardChromium.cpp @@ -354,7 +354,7 @@ void ClipboardChromium::writeRange(Range* selectedRange, Frame* frame) m_dataObject->textHtml = createMarkup(selectedRange, 0, AnnotateForInterchange); #if PLATFORM(DARWIN) - m_dataObject->textHtml = String("<meta charset='utf-8'>") + m_dataObject->textHtml; + m_dataObject->textHtml = String("<meta charset='utf-8' id='webkit-interchange-charset'>") + m_dataObject->textHtml; #endif m_dataObject->htmlBaseUrl = frame->document()->url(); diff --git a/WebCore/platform/chromium/ContextMenuChromium.cpp b/WebCore/platform/chromium/ContextMenuChromium.cpp index 0614e3e..93c0ec4 100644 --- a/WebCore/platform/chromium/ContextMenuChromium.cpp +++ b/WebCore/platform/chromium/ContextMenuChromium.cpp @@ -38,13 +38,11 @@ namespace WebCore { ContextMenu::ContextMenu(const HitTestResult& result) : m_hitTestResult(result) - , m_platformDescription(0) { } ContextMenu::ContextMenu(const HitTestResult& result, const PlatformMenuDescription menu) : m_hitTestResult(result) - , m_platformDescription(0) { } @@ -54,25 +52,31 @@ ContextMenu::~ContextMenu() unsigned ContextMenu::itemCount() const { - return 0; + return m_items.size(); } void ContextMenu::insertItem(unsigned position, ContextMenuItem& item) { + m_items.insert(position, item); } void ContextMenu::appendItem(ContextMenuItem& item) { + m_items.append(item); } ContextMenuItem* ContextMenu::itemWithAction(unsigned action) { + for (size_t i = 0; i < m_items.size(); ++i) { + if (m_items[i].action() == static_cast<ContextMenuAction>(action)) + return &m_items[i]; + } return 0; } ContextMenuItem* ContextMenu::itemAtIndex(unsigned index, const PlatformMenuDescription platformDescription) { - return 0; + return &m_items[index]; } void ContextMenu::setPlatformDescription(PlatformMenuDescription menu) @@ -81,7 +85,7 @@ void ContextMenu::setPlatformDescription(PlatformMenuDescription menu) PlatformMenuDescription ContextMenu::platformDescription() const { - return m_platformDescription; + return 0; } PlatformMenuDescription ContextMenu::releasePlatformDescription() diff --git a/WebCore/platform/chromium/ContextMenuItemChromium.cpp b/WebCore/platform/chromium/ContextMenuItemChromium.cpp index f34ea23..6a0d657 100644 --- a/WebCore/platform/chromium/ContextMenuItemChromium.cpp +++ b/WebCore/platform/chromium/ContextMenuItemChromium.cpp @@ -46,6 +46,9 @@ ContextMenuItem::ContextMenuItem(ContextMenu* subMenu) ContextMenuItem::ContextMenuItem(ContextMenuItemType type, ContextMenuAction action, const String& title, ContextMenu* subMenu) { + m_platformDescription.type = type; + m_platformDescription.action = action; + m_platformDescription.title = title; } ContextMenuItem::~ContextMenuItem() @@ -54,22 +57,32 @@ ContextMenuItem::~ContextMenuItem() PlatformMenuItemDescription ContextMenuItem::releasePlatformDescription() { - return PlatformMenuItemDescription(); + return m_platformDescription; } ContextMenuItemType ContextMenuItem::type() const { - return ContextMenuItemType(); + return m_platformDescription.type; } ContextMenuAction ContextMenuItem::action() const { - return ContextMenuAction(); + return m_platformDescription.action; } String ContextMenuItem::title() const { - return String(); + return m_platformDescription.title; +} + +bool ContextMenuItem::checked() const +{ + return m_platformDescription.checked; +} + +bool ContextMenuItem::enabled() const +{ + return m_platformDescription.enabled; } PlatformMenuDescription ContextMenuItem::platformSubMenu() const @@ -79,14 +92,17 @@ PlatformMenuDescription ContextMenuItem::platformSubMenu() const void ContextMenuItem::setType(ContextMenuItemType type) { + m_platformDescription.type = type; } void ContextMenuItem::setAction(ContextMenuAction action) { + m_platformDescription.action = action; } void ContextMenuItem::setTitle(const String& title) { + m_platformDescription.title = title; } void ContextMenuItem::setSubMenu(ContextMenu* subMenu) @@ -95,15 +111,12 @@ void ContextMenuItem::setSubMenu(ContextMenu* subMenu) void ContextMenuItem::setChecked(bool checked) { + m_platformDescription.checked = checked; } void ContextMenuItem::setEnabled(bool enabled) { -} - -bool ContextMenuItem::enabled() const -{ - return false; + m_platformDescription.enabled = enabled; } } // namespace WebCore diff --git a/WebCore/platform/chromium/GeolocationServiceChromium.cpp b/WebCore/platform/chromium/GeolocationServiceChromium.cpp new file mode 100644 index 0000000..65886b0 --- /dev/null +++ b/WebCore/platform/chromium/GeolocationServiceChromium.cpp @@ -0,0 +1,55 @@ +/* + * 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 "GeolocationService.h" + +namespace WebCore { + +class GeolocationServiceChromium : public GeolocationService { +public: + GeolocationServiceChromium(GeolocationServiceClient* c) + : GeolocationService(c) + { + } + // FIXME: Implement. https://bugs.webkit.org/show_bug.cgi?id=32068 +}; + +// This guard is the counterpart of the one in WebCore/platform/GeolocationService.cpp +#if ENABLE(GEOLOCATION) +static GeolocationService* createGeolocationService(GeolocationServiceClient* c) +{ + return new GeolocationServiceChromium(c); +} + +GeolocationService::FactoryFunction* GeolocationService::s_factoryFunction = &createGeolocationService; +#endif + +} // namespace WebCore diff --git a/WebCore/platform/chromium/MIMETypeRegistryChromium.cpp b/WebCore/platform/chromium/MIMETypeRegistryChromium.cpp index 51bff80..ff0be82 100644 --- a/WebCore/platform/chromium/MIMETypeRegistryChromium.cpp +++ b/WebCore/platform/chromium/MIMETypeRegistryChromium.cpp @@ -34,6 +34,7 @@ #include "ChromiumBridge.h" #include "CString.h" #include "MediaPlayer.h" +#include "PluginDataChromium.h" // NOTE: Unlike other ports, we don't use the shared implementation bits in // MIMETypeRegistry.cpp. Instead, we need to route most functions via the @@ -41,11 +42,6 @@ namespace WebCore { -// Checks if any of the plugins handle this extension, and if so returns the -// plugin's mime type for this extension. Otherwise returns an empty string. -// See PluginsChromium.cpp for the implementation of this function. -String getPluginMimeTypeFromExtension(const String& extension); - String MIMETypeRegistry::getMIMETypeForExtension(const String &ext) { return ChromiumBridge::mimeTypeForExtension(ext); diff --git a/WebCore/platform/chromium/PasteboardChromium.cpp b/WebCore/platform/chromium/PasteboardChromium.cpp index 4929eb8..ce06e55 100644 --- a/WebCore/platform/chromium/PasteboardChromium.cpp +++ b/WebCore/platform/chromium/PasteboardChromium.cpp @@ -83,7 +83,7 @@ void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, { String html = createMarkup(selectedRange, 0, AnnotateForInterchange); #if PLATFORM(DARWIN) - html = String("<meta charset='utf-8'>") + html; + html = String("<meta charset='utf-8' id='webkit-interchange-charset'>") + html; #endif ExceptionCode ec = 0; KURL url = selectedRange->startContainer(ec)->document()->url(); @@ -170,6 +170,11 @@ PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefP String markup; KURL srcURL; ChromiumBridge::clipboardReadHTML(buffer, &markup, &srcURL); +#if PLATFORM(DARWIN) + DEFINE_STATIC_LOCAL(const String, forceUtf8String, ("<meta charset='utf-8' id='webkit-interchange-charset'>")); + if (markup.startsWith(forceUtf8String)) + markup = markup.substring(forceUtf8String.length()); +#endif RefPtr<DocumentFragment> fragment = createFragmentFromMarkup(frame->document(), markup, srcURL); diff --git a/WebCore/platform/chromium/PopupMenuChromium.cpp b/WebCore/platform/chromium/PopupMenuChromium.cpp index d6f895d..5abd364 100644 --- a/WebCore/platform/chromium/PopupMenuChromium.cpp +++ b/WebCore/platform/chromium/PopupMenuChromium.cpp @@ -370,6 +370,12 @@ void PopupContainer::showExternal(const IntRect& rect, FrameView* v, int index) ChromeClientChromium* client = static_cast<ChromeClientChromium*>( v->frame()->page()->chrome()->client()); client->popupOpened(this, popupRect, true, true); + + // The popup sends its "closed" notification through its parent. Set the + // parent, even though external popups have no real on-screen widget but a + // native menu (see |PopupListBox::hidePopup()|); + if (!m_listBox->parent()) + addChild(m_listBox.get()); } void PopupContainer::hidePopup() @@ -446,7 +452,7 @@ void PopupContainer::paintBorder(GraphicsContext* gc, const IntRect& rect) Color borderColor(127, 157, 185); gc->setStrokeStyle(NoStroke); - gc->setFillColor(borderColor); + gc->setFillColor(borderColor, DeviceColorSpace); int tx = x(); int ty = y(); @@ -772,7 +778,7 @@ void PopupListBox::paint(GraphicsContext* gc, const IntRect& rect) // Special case for an empty popup. if (numItems() == 0) - gc->fillRect(r, Color::white); + gc->fillRect(r, Color::white, DeviceColorSpace); gc->restore(); @@ -805,23 +811,23 @@ void PopupListBox::paintRow(GraphicsContext* gc, const IntRect& rect, int rowInd // If we have a transparent background, make sure it has a color to blend // against. if (backColor.hasAlpha()) - gc->fillRect(rowRect, Color::white); + gc->fillRect(rowRect, Color::white, DeviceColorSpace); - gc->fillRect(rowRect, backColor); + gc->fillRect(rowRect, backColor, DeviceColorSpace); if (m_popupClient->itemIsSeparator(rowIndex)) { IntRect separatorRect( rowRect.x() + separatorPadding, rowRect.y() + (rowRect.height() - separatorHeight) / 2, rowRect.width() - 2 * separatorPadding, separatorHeight); - gc->fillRect(separatorRect, textColor); + gc->fillRect(separatorRect, textColor, DeviceColorSpace); return; } if (!style.isVisible()) return; - gc->setFillColor(textColor); + gc->setFillColor(textColor, DeviceColorSpace); Font itemFont = getRowFont(rowIndex); // FIXME: http://crbug.com/19872 We should get the padding of individual option diff --git a/WebCore/platform/chromium/ScrollbarThemeChromium.cpp b/WebCore/platform/chromium/ScrollbarThemeChromium.cpp index 725de10..a6720a1 100644 --- a/WebCore/platform/chromium/ScrollbarThemeChromium.cpp +++ b/WebCore/platform/chromium/ScrollbarThemeChromium.cpp @@ -113,7 +113,7 @@ void ScrollbarThemeChromium::paintTickmarks(GraphicsContext* context, Scrollbar* const int yPos = rect.topLeft().y() + (rect.height() * percent); IntPoint tick(scrollbar->x(), yPos); - context->drawImage(dash.get(), tick); + context->drawImage(dash.get(), DeviceColorSpace, tick); } context->restore(); diff --git a/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp b/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp index 64f58c4..3a1a652 100644 --- a/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp +++ b/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp @@ -33,6 +33,8 @@ #include "PlatformContextSkia.h" #include "PlatformMouseEvent.h" +#include "RenderTheme.h" +#include "RenderThemeChromiumLinux.h" #include "Scrollbar.h" #include "TransformationMatrix.h" @@ -73,6 +75,60 @@ static void drawBox(SkCanvas* canvas, const IntRect& rect, const SkPaint& paint) drawVertLine(canvas, rect.x(), rect.y(), bottom, paint); } +static SkScalar clamp(SkScalar value, SkScalar min, SkScalar max) +{ + return std::min(std::max(value, min), max); +} + +static SkColor saturateAndBrighten(SkScalar* hsv, + SkScalar saturateAmount, + SkScalar brightenAmount) +{ + SkScalar color[3]; + color[0] = hsv[0]; + color[1] = clamp(hsv[1] + saturateAmount, 0.0, 1.0); + color[2] = clamp(hsv[2] + brightenAmount, 0.0, 1.0); + return SkHSVToColor(color); +} + +static SkColor outlineColor(SkScalar* hsv1, SkScalar* hsv2) +{ + // GTK Theme engines have way too much control over the layout of + // the scrollbar. We might be able to more closely approximate its + // look-and-feel, if we sent whole images instead of just colors + // from the browser to the renderer. But even then, some themes + // would just break. + // + // So, instead, we don't even try to 100% replicate the look of + // the native scrollbar. We render our own version, but we make + // sure to pick colors that blend in nicely with the system GTK + // theme. In most cases, we can just sample a couple of pixels + // from the system scrollbar and use those colors to draw our + // scrollbar. + // + // This works fine for the track color and the overall thumb + // color. But it fails spectacularly for the outline color used + // around the thumb piece. Not all themes have a clearly defined + // outline. For some of them it is partially transparent, and for + // others the thickness is very unpredictable. + // + // So, instead of trying to approximate the system theme, we + // instead try to compute a reasonable looking choice based on the + // known color of the track and the thumb piece. This is difficult + // when trying to deal both with high- and low-contrast themes, + // and both with positive and inverted themes. + // + // The following code has been tested to look OK with all of the + // default GTK themes. + SkScalar minDiff = clamp((hsv1[1] + hsv2[1]) * 1.2, 0.2, 0.5); + SkScalar diff = clamp(fabs(hsv1[2] - hsv2[2]) / 2, minDiff, 0.5); + + if (hsv1[2] + hsv2[2] > 1.0) + diff = -diff; + + return saturateAndBrighten(hsv2, -0.2, diff); +} + IntRect ScrollbarThemeChromium::trackRect(Scrollbar* scrollbar, bool) { IntSize bs = buttonSize(scrollbar); @@ -89,10 +145,16 @@ void ScrollbarThemeChromiumLinux::paintTrackPiece(GraphicsContext* gc, Scrollbar SkIRect skrect; skrect.set(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height()); - paint.setARGB(0xff, 0xe3, 0xdd, 0xd8); + SkScalar track_hsv[3]; + SkColorToHSV(RenderThemeChromiumLinux::trackColor(), track_hsv); + paint.setColor(saturateAndBrighten(track_hsv, 0, 0)); canvas->drawIRect(skrect, paint); - paint.setARGB(0xff, 0xc5, 0xba, 0xb0); + SkScalar thumb_hsv[3]; + SkColorToHSV(RenderThemeChromiumLinux::thumbInactiveColor(), + thumb_hsv); + + paint.setColor(outlineColor(track_hsv, thumb_hsv)); drawBox(canvas, rect, paint); } @@ -109,11 +171,14 @@ void ScrollbarThemeChromiumLinux::paintThumb(GraphicsContext* gc, Scrollbar* scr const bool vertical = scrollbar->orientation() == VerticalScrollbar; SkCanvas* const canvas = gc->platformContext()->canvas(); + SkScalar thumb[3]; + SkColorToHSV(hovered + ? RenderThemeChromiumLinux::thumbActiveColor() + : RenderThemeChromiumLinux::thumbInactiveColor(), + thumb); + SkPaint paint; - if (hovered) - paint.setARGB(0xff, 0xff, 0xff, 0xff); - else - paint.setARGB(0xff, 0xf4, 0xf2, 0xef); + paint.setColor(saturateAndBrighten(thumb, 0, 0.02)); SkIRect skrect; if (vertical) @@ -123,10 +188,7 @@ void ScrollbarThemeChromiumLinux::paintThumb(GraphicsContext* gc, Scrollbar* scr canvas->drawIRect(skrect, paint); - if (hovered) - paint.setARGB(0xff, 0xf4, 0xf2, 0xef); - else - paint.setARGB(0xff, 0xea, 0xe5, 0xe0); + paint.setColor(saturateAndBrighten(thumb, 0, -0.02)); if (vertical) skrect.set(midx + 1, rect.y(), rect.x() + rect.width(), rect.y() + rect.height()); @@ -135,11 +197,12 @@ void ScrollbarThemeChromiumLinux::paintThumb(GraphicsContext* gc, Scrollbar* scr canvas->drawIRect(skrect, paint); - paint.setARGB(0xff, 0x9d, 0x96, 0x8e); + SkScalar track[3]; + SkColorToHSV(RenderThemeChromiumLinux::trackColor(), track); + paint.setColor(outlineColor(track, thumb)); drawBox(canvas, rect, paint); if (rect.height() > 10 && rect.width() > 10) { - paint.setARGB(0xff, 0x9d, 0x96, 0x8e); const int grippyHalfWidth = 2; const int interGrippyOffset = 3; if (vertical) { diff --git a/WebCore/platform/chromium/ScrollbarThemeChromiumMac.h b/WebCore/platform/chromium/ScrollbarThemeChromiumMac.h new file mode 100644 index 0000000..1ab2f18 --- /dev/null +++ b/WebCore/platform/chromium/ScrollbarThemeChromiumMac.h @@ -0,0 +1,74 @@ +/* + * 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 ScrollbarThemeChromiumMac_h +#define ScrollbarThemeChromiumMac_h + +#include "ScrollbarThemeComposite.h" + +// This file (and its associated .mm file) is a clone of ScrollbarThemeMac.h. +// See the .mm file for details. + +namespace WebCore { + +class ScrollbarThemeChromiumMac : public ScrollbarThemeComposite { +public: + ScrollbarThemeChromiumMac(); + virtual ~ScrollbarThemeChromiumMac(); + + virtual bool paint(Scrollbar*, GraphicsContext* context, const IntRect& damageRect); + + virtual int scrollbarThickness(ScrollbarControlSize = RegularScrollbar); + + virtual bool supportsControlTints() const { return true; } + + virtual double initialAutoscrollTimerDelay(); + virtual double autoscrollTimerDelay(); + + virtual ScrollbarButtonsPlacement buttonsPlacement() const; + + virtual void registerScrollbar(Scrollbar*); + virtual void unregisterScrollbar(Scrollbar*); + +protected: + virtual bool hasButtons(Scrollbar*); + virtual bool hasThumb(Scrollbar*); + + virtual IntRect backButtonRect(Scrollbar*, ScrollbarPart, bool painting = false); + virtual IntRect forwardButtonRect(Scrollbar*, ScrollbarPart, bool painting = false); + virtual IntRect trackRect(Scrollbar*, bool painting = false); + + virtual int minimumThumbLength(Scrollbar*); + + virtual bool shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent&); + +public: + void preferencesChanged(); +}; + +} + +#endif // ScrollbarThemeChromiumMac_h diff --git a/WebCore/platform/chromium/ScrollbarThemeChromiumMac.mm b/WebCore/platform/chromium/ScrollbarThemeChromiumMac.mm new file mode 100644 index 0000000..b4ebaf6 --- /dev/null +++ b/WebCore/platform/chromium/ScrollbarThemeChromiumMac.mm @@ -0,0 +1,463 @@ +/* + * 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. + */ + +#include "config.h" +#include "ScrollbarThemeChromiumMac.h" + +#include "ImageBuffer.h" +#include "PlatformMouseEvent.h" +#include "ScrollView.h" +#include <Carbon/Carbon.h> +#include <wtf/StdLibExtras.h> +#include <wtf/UnusedParam.h> + +// FIXME: There are repainting problems due to Aqua scroll bar buttons' visual overflow. + +using namespace std; +using namespace WebCore; + +// This file (and its associated .h file) is a clone of ScrollbarThemeMac.mm. +// Because we want to draw tickmarks in the scrollbar, we must maintain a fork. +// Please maintain this file by performing parallel changes to it. +// +// The only changes from ScrollbarThemeMac should be: +// - The classname change from ScrollbarThemeMac to ScrollbarThemeChromiumMac. +// - In paint() the code to paint the track, tickmarks, and thumb separately. +// +// 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. + +static HashSet<Scrollbar*>* gScrollbars; + +@interface ScrollbarPrefsObserver : NSObject +{ + +} + ++ (void)registerAsObserver; ++ (void)appearancePrefsChanged:(NSNotification*)theNotification; ++ (void)behaviorPrefsChanged:(NSNotification*)theNotification; + +@end + +@implementation ScrollbarPrefsObserver + ++ (void)appearancePrefsChanged:(NSNotification*)unusedNotification +{ + UNUSED_PARAM(unusedNotification); + + static_cast<ScrollbarThemeChromiumMac*>(ScrollbarTheme::nativeTheme())->preferencesChanged(); + if (!gScrollbars) + return; + HashSet<Scrollbar*>::iterator end = gScrollbars->end(); + for (HashSet<Scrollbar*>::iterator it = gScrollbars->begin(); it != end; ++it) { + (*it)->styleChanged(); + (*it)->invalidate(); + } +} + ++ (void)behaviorPrefsChanged:(NSNotification*)unusedNotification +{ + UNUSED_PARAM(unusedNotification); + + static_cast<ScrollbarThemeChromiumMac*>(ScrollbarTheme::nativeTheme())->preferencesChanged(); +} + ++ (void)registerAsObserver +{ + [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(appearancePrefsChanged:) name:@"AppleAquaScrollBarVariantChanged" object:nil suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately]; + [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(behaviorPrefsChanged:) name:@"AppleNoRedisplayAppearancePreferenceChanged" object:nil suspensionBehavior:NSNotificationSuspensionBehaviorCoalesce]; +} + +@end + +namespace WebCore { + +ScrollbarTheme* ScrollbarTheme::nativeTheme() +{ + DEFINE_STATIC_LOCAL(ScrollbarThemeChromiumMac, theme, ()); + return &theme; +} + +// FIXME: Get these numbers from CoreUI. +static int cScrollbarThickness[] = { 15, 11 }; +static int cRealButtonLength[] = { 28, 21 }; +static int cButtonInset[] = { 14, 11 }; +static int cButtonHitInset[] = { 3, 2 }; +// cRealButtonLength - cButtonInset +static int cButtonLength[] = { 14, 10 }; +static int cThumbMinLength[] = { 26, 20 }; + +static int cOuterButtonLength[] = { 16, 14 }; // The outer button in a double button pair is a bit bigger. +static int cOuterButtonOverlap = 2; + +static float gInitialButtonDelay = 0.5f; +static float gAutoscrollButtonDelay = 0.05f; +static bool gJumpOnTrackClick = false; +static ScrollbarButtonsPlacement gButtonPlacement = ScrollbarButtonsDoubleEnd; + +static void updateArrowPlacement() +{ + NSString *buttonPlacement = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollBarVariant"]; + if ([buttonPlacement isEqualToString:@"Single"]) + gButtonPlacement = ScrollbarButtonsSingle; + else if ([buttonPlacement isEqualToString:@"DoubleMin"]) + gButtonPlacement = ScrollbarButtonsDoubleStart; + else if ([buttonPlacement isEqualToString:@"DoubleBoth"]) + gButtonPlacement = ScrollbarButtonsDoubleBoth; + else + gButtonPlacement = ScrollbarButtonsDoubleEnd; // The default is ScrollbarButtonsDoubleEnd. +} + +void ScrollbarThemeChromiumMac::registerScrollbar(Scrollbar* scrollbar) +{ + if (!gScrollbars) + gScrollbars = new HashSet<Scrollbar*>; + gScrollbars->add(scrollbar); +} + +void ScrollbarThemeChromiumMac::unregisterScrollbar(Scrollbar* scrollbar) +{ + gScrollbars->remove(scrollbar); + if (gScrollbars->isEmpty()) { + delete gScrollbars; + gScrollbars = 0; + } +} + +ScrollbarThemeChromiumMac::ScrollbarThemeChromiumMac() +{ + static bool initialized; + if (!initialized) { + initialized = true; + [ScrollbarPrefsObserver registerAsObserver]; + preferencesChanged(); + } +} + +ScrollbarThemeChromiumMac::~ScrollbarThemeChromiumMac() +{ +} + +void ScrollbarThemeChromiumMac::preferencesChanged() +{ + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults synchronize]; + updateArrowPlacement(); + gInitialButtonDelay = [defaults floatForKey:@"NSScrollerButtonDelay"]; + gAutoscrollButtonDelay = [defaults floatForKey:@"NSScrollerButtonPeriod"]; + gJumpOnTrackClick = [defaults boolForKey:@"AppleScrollerPagingBehavior"]; +} + +int ScrollbarThemeChromiumMac::scrollbarThickness(ScrollbarControlSize controlSize) +{ + return cScrollbarThickness[controlSize]; +} + +double ScrollbarThemeChromiumMac::initialAutoscrollTimerDelay() +{ + return gInitialButtonDelay; +} + +double ScrollbarThemeChromiumMac::autoscrollTimerDelay() +{ + return gAutoscrollButtonDelay; +} + +ScrollbarButtonsPlacement ScrollbarThemeChromiumMac::buttonsPlacement() const +{ + return gButtonPlacement; +} + +bool ScrollbarThemeChromiumMac::hasButtons(Scrollbar* scrollbar) +{ + return scrollbar->enabled() && (scrollbar->orientation() == HorizontalScrollbar ? + scrollbar->width() : + scrollbar->height()) >= 2 * (cRealButtonLength[scrollbar->controlSize()] - cButtonHitInset[scrollbar->controlSize()]); +} + +bool ScrollbarThemeChromiumMac::hasThumb(Scrollbar* scrollbar) +{ + return scrollbar->enabled() && (scrollbar->orientation() == HorizontalScrollbar ? + scrollbar->width() : + scrollbar->height()) >= 2 * cButtonInset[scrollbar->controlSize()] + cThumbMinLength[scrollbar->controlSize()] + 1; +} + +static IntRect buttonRepaintRect(const IntRect& buttonRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize, bool start) +{ + IntRect paintRect(buttonRect); + if (orientation == HorizontalScrollbar) { + paintRect.setWidth(cRealButtonLength[controlSize]); + if (!start) + paintRect.setX(buttonRect.x() - (cRealButtonLength[controlSize] - buttonRect.width())); + } else { + paintRect.setHeight(cRealButtonLength[controlSize]); + if (!start) + paintRect.setY(buttonRect.y() - (cRealButtonLength[controlSize] - buttonRect.height())); + } + + return paintRect; +} + +IntRect ScrollbarThemeChromiumMac::backButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool painting) +{ + IntRect result; + + if (part == BackButtonStartPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleEnd)) + return result; + + if (part == BackButtonEndPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleStart || buttonsPlacement() == ScrollbarButtonsSingle)) + return result; + + int thickness = scrollbarThickness(scrollbar->controlSize()); + bool outerButton = part == BackButtonStartPart && (buttonsPlacement() == ScrollbarButtonsDoubleStart || buttonsPlacement() == ScrollbarButtonsDoubleBoth); + if (outerButton) { + if (scrollbar->orientation() == HorizontalScrollbar) + result = IntRect(scrollbar->x(), scrollbar->y(), cOuterButtonLength[scrollbar->controlSize()] + painting ? cOuterButtonOverlap : 0, thickness); + else + result = IntRect(scrollbar->x(), scrollbar->y(), thickness, cOuterButtonLength[scrollbar->controlSize()] + painting ? cOuterButtonOverlap : 0); + return result; + } + + // Our repaint rect is slightly larger, since we are a button that is adjacent to the track. + if (scrollbar->orientation() == HorizontalScrollbar) { + int start = part == BackButtonStartPart ? scrollbar->x() : scrollbar->x() + scrollbar->width() - cOuterButtonLength[scrollbar->controlSize()] - cButtonLength[scrollbar->controlSize()]; + result = IntRect(start, scrollbar->y(), cButtonLength[scrollbar->controlSize()], thickness); + } else { + int start = part == BackButtonStartPart ? scrollbar->y() : scrollbar->y() + scrollbar->height() - cOuterButtonLength[scrollbar->controlSize()] - cButtonLength[scrollbar->controlSize()]; + result = IntRect(scrollbar->x(), start, thickness, cButtonLength[scrollbar->controlSize()]); + } + + if (painting) + return buttonRepaintRect(result, scrollbar->orientation(), scrollbar->controlSize(), part == BackButtonStartPart); + return result; +} + +IntRect ScrollbarThemeChromiumMac::forwardButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool painting) +{ + IntRect result; + + if (part == ForwardButtonEndPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleStart)) + return result; + + if (part == ForwardButtonStartPart && (buttonsPlacement() == ScrollbarButtonsNone || buttonsPlacement() == ScrollbarButtonsDoubleEnd || buttonsPlacement() == ScrollbarButtonsSingle)) + return result; + + int thickness = scrollbarThickness(scrollbar->controlSize()); + int outerButtonLength = cOuterButtonLength[scrollbar->controlSize()]; + int buttonLength = cButtonLength[scrollbar->controlSize()]; + + bool outerButton = part == ForwardButtonEndPart && (buttonsPlacement() == ScrollbarButtonsDoubleEnd || buttonsPlacement() == ScrollbarButtonsDoubleBoth); + if (outerButton) { + if (scrollbar->orientation() == HorizontalScrollbar) { + result = IntRect(scrollbar->x() + scrollbar->width() - outerButtonLength, scrollbar->y(), outerButtonLength, thickness); + if (painting) + result.inflateX(cOuterButtonOverlap); + } else { + result = IntRect(scrollbar->x(), scrollbar->y() + scrollbar->height() - outerButtonLength, thickness, outerButtonLength); + if (painting) + result.inflateY(cOuterButtonOverlap); + } + return result; + } + + if (scrollbar->orientation() == HorizontalScrollbar) { + int start = part == ForwardButtonEndPart ? scrollbar->x() + scrollbar->width() - buttonLength : scrollbar->x() + outerButtonLength; + result = IntRect(start, scrollbar->y(), buttonLength, thickness); + } else { + int start = part == ForwardButtonEndPart ? scrollbar->y() + scrollbar->height() - buttonLength : scrollbar->y() + outerButtonLength; + result = IntRect(scrollbar->x(), start, thickness, buttonLength); + } + if (painting) + return buttonRepaintRect(result, scrollbar->orientation(), scrollbar->controlSize(), part == ForwardButtonStartPart); + return result; +} + +IntRect ScrollbarThemeChromiumMac::trackRect(Scrollbar* scrollbar, bool painting) +{ + if (painting || !hasButtons(scrollbar)) + return scrollbar->frameRect(); + + IntRect result; + int thickness = scrollbarThickness(scrollbar->controlSize()); + int startWidth = 0; + int endWidth = 0; + int outerButtonLength = cOuterButtonLength[scrollbar->controlSize()]; + int buttonLength = cButtonLength[scrollbar->controlSize()]; + int doubleButtonLength = outerButtonLength + buttonLength; + switch (buttonsPlacement()) { + case ScrollbarButtonsSingle: + startWidth = buttonLength; + endWidth = buttonLength; + break; + case ScrollbarButtonsDoubleStart: + startWidth = doubleButtonLength; + break; + case ScrollbarButtonsDoubleEnd: + endWidth = doubleButtonLength; + break; + case ScrollbarButtonsDoubleBoth: + startWidth = doubleButtonLength; + endWidth = doubleButtonLength; + break; + default: + break; + } + + int totalWidth = startWidth + endWidth; + if (scrollbar->orientation() == HorizontalScrollbar) + return IntRect(scrollbar->x() + startWidth, scrollbar->y(), scrollbar->width() - totalWidth, thickness); + return IntRect(scrollbar->x(), scrollbar->y() + startWidth, thickness, scrollbar->height() - totalWidth); +} + +int ScrollbarThemeChromiumMac::minimumThumbLength(Scrollbar* scrollbar) +{ + return cThumbMinLength[scrollbar->controlSize()]; +} + +bool ScrollbarThemeChromiumMac::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& evt) +{ + if (evt.button() != LeftButton) + return false; + if (gJumpOnTrackClick) + return !evt.altKey(); + return evt.altKey(); +} + +static int scrollbarPartToHIPressedState(ScrollbarPart part) +{ + switch (part) { + case BackButtonStartPart: + return kThemeTopOutsideArrowPressed; + case BackButtonEndPart: + return kThemeTopOutsideArrowPressed; // This does not make much sense. For some reason the outside constant is required. + case ForwardButtonStartPart: + return kThemeTopInsideArrowPressed; + case ForwardButtonEndPart: + return kThemeBottomOutsideArrowPressed; + case ThumbPart: + return kThemeThumbPressed; + default: + return 0; + } +} + +bool ScrollbarThemeChromiumMac::paint(Scrollbar* scrollbar, GraphicsContext* context, const IntRect& damageRect) +{ + HIThemeTrackDrawInfo trackInfo; + trackInfo.version = 0; + trackInfo.kind = scrollbar->controlSize() == RegularScrollbar ? kThemeMediumScrollBar : kThemeSmallScrollBar; + trackInfo.bounds = scrollbar->frameRect(); + trackInfo.min = 0; + trackInfo.max = scrollbar->maximum(); + trackInfo.value = scrollbar->currentPos(); + trackInfo.trackInfo.scrollbar.viewsize = scrollbar->pageStep(); + trackInfo.attributes = 0; + if (scrollbar->orientation() == HorizontalScrollbar) + trackInfo.attributes |= kThemeTrackHorizontal; + + if (!scrollbar->enabled()) + trackInfo.enableState = kThemeTrackDisabled; + else + trackInfo.enableState = scrollbar->client()->isActive() ? kThemeTrackActive : kThemeTrackInactive; + + if (!hasButtons(scrollbar)) + trackInfo.enableState = kThemeTrackNothingToScroll; + trackInfo.trackInfo.scrollbar.pressState = scrollbarPartToHIPressedState(scrollbar->pressedPart()); + + CGAffineTransform currentCTM = CGContextGetCTM(context->platformContext()); + + // The Aqua scrollbar is buggy when rotated and scaled. We will just draw into a bitmap if we detect a scale or rotation. + bool canDrawDirectly = currentCTM.a == 1.0f && currentCTM.b == 0.0f && currentCTM.c == 0.0f && (currentCTM.d == 1.0f || currentCTM.d == -1.0f); + GraphicsContext* drawingContext = context; + OwnPtr<ImageBuffer> imageBuffer; + if (!canDrawDirectly) { + trackInfo.bounds = IntRect(IntPoint(), scrollbar->frameRect().size()); + + IntRect bufferRect(scrollbar->frameRect()); + bufferRect.intersect(damageRect); + bufferRect.move(-scrollbar->frameRect().x(), -scrollbar->frameRect().y()); + + imageBuffer = ImageBuffer::create(bufferRect.size()); + if (!imageBuffer) + return true; + + drawingContext = imageBuffer->context(); + } + + // Draw thumbless. + HIThemeDrawTrack(&trackInfo, 0, drawingContext->platformContext(), kHIThemeOrientationNormal); + + Vector<IntRect> tickmarks; + scrollbar->client()->getTickmarks(tickmarks); + if (scrollbar->orientation() == VerticalScrollbar && tickmarks.size()) { + drawingContext->save(); + drawingContext->setShouldAntialias(false); + drawingContext->setStrokeColor(Color(0xCC, 0xAA, 0x00, 0xFF), DeviceColorSpace); + drawingContext->setFillColor(Color(0xFF, 0xDD, 0x00, 0xFF), DeviceColorSpace); + + IntRect thumbArea = trackRect(scrollbar, false); + if (!canDrawDirectly) { + thumbArea.setX(0); + thumbArea.setY(0); + } + // The ends are rounded and the thumb doesn't go there. + thumbArea.inflateY(-thumbArea.width()); + + for (Vector<IntRect>::const_iterator i = tickmarks.begin(); i != tickmarks.end(); ++i) { + // Calculate how far down (in %) the tick-mark should appear. + const float percent = static_cast<float>(i->y()) / scrollbar->totalSize(); + if (percent < 0.0 || percent > 1.0) + continue; + + // Calculate how far down (in pixels) the tick-mark should appear. + const int yPos = static_cast<int>((thumbArea.topLeft().y() + (thumbArea.height() * percent))) & ~1; + + // Paint. + const int indent = 2; + FloatRect tickRect(thumbArea.topLeft().x() + indent, yPos, thumbArea.width() - 2 * indent - 1, 2); + drawingContext->fillRect(tickRect); + drawingContext->strokeRect(tickRect, 1); + } + + drawingContext->restore(); + } + + if (hasThumb(scrollbar)) { + trackInfo.attributes |= (kThemeTrackShowThumb | kThemeTrackHideTrack); + HIThemeDrawTrack(&trackInfo, 0, drawingContext->platformContext(), kHIThemeOrientationNormal); + } + + if (!canDrawDirectly) { + context->drawImage(imageBuffer->image(), DeviceColorSpace, scrollbar->frameRect().location()); + } + + return true; +} + +} + |