diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-05 14:34:32 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-05 14:34:32 -0800 |
commit | 635860845790a19bf50bbc51ba8fb66a96dde068 (patch) | |
tree | ef6ad9ff73a5b57f65249d4232a202fa77e6a140 /WebCore/platform | |
parent | 8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2 (diff) | |
download | external_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.zip external_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.tar.gz external_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.tar.bz2 |
auto import from //depot/cupcake/@136594
Diffstat (limited to 'WebCore/platform')
467 files changed, 31468 insertions, 4036 deletions
diff --git a/WebCore/platform/Arena.cpp b/WebCore/platform/Arena.cpp index 90f850f..2cc8eba 100644 --- a/WebCore/platform/Arena.cpp +++ b/WebCore/platform/Arena.cpp @@ -90,8 +90,7 @@ static int CeilingLog2(unsigned int i) { return log2; } -void InitArenaPool(ArenaPool *pool, const char *name, - unsigned int size, unsigned int align) +void InitArenaPool(ArenaPool* pool, const char*, unsigned size, unsigned align) { if (align == 0) align = ARENA_DEFAULT_ALIGN; @@ -196,16 +195,6 @@ void* ArenaAllocate(ArenaPool *pool, unsigned int nb) } } /* --- end ArenaAllocate() --- */ -void* ArenaGrow(ArenaPool *pool, void *p, unsigned int size, unsigned int incr) -{ - void *newp; - - ARENA_ALLOCATE(newp, pool, size + incr); - if (newp) - memcpy(newp, p, size); - return newp; -} - /* * Free tail arenas linked after head, which may not be the true list head. * Reset pool->current to point to head in case it pointed at a tail arena. @@ -256,19 +245,6 @@ static void FreeArenaList(ArenaPool *pool, Arena *head, bool reallyFree) pool->current = head; } -void ArenaRelease(ArenaPool *pool, char *mark) -{ - Arena *a; - - for (a = pool->first.next; a; a = a->next) { - if (UPTRDIFF(mark, a->base) < UPTRDIFF(a->avail, a->base)) { - a->avail = (uword)ARENA_ALIGN(pool, mark); - FreeArenaList(pool, a, false); - return; - } - } -} - void FreeArenaPool(ArenaPool *pool) { FreeArenaList(pool, &pool->first, false); @@ -279,4 +255,16 @@ void FinishArenaPool(ArenaPool *pool) FreeArenaList(pool, &pool->first, true); } +#ifdef ANDROID_INSTRUMENT +size_t ReportPoolSize(const ArenaPool* pool) +{ + size_t total = 0; + for (const Arena *a = &pool->first; a; a = a->next) + total += (a->limit - a->base); + for (const Arena *fa = arena_freelist; fa; fa = fa->next ) + total += (fa->limit - fa->base); + return total; +} +#endif + } diff --git a/WebCore/platform/Arena.h b/WebCore/platform/Arena.h index b6f6931..4c9ecf4 100644 --- a/WebCore/platform/Arena.h +++ b/WebCore/platform/Arena.h @@ -125,6 +125,10 @@ void* ArenaAllocate(ArenaPool *pool, unsigned int nb); fastFree(a); \ (a) = 0; +#ifdef ANDROID_INSTRUMENT +size_t ReportPoolSize(const ArenaPool* pool); +#endif + } #endif diff --git a/WebCore/platform/ContextMenu.cpp b/WebCore/platform/ContextMenu.cpp index a9c64df..f086b63 100644 --- a/WebCore/platform/ContextMenu.cpp +++ b/WebCore/platform/ContextMenu.cpp @@ -43,6 +43,7 @@ #include "Page.h" #include "ResourceRequest.h" #include "SelectionController.h" +#include "Settings.h" #include "TextIterator.h" #include <memory> @@ -171,6 +172,21 @@ static void createAndAppendWritingDirectionSubMenu(const HitTestResult& result, writingDirectionMenuItem.setSubMenu(&writingDirectionMenu); } + +static void createAndAppendTextDirectionSubMenu(const HitTestResult& result, ContextMenuItem& textDirectionMenuItem) +{ + ContextMenu textDirectionMenu(result); + + ContextMenuItem defaultItem(ActionType, ContextMenuItemTagTextDirectionDefault, contextMenuItemTagDefaultDirection()); + ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagTextDirectionLeftToRight, contextMenuItemTagLeftToRight()); + ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagTextDirectionRightToLeft, contextMenuItemTagRightToLeft()); + + textDirectionMenu.appendItem(defaultItem); + textDirectionMenu.appendItem(ltr); + textDirectionMenu.appendItem(rtl); + + textDirectionMenuItem.setSubMenu(&textDirectionMenu); +} #endif static bool selectionContainsPossibleWord(Frame* frame) @@ -408,6 +424,18 @@ void ContextMenu::populate() contextMenuItemTagWritingDirectionMenu()); createAndAppendWritingDirectionSubMenu(m_hitTestResult, WritingDirectionMenuItem); appendItem(WritingDirectionMenuItem); + if (Page* page = frame->page()) { + if (Settings* settings = page->settings()) { + bool includeTextDirectionSubmenu = settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAlwaysIncluded + || settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAutomaticallyIncluded && frame->editor()->hasBidiSelection(); + if (includeTextDirectionSubmenu) { + ContextMenuItem TextDirectionMenuItem(SubmenuType, ContextMenuItemTagTextDirectionMenu, + contextMenuItemTagTextDirectionMenu()); + createAndAppendTextDirectionSubMenu(m_hitTestResult, TextDirectionMenuItem); + appendItem(TextDirectionMenuItem); + } + } + } #endif } } @@ -465,6 +493,24 @@ void ContextMenu::checkOrEnableIfNeeded(ContextMenuItem& item) const shouldEnable = true; break; } + case ContextMenuItemTagTextDirectionDefault: { + Editor::Command command = frame->editor()->command("MakeTextWritingDirectionNatural"); + shouldCheck = command.state() == TrueTriState; + shouldEnable = command.isEnabled(); + break; + } + case ContextMenuItemTagTextDirectionLeftToRight: { + Editor::Command command = frame->editor()->command("MakeTextWritingDirectionLeftToRight"); + shouldCheck = command.state() == TrueTriState; + shouldEnable = command.isEnabled(); + break; + } + case ContextMenuItemTagTextDirectionRightToLeft: { + Editor::Command command = frame->editor()->command("MakeTextWritingDirectionRightToLeft"); + shouldCheck = command.state() == TrueTriState; + shouldEnable = command.isEnabled(); + break; + } case ContextMenuItemTagCopy: shouldEnable = frame->editor()->canDHTMLCopy() || frame->editor()->canCopy(); break; @@ -595,6 +641,7 @@ void ContextMenu::checkOrEnableIfNeeded(ContextMenuItem& item) const case ContextMenuItemTagStartSpeaking: case ContextMenuItemTagStopSpeaking: case ContextMenuItemTagWritingDirectionMenu: + case ContextMenuItemTagTextDirectionMenu: case ContextMenuItemTagPDFSinglePageScrolling: case ContextMenuItemTagPDFFacingPagesScrolling: case ContextMenuItemTagInspectElement: diff --git a/WebCore/platform/ContextMenu.h b/WebCore/platform/ContextMenu.h index e10c762..9418ff5 100644 --- a/WebCore/platform/ContextMenu.h +++ b/WebCore/platform/ContextMenu.h @@ -69,10 +69,11 @@ class MenuEventProxy; void setPlatformDescription(PlatformMenuDescription); PlatformMenuDescription releasePlatformDescription(); - +#if PLATFORM(WX) + static ContextMenuItem* itemWithId(int); +#endif private: HitTestResult m_hitTestResult; - #if PLATFORM(MAC) // Keep this in sync with the PlatformMenuDescription typedef RetainPtr<NSMutableArray> m_platformDescription; diff --git a/WebCore/platform/ContextMenuItem.h b/WebCore/platform/ContextMenuItem.h index 5fb2681..52c4d1b 100644 --- a/WebCore/platform/ContextMenuItem.h +++ b/WebCore/platform/ContextMenuItem.h @@ -120,6 +120,10 @@ namespace WebCore { ContextMenuItemTagPDFSinglePageScrolling, ContextMenuItemTagPDFFacingPagesScrolling, ContextMenuItemTagInspectElement, + ContextMenuItemTagTextDirectionMenu, // Text Direction sub-menu + ContextMenuItemTagTextDirectionDefault, + ContextMenuItemTagTextDirectionLeftToRight, + ContextMenuItemTagTextDirectionRightToLeft, ContextMenuItemBaseApplicationTag = 10000 }; @@ -170,7 +174,21 @@ namespace WebCore { #elif defined ANDROID typedef void* PlatformMenuItemDescription; #elif PLATFORM(WX) - typedef wxMenuItem* PlatformMenuItemDescription; + struct PlatformMenuItemDescription { + PlatformMenuItemDescription() + : type(ActionType), + action(ContextMenuItemTagNoAction), + checked(false), + enabled(true) + {} + + ContextMenuItemType type; + ContextMenuAction action; + String title; + wxMenu * subMenu; + bool checked; + bool enabled; + }; #else typedef void* PlatformMenuItemDescription; #endif diff --git a/WebCore/platform/CookieJar.h b/WebCore/platform/CookieJar.h index 22627f2..178ee79 100644 --- a/WebCore/platform/CookieJar.h +++ b/WebCore/platform/CookieJar.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2003, 2006, 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 @@ -26,22 +26,16 @@ #ifndef CookieJar_h #define CookieJar_h -#if USE(SOUP) -#include <libsoup/soup.h> -#endif - namespace WebCore { class KURL; class String; class Document; - String cookies(const Document* document, const KURL&); - void setCookies(Document* document, const KURL&, const KURL& policyBaseURL, const String&); - bool cookiesEnabled(const Document* document); -#if USE(SOUP) - SoupCookieJar* getCookieJar(void); -#endif + String cookies(const Document*, const KURL&); + void setCookies(Document*, const KURL&, const KURL& policyBaseURL, const String&); + bool cookiesEnabled(const Document*); + } #endif diff --git a/WebCore/platform/DeprecatedPtrListImpl.cpp b/WebCore/platform/DeprecatedPtrListImpl.cpp index b3badc2..6d6112e 100644 --- a/WebCore/platform/DeprecatedPtrListImpl.cpp +++ b/WebCore/platform/DeprecatedPtrListImpl.cpp @@ -143,7 +143,7 @@ bool DeprecatedPtrListImpl::insert(unsigned n, const void *item) return false; } - DeprecatedListNode *node = new DeprecatedListNode((void *)item); + DeprecatedListNode *node = new DeprecatedListNode(const_cast<void*>(item)); if (n == 0) { // inserting at head diff --git a/WebCore/platform/DeprecatedValueList.h b/WebCore/platform/DeprecatedValueList.h deleted file mode 100644 index 8c00b4b..0000000 --- a/WebCore/platform/DeprecatedValueList.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2004 Apple Computer, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef DeprecatedValueList_h -#define DeprecatedValueList_h - -#include "DeprecatedValueListImpl.h" - -namespace WebCore { - -template <class T> class DeprecatedValueList; -template <class T> class DeprecatedValueListConstIterator; - -template<class T> class DeprecatedValueListNode : private DeprecatedValueListImplNode { -public: - DeprecatedValueListNode(const T &val) : value(val) { } - T value; - friend class DeprecatedValueList<T>; -}; - -template<class T> class DeprecatedValueListIterator { -public: - DeprecatedValueListIterator() { } - - T& operator*() const { return ((DeprecatedValueListNode<T> *)impl.node())->value; } - - DeprecatedValueListIterator &operator++() { ++impl; return *this; } - DeprecatedValueListIterator &operator--() { --impl; return *this; } - DeprecatedValueListIterator operator++(int) { return impl++; } - - bool operator==(const DeprecatedValueListIterator &other) { return impl == other.impl; } - bool operator!=(const DeprecatedValueListIterator &other) { return impl != other.impl; } - -private: - DeprecatedValueListIterator(const DeprecatedValueListImplIterator &pImp) : impl(pImp) { } - - DeprecatedValueListImplIterator impl; - - friend class DeprecatedValueList<T>; - friend class DeprecatedValueListConstIterator<T>; -}; - -template<class T> class DeprecatedValueListConstIterator { -public: - DeprecatedValueListConstIterator() { } - DeprecatedValueListConstIterator(const DeprecatedValueListIterator<T> &it) : impl(it.impl) { } - - const T& operator*() const { return ((const DeprecatedValueListNode<T> *)impl.node())->value; } - - DeprecatedValueListConstIterator &operator++() { ++impl; return *this; } - DeprecatedValueListConstIterator &operator--() { --impl; return *this; } - DeprecatedValueListConstIterator operator++(int) { return impl++; } - - bool operator==(const DeprecatedValueListConstIterator &other) { return impl == other.impl; } - bool operator!=(const DeprecatedValueListConstIterator &other) { return impl != other.impl; } - -private: - DeprecatedValueListConstIterator(const DeprecatedValueListImplIterator &pImp) : impl(pImp) { } - - DeprecatedValueListImplIterator impl; - - friend class DeprecatedValueList<T>; -}; - -template<class T> bool operator==(const DeprecatedValueList<T> &a, const DeprecatedValueList<T> &b); - -template <class T> class DeprecatedValueList { -public: - typedef DeprecatedValueListIterator<T> Iterator; - typedef DeprecatedValueListIterator<T> iterator; - typedef DeprecatedValueListConstIterator<T> ConstIterator; - typedef DeprecatedValueListConstIterator<T> const_iterator; - - DeprecatedValueList() : impl(deleteNode, copyNode) { } - - void clear() { impl.clear(); } - unsigned count() const { return impl.count(); } - bool isEmpty() const { return impl.isEmpty(); } - - Iterator append(const T &val) { return impl.appendNode(new DeprecatedValueListNode<T>(val)); } - Iterator prepend(const T &val) { return impl.prependNode(new DeprecatedValueListNode<T>(val)); } - void remove(const T &val) { DeprecatedValueListNode<T> node(val); impl.removeEqualNodes(&node, nodesEqual); } - unsigned contains(const T &val) const { DeprecatedValueListNode<T> node(val); return impl.containsEqualNodes(&node, nodesEqual); } - Iterator find(const T &val) const { DeprecatedValueListNode<T> node(val); return impl.findEqualNode(&node, nodesEqual); } - - Iterator insert(Iterator iter, const T& val) { return impl.insert(iter.impl, new DeprecatedValueListNode<T>(val)); } - Iterator remove(Iterator iter) { return impl.removeIterator(iter.impl); } - Iterator fromLast() { return impl.fromLast(); } - - T& first() { return static_cast<DeprecatedValueListNode<T> *>(impl.firstNode())->value; } - const T& first() const { return static_cast<DeprecatedValueListNode<T> *>(impl.firstNode())->value; } - T& last() { return static_cast<DeprecatedValueListNode<T> *>(impl.lastNode())->value; } - const T& last() const { return static_cast<DeprecatedValueListNode<T> *>(impl.lastNode())->value; } - - Iterator begin() { return impl.begin(); } - Iterator end() { return impl.end(); } - - ConstIterator begin() const { return impl.begin(); } - ConstIterator end() const { return impl.end(); } - ConstIterator constBegin() const { return impl.begin(); } - ConstIterator constEnd() const { return impl.end(); } - ConstIterator fromLast() const { return impl.fromLast(); } - - T& operator[] (unsigned index) { return ((DeprecatedValueListNode<T> *)impl.nodeAt(index))->value; } - const T& operator[] (unsigned index) const { return ((const DeprecatedValueListNode<T> *)impl.nodeAt(index))->value; } - DeprecatedValueList &operator+=(const T &value) { impl.appendNode(new DeprecatedValueListNode<T>(value)); return *this; } - DeprecatedValueList &operator<<(const T &value) { impl.appendNode(new DeprecatedValueListNode<T>(value)); return *this; } - - friend bool operator==<>(const DeprecatedValueList<T> &, const DeprecatedValueList<T> &); - -private: - DeprecatedValueListImpl impl; - - static void deleteNode(DeprecatedValueListImplNode *node) { delete (DeprecatedValueListNode<T> *)node; } - static bool nodesEqual(const DeprecatedValueListImplNode *a, const DeprecatedValueListImplNode *b) - { return ((DeprecatedValueListNode<T> *)a)->value == ((DeprecatedValueListNode<T> *)b)->value; } - static DeprecatedValueListImplNode *copyNode(DeprecatedValueListImplNode *node) - { return new DeprecatedValueListNode<T>(((DeprecatedValueListNode<T> *)node)->value); } -}; - -template<class T> -inline bool operator==(const DeprecatedValueList<T> &a, const DeprecatedValueList<T> &b) -{ - return a.impl.isEqual(b.impl, DeprecatedValueList<T>::nodesEqual); -} - -} - -#endif diff --git a/WebCore/platform/DeprecatedValueListImpl.cpp b/WebCore/platform/DeprecatedValueListImpl.cpp deleted file mode 100644 index dc8c660..0000000 --- a/WebCore/platform/DeprecatedValueListImpl.cpp +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Copyright (C) 2003, 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "DeprecatedValueListImpl.h" - -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> -#include <stdlib.h> - -namespace WebCore { - -class DeprecatedValueListImpl::Private : public RefCounted<DeprecatedValueListImpl::Private> { -public: - Private(void (*deleteFunc)(DeprecatedValueListImplNode *), DeprecatedValueListImplNode *(*copyFunc)(DeprecatedValueListImplNode *)); - Private(const Private &other); - - ~Private(); - - void copyList(DeprecatedValueListImplNode *l, DeprecatedValueListImplNode *&head, DeprecatedValueListImplNode *&tail) const; - void deleteList(DeprecatedValueListImplNode *l); - - DeprecatedValueListImplNode *head; - DeprecatedValueListImplNode *tail; - - void (*deleteNode)(DeprecatedValueListImplNode *); - DeprecatedValueListImplNode *(*copyNode)(DeprecatedValueListImplNode *); - unsigned count; -}; - -inline DeprecatedValueListImpl::Private::Private(void (*deleteFunc)(DeprecatedValueListImplNode*), - DeprecatedValueListImplNode* (*copyFunc)(DeprecatedValueListImplNode*)) - : head(NULL) - , tail(NULL) - , deleteNode(deleteFunc) - , copyNode(copyFunc) - , count(0) -{ -} - -inline DeprecatedValueListImpl::Private::Private(const Private &other) - : RefCounted<Private>() - , deleteNode(other.deleteNode) - , copyNode(other.copyNode) - , count(other.count) -{ - other.copyList(other.head, head, tail); -} - -inline DeprecatedValueListImpl::Private::~Private() -{ - deleteList(head); -} - -void DeprecatedValueListImpl::Private::copyList(DeprecatedValueListImplNode *l, DeprecatedValueListImplNode *&head, DeprecatedValueListImplNode *&tail) const -{ - DeprecatedValueListImplNode *prev = NULL; - DeprecatedValueListImplNode *node = l; - - head = NULL; - - while (node != NULL) { - DeprecatedValueListImplNode *copy = copyNode(node); - if (prev == NULL) { - head = copy; - } else { - prev->next = copy; - } - - copy->prev = prev; - copy->next = NULL; - - prev = copy; - node = node->next; - } - - tail = prev; -} - -void DeprecatedValueListImpl::Private::deleteList(DeprecatedValueListImplNode *l) -{ - DeprecatedValueListImplNode *p = l; - - while (p != NULL) { - DeprecatedValueListImplNode *next = p->next; - deleteNode(p); - p = next; - } -} - -DeprecatedValueListImpl::DeprecatedValueListImpl(void (*deleteFunc)(DeprecatedValueListImplNode *), DeprecatedValueListImplNode *(*copyFunc)(DeprecatedValueListImplNode *)) : - d(adoptRef(new Private(deleteFunc, copyFunc))) -{ -} - -DeprecatedValueListImpl::DeprecatedValueListImpl(const DeprecatedValueListImpl &other) : - d(other.d) -{ -} - -DeprecatedValueListImpl::~DeprecatedValueListImpl() -{ -} - -void DeprecatedValueListImpl::clear() -{ - if (d->head) { - copyOnWrite(); - d->deleteList(d->head); - d->head = NULL; - d->tail = NULL; - d->count = 0; - } -} - -unsigned DeprecatedValueListImpl::count() const -{ - return d->count; -} - -bool DeprecatedValueListImpl::isEmpty() const -{ - return d->count == 0; -} - -DeprecatedValueListImplIterator DeprecatedValueListImpl::appendNode(DeprecatedValueListImplNode *node) -{ - copyOnWrite(); - - node->next = NULL; - node->prev = d->tail; - d->tail = node; - - if (d->head == NULL) { - d->head = node; - } else { - node->prev->next = node; - } - - d->count++; - - return node; -} - -DeprecatedValueListImplIterator DeprecatedValueListImpl::prependNode(DeprecatedValueListImplNode *node) -{ - copyOnWrite(); - - node->next = d->head; - node->prev = NULL; - d->head = node; - - if (d->tail == NULL) { - d->tail = node; - } else { - node->next->prev = node; - } - - d->count++; - - return node; -} - -void DeprecatedValueListImpl::removeEqualNodes(DeprecatedValueListImplNode *node, bool (*equalFunc)(const DeprecatedValueListImplNode *, const DeprecatedValueListImplNode *)) -{ - copyOnWrite(); - - DeprecatedValueListImplNode *next; - for (DeprecatedValueListImplNode *p = d->head; p != NULL; p = next) { - next = p->next; - if (equalFunc(node, p)) { - if (p->next != NULL) { - p->next->prev = p->prev; - } else { - d->tail = p->prev; - } - - if (p->prev != NULL) { - p->prev->next = p->next; - } else { - d->head = p->next; - } - - d->deleteNode(p); - - d->count--; - } - } -} - -unsigned DeprecatedValueListImpl::containsEqualNodes(DeprecatedValueListImplNode *node, bool (*equalFunc)(const DeprecatedValueListImplNode *, const DeprecatedValueListImplNode *)) const -{ - unsigned contains = 0; - - for (DeprecatedValueListImplNode *p = d->head; p != NULL; p = p->next) { - if (equalFunc(node, p)) { - ++contains; - } - } - - return contains; -} - -DeprecatedValueListImplIterator DeprecatedValueListImpl::findEqualNode(DeprecatedValueListImplNode *node, bool (*equalFunc)(const DeprecatedValueListImplNode *, const DeprecatedValueListImplNode *)) const -{ - DeprecatedValueListImplIterator it = begin(); - DeprecatedValueListImplIterator endIt = end(); - while (it != endIt) { - if (equalFunc(node, it.node())) { - break; - } - it++; - } - return it; -} - -DeprecatedValueListImplIterator DeprecatedValueListImpl::insert(const DeprecatedValueListImplIterator &iterator, DeprecatedValueListImplNode *node) -{ - copyOnWrite(); - - DeprecatedValueListImplNode *next = iterator.nodeImpl; - - if (next == NULL) - return appendNode(node); - - if (next == d->head) - return prependNode(node); - - DeprecatedValueListImplNode *prev = next->prev; - - node->next = next; - node->prev = prev; - next->prev = node; - prev->next = node; - - d->count++; - - return node; -} - -DeprecatedValueListImplIterator DeprecatedValueListImpl::removeIterator(DeprecatedValueListImplIterator &iterator) -{ - copyOnWrite(); - - if (iterator.nodeImpl == NULL) { - return iterator; - } - - DeprecatedValueListImplNode *next = iterator.nodeImpl->next; - - // detach node - if (iterator.nodeImpl->next != NULL) { - iterator.nodeImpl->next->prev = iterator.nodeImpl->prev; - } else { - d->tail = iterator.nodeImpl->prev; - } - if (iterator.nodeImpl->prev != NULL) { - iterator.nodeImpl->prev->next = iterator.nodeImpl->next; - } else { - d->head = iterator.nodeImpl->next; - } - - d->deleteNode(iterator.nodeImpl); - d->count--; - - return DeprecatedValueListImplIterator(next); -} - -DeprecatedValueListImplIterator DeprecatedValueListImpl::fromLast() -{ - copyOnWrite(); - return DeprecatedValueListImplIterator(lastNode()); -} - -DeprecatedValueListImplNode *DeprecatedValueListImpl::firstNode() -{ - copyOnWrite(); - return ((const DeprecatedValueListImpl *)this)->firstNode(); -} - -DeprecatedValueListImplNode *DeprecatedValueListImpl::lastNode() -{ - copyOnWrite(); - return ((const DeprecatedValueListImpl *)this)->lastNode(); -} - -DeprecatedValueListImplNode *DeprecatedValueListImpl::firstNode() const -{ - return d->head; -} - -DeprecatedValueListImplNode *DeprecatedValueListImpl::lastNode() const -{ - return d->tail; -} - -DeprecatedValueListImplIterator DeprecatedValueListImpl::begin() -{ - copyOnWrite(); - return ((const DeprecatedValueListImpl *)this)->begin(); -} - -DeprecatedValueListImplIterator DeprecatedValueListImpl::end() -{ - copyOnWrite(); - return ((const DeprecatedValueListImpl *)this)->end(); -} - - -DeprecatedValueListImplIterator DeprecatedValueListImpl::begin() const -{ - return DeprecatedValueListImplIterator(firstNode()); -} - -DeprecatedValueListImplIterator DeprecatedValueListImpl::end() const -{ - return DeprecatedValueListImplIterator(NULL); -} - -DeprecatedValueListImplIterator DeprecatedValueListImpl::fromLast() const -{ - return DeprecatedValueListImplIterator(lastNode()); -} - -DeprecatedValueListImplNode *DeprecatedValueListImpl::nodeAt(unsigned index) -{ - copyOnWrite(); - - if (d->count <= index) { - return NULL; - } - - DeprecatedValueListImplNode *p = d->head; - - for (unsigned i = 0; i < index; i++) { - p = p->next; - } - - return p; -} - -DeprecatedValueListImplNode *DeprecatedValueListImpl::nodeAt(unsigned index) const -{ - if (d->count <= index) { - return NULL; - } - - DeprecatedValueListImplNode *p = d->head; - - for (unsigned i = 0; i < index; i++) { - p = p->next; - } - - return p; -} - -DeprecatedValueListImpl& DeprecatedValueListImpl::operator=(const DeprecatedValueListImpl &other) -{ - DeprecatedValueListImpl tmp(other); - RefPtr<Private> tmpD = tmp.d; - - tmp.d = d; - d = tmpD; - - return *this; -} - -void DeprecatedValueListImpl::copyOnWrite() -{ - if (!d->hasOneRef()) - d = adoptRef(new Private(*d)); -} - -bool DeprecatedValueListImpl::isEqual(const DeprecatedValueListImpl &other, bool (*equalFunc)(const DeprecatedValueListImplNode *, const DeprecatedValueListImplNode *)) const -{ - DeprecatedValueListImplNode *p, *q; - for (p = d->head, q = other.d->head; p && q; p = p->next, q = q->next) { - if (!equalFunc(p, q)) { - return false; - } - } - return !p && !q; -} - -} diff --git a/WebCore/platform/DeprecatedValueListImpl.h b/WebCore/platform/DeprecatedValueListImpl.h deleted file mode 100644 index 108f008..0000000 --- a/WebCore/platform/DeprecatedValueListImpl.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (C) 2003 Apple Computer, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef DeprecatedValueListImpl_h -#define DeprecatedValueListImpl_h - -#include <wtf/RefPtr.h> - -namespace WebCore { - -class DeprecatedValueListImplNode; - -class DeprecatedValueListImplIterator -{ -public: - DeprecatedValueListImplIterator(); - - bool operator==(const DeprecatedValueListImplIterator &other); - bool operator!=(const DeprecatedValueListImplIterator &other); - - DeprecatedValueListImplNode *node(); - const DeprecatedValueListImplNode *node() const; - - DeprecatedValueListImplIterator& operator++(); - DeprecatedValueListImplIterator operator++(int); - DeprecatedValueListImplIterator& operator--(); - -private: - DeprecatedValueListImplIterator(const DeprecatedValueListImplNode *n); - - DeprecatedValueListImplNode *nodeImpl; - - friend class DeprecatedValueListImpl; -}; - -class DeprecatedValueListImpl -{ -public: - DeprecatedValueListImpl(void (*deleteFunc)(DeprecatedValueListImplNode *), DeprecatedValueListImplNode *(*copyNode)(DeprecatedValueListImplNode *)); - ~DeprecatedValueListImpl(); - - DeprecatedValueListImpl(const DeprecatedValueListImpl&); - DeprecatedValueListImpl& operator=(const DeprecatedValueListImpl&); - - void clear(); - unsigned count() const; - bool isEmpty() const; - - DeprecatedValueListImplIterator appendNode(DeprecatedValueListImplNode *node); - DeprecatedValueListImplIterator prependNode(DeprecatedValueListImplNode *node); - void removeEqualNodes(DeprecatedValueListImplNode *node, bool (*equalFunc)(const DeprecatedValueListImplNode *, const DeprecatedValueListImplNode *)); - unsigned containsEqualNodes(DeprecatedValueListImplNode *node, bool (*equalFunc)(const DeprecatedValueListImplNode *, const DeprecatedValueListImplNode *)) const; - - DeprecatedValueListImplIterator findEqualNode(DeprecatedValueListImplNode *node, bool (*equalFunc)(const DeprecatedValueListImplNode *, const DeprecatedValueListImplNode *)) const; - - DeprecatedValueListImplIterator insert(const DeprecatedValueListImplIterator &iterator, DeprecatedValueListImplNode* node); - DeprecatedValueListImplIterator removeIterator(DeprecatedValueListImplIterator &iterator); - DeprecatedValueListImplIterator fromLast(); - - DeprecatedValueListImplNode *firstNode(); - DeprecatedValueListImplNode *lastNode(); - - DeprecatedValueListImplNode *firstNode() const; - DeprecatedValueListImplNode *lastNode() const; - - DeprecatedValueListImplIterator begin(); - DeprecatedValueListImplIterator end(); - - DeprecatedValueListImplIterator begin() const; - DeprecatedValueListImplIterator end() const; - DeprecatedValueListImplIterator fromLast() const; - - DeprecatedValueListImplNode *nodeAt(unsigned index); - DeprecatedValueListImplNode *nodeAt(unsigned index) const; - - bool isEqual(const DeprecatedValueListImpl &other, bool (*equalFunc)(const DeprecatedValueListImplNode *, const DeprecatedValueListImplNode *)) const; - -private: - void copyOnWrite(); - - class Private; - - RefPtr<Private> d; - - friend class DeprecatedValueListImplNode; -}; - -class DeprecatedValueListImplNode -{ -protected: - DeprecatedValueListImplNode(); - -private: - DeprecatedValueListImplNode *prev; - DeprecatedValueListImplNode *next; - - friend class DeprecatedValueListImpl; - friend class DeprecatedValueListImplIterator; - friend class DeprecatedValueListImpl::Private; -}; - -inline DeprecatedValueListImplIterator::DeprecatedValueListImplIterator() : - nodeImpl(NULL) -{ -} - -inline bool DeprecatedValueListImplIterator::operator==(const DeprecatedValueListImplIterator &other) -{ - return nodeImpl == other.nodeImpl; -} - -inline bool DeprecatedValueListImplIterator::operator!=(const DeprecatedValueListImplIterator &other) -{ - return nodeImpl != other.nodeImpl; -} - -inline DeprecatedValueListImplNode *DeprecatedValueListImplIterator::node() -{ - return nodeImpl; -} - -inline const DeprecatedValueListImplNode *DeprecatedValueListImplIterator::node() const -{ - return nodeImpl; -} - -inline DeprecatedValueListImplIterator& DeprecatedValueListImplIterator::operator++() -{ - if (nodeImpl != NULL) { - nodeImpl = nodeImpl->next; - } - return *this; -} - -inline DeprecatedValueListImplIterator DeprecatedValueListImplIterator::operator++(int) -{ - DeprecatedValueListImplIterator tmp(*this); - - if (nodeImpl != NULL) { - nodeImpl = nodeImpl->next; - } - - return tmp; -} - -inline DeprecatedValueListImplIterator& DeprecatedValueListImplIterator::operator--() -{ - if (nodeImpl != NULL) { - nodeImpl = nodeImpl->prev; - } - return *this; -} - -inline DeprecatedValueListImplIterator::DeprecatedValueListImplIterator(const DeprecatedValueListImplNode *n) : - nodeImpl((DeprecatedValueListImplNode *)n) -{ -} - -inline DeprecatedValueListImplNode::DeprecatedValueListImplNode() : - prev(NULL), - next(NULL) -{ -} - -} - -#endif diff --git a/WebCore/platform/FileSystem.h b/WebCore/platform/FileSystem.h index a3d5d2d..66dbc20 100644 --- a/WebCore/platform/FileSystem.h +++ b/WebCore/platform/FileSystem.h @@ -97,10 +97,10 @@ const PlatformFileHandle invalidPlatformFileHandle = 0; #if defined(Q_WS_MAC) typedef CFBundleRef PlatformModule; typedef unsigned PlatformModuleVersion; -#elif defined(Q_WS_X11) || defined(Q_WS_QWS) +#elif defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_S60) typedef QLibrary* PlatformModule; typedef unsigned PlatformModuleVersion; -#elif defined(Q_OS_WIN32) +#elif defined(Q_OS_WIN) typedef HMODULE PlatformModule; struct PlatformModuleVersion { unsigned leastSig; diff --git a/WebCore/platform/HostWindow.h b/WebCore/platform/HostWindow.h index 761e3d7..7007ac5 100644 --- a/WebCore/platform/HostWindow.h +++ b/WebCore/platform/HostWindow.h @@ -52,9 +52,13 @@ public: // Methods for doing coordinate conversions to and from screen coordinates. 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; + + // 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; }; } // namespace WebCore diff --git a/WebCore/platform/KURL.cpp b/WebCore/platform/KURL.cpp index 1f33297..6fcb9b9 100644 --- a/WebCore/platform/KURL.cpp +++ b/WebCore/platform/KURL.cpp @@ -24,11 +24,15 @@ */ #include "config.h" + +#if !USE(GOOGLEURL) + #include "KURL.h" #include "CString.h" #include "PlatformString.h" #include "TextEncoding.h" +#include <wtf/StdLibExtras.h> #if USE(ICU_UNICODE) #include <unicode/uidna.h> @@ -239,6 +243,14 @@ static void copyASCII(const UChar* src, int length, char* dest) dest[i] = static_cast<char>(src[i]); } +static void appendASCII(const String& base, const char* rel, size_t len, CharBuffer& buffer) +{ + buffer.resize(base.length() + len + 1); + copyASCII(base.characters(), base.length(), buffer.data()); + memcpy(buffer.data() + base.length(), rel, len); + buffer[buffer.size() - 1] = '\0'; +} + // FIXME: Move to PlatformString.h eventually. // Returns the index of the first index in string |s| of any of the characters // in |toFind|. |toFind| should be a null-terminated string, all characters up @@ -255,6 +267,20 @@ static int findFirstOf(const UChar* s, int sLen, int startPos, const char* toFin return -1; } +#ifndef NDEBUG +static void checkEncodedString(const String& url) +{ + for (unsigned i = 0; i < url.length(); ++i) + ASSERT(!(url[i] & ~0x7F)); + + ASSERT(!url.length() || isSchemeFirstChar(url[0])); +} +#else +static inline void checkEncodedString(const String&) +{ +} +#endif + inline bool KURL::protocolIs(const String& string, const char* protocol) { return WebCore::protocolIs(string, protocol); @@ -277,39 +303,16 @@ void KURL::invalidate() KURL::KURL(const char* url) { - if (!url || url[0] != '/') { - parse(url, 0); - return; - } - - size_t urlLength = strlen(url) + 1; - CharBuffer buffer(urlLength + 5); // 5 for "file:". - buffer[0] = 'f'; - buffer[1] = 'i'; - buffer[2] = 'l'; - buffer[3] = 'e'; - buffer[4] = ':'; - memcpy(&buffer[5], url, urlLength); - parse(buffer.data(), 0); + parse(url, 0); + ASSERT(url == m_string); } KURL::KURL(const String& url) { - if (url[0] != '/') { - parse(url); - return; - } - - CharBuffer buffer(url.length() + 6); // 5 for "file:", 1 for terminator. - buffer[0] = 'f'; - buffer[1] = 'i'; - buffer[2] = 'l'; - buffer[3] = 'e'; - buffer[4] = ':'; - copyASCII(url.characters(), url.length(), &buffer[5]); - buffer[url.length() + 5] = '\0'; // Need null terminator. + checkEncodedString(url); - parse(buffer.data(), 0); + parse(url); + ASSERT(url == m_string); } KURL::KURL(const KURL& base, const String& relative) @@ -319,7 +322,11 @@ KURL::KURL(const KURL& base, const String& relative) KURL::KURL(const KURL& base, const String& relative, const TextEncoding& encoding) { - init(base, relative, encoding); + // For UTF-{7,16,32}, we want to use UTF-8 for the query part as + // we do when submitting a form. A form with GET method + // has its contents added to a URL as query params and it makes sense + // to be consistent. + init(base, relative, encoding.encodingForFormSubmission()); } void KURL::init(const KURL& base, const String& relative, const TextEncoding& encoding) @@ -391,15 +398,18 @@ void KURL::init(const KURL& base, const String& relative, const TextEncoding& en } } + CharBuffer parseBuffer; + if (absolute) { parse(str, originalString); } else { // If the base is empty or opaque (e.g. data: or javascript:), then the URL is invalid // unless the relative URL is a single fragment. if (!base.isHierarchical()) { - if (str[0] == '#') - parse(base.m_string.left(base.m_queryEnd) + (allASCII ? String(str) : String::fromUTF8(str))); - else { + if (str[0] == '#') { + appendASCII(base.m_string.left(base.m_queryEnd), str, len, parseBuffer); + parse(parseBuffer.data(), 0); + } else { m_string = relative; invalidate(); } @@ -412,22 +422,28 @@ void KURL::init(const KURL& base, const String& relative, const TextEncoding& en // reference to the same document *this = base; break; - case '#': + case '#': { // must be fragment-only reference - parse(base.m_string.left(base.m_queryEnd) + (allASCII ? String(str) : String::fromUTF8(str))); + appendASCII(base.m_string.left(base.m_queryEnd), str, len, parseBuffer); + parse(parseBuffer.data(), 0); break; - case '?': + } + case '?': { // query-only reference, special case needed for non-URL results - parse(base.m_string.left(base.m_pathEnd) + (allASCII ? String(str) : String::fromUTF8(str))); + appendASCII(base.m_string.left(base.m_pathEnd), str, len, parseBuffer); + parse(parseBuffer.data(), 0); break; + } case '/': // must be net-path or absolute-path reference if (str[1] == '/') { // net-path - parse(base.m_string.left(base.m_schemeEnd + 1) + (allASCII ? String(str) : String::fromUTF8(str))); + appendASCII(base.m_string.left(base.m_schemeEnd + 1), str, len, parseBuffer); + parse(parseBuffer.data(), 0); } else { // abs-path - parse(base.m_string.left(base.m_portEnd) + (allASCII ? String(str) : String::fromUTF8(str))); + appendASCII(base.m_string.left(base.m_portEnd), str, len, parseBuffer); + parse(parseBuffer.data(), 0); } break; default: @@ -435,16 +451,15 @@ void KURL::init(const KURL& base, const String& relative, const TextEncoding& en // must be relative-path reference // Base part plus relative part plus one possible slash added in between plus terminating \0 byte. - CharBuffer buffer(base.m_pathEnd + 1 + len + 1); + parseBuffer.resize(base.m_pathEnd + 1 + len + 1); - char* bufferPos = buffer.data(); + char* bufferPos = parseBuffer.data(); // first copy everything before the path from the base unsigned baseLength = base.m_string.length(); const UChar* baseCharacters = base.m_string.characters(); CharBuffer baseStringBuffer(baseLength); - for (unsigned i = 0; i < baseLength; ++i) - baseStringBuffer[i] = static_cast<char>(baseCharacters[i]); + copyASCII(baseCharacters, baseLength, baseStringBuffer.data()); const char* baseString = baseStringBuffer.data(); const char* baseStringStart = baseString; const char* pathStart = baseStringStart + base.m_portEnd; @@ -503,15 +518,22 @@ void KURL::init(const KURL& base, const String& relative, const TextEncoding& en // of the relative reference; this will also add a null terminator strcpy(bufferPos, relStringPos); - parse(buffer.data(), 0); + parse(parseBuffer.data(), 0); - ASSERT(strlen(buffer.data()) + 1 <= buffer.size()); + ASSERT(strlen(parseBuffer.data()) + 1 <= parseBuffer.size()); break; } } } } +KURL KURL::copy() const +{ + KURL result = *this; + result.m_string = result.m_string.copy(); + return result; +} + bool KURL::hasPath() const { return m_pathEnd != m_portEnd; @@ -582,17 +604,25 @@ bool KURL::hasRef() const return m_fragmentEnd != m_queryEnd; } -static inline void assertProtocolIsGood(const char* protocol) +#ifdef NDEBUG + +static inline void assertProtocolIsGood(const char*) +{ +} + +#else + +static void assertProtocolIsGood(const char* protocol) { -#ifndef NDEBUG const char* p = protocol; while (*p) { ASSERT(*p > ' ' && *p < 0x7F && !(*p >= 'A' && *p <= 'Z')); ++p; } -#endif } +#endif + bool KURL::protocolIs(const char* protocol) const { // Do the comparison without making a new string object. @@ -618,6 +648,9 @@ String KURL::path() const void KURL::setProtocol(const String& s) { + // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations, + // and to avoid changing more than just the protocol. + if (!m_isValid) { parse(s + ":" + m_string); return; @@ -631,6 +664,9 @@ void KURL::setHost(const String& s) if (!m_isValid) return; + // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations, + // and to avoid changing more than just the host. + bool slashSlashNeeded = m_userStart == m_schemeEnd + 1; parse(m_string.left(hostStart()) + (slashSlashNeeded ? "//" : "") + s + m_string.substring(m_hostEnd)); @@ -641,6 +677,9 @@ void KURL::setPort(unsigned short i) if (!m_isValid) return; + // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations, + // and to avoid changing more than just the port. + bool colonNeeded = m_portEnd == m_hostEnd; int portStart = (colonNeeded ? m_hostEnd : m_hostEnd + 1); @@ -652,6 +691,9 @@ void KURL::setHostAndPort(const String& hostAndPort) if (!m_isValid) return; + // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations, + // and to avoid changing more than just host and port. + bool slashSlashNeeded = m_userStart == m_schemeEnd + 1; parse(m_string.left(hostStart()) + (slashSlashNeeded ? "//" : "") + hostAndPort + m_string.substring(m_portEnd)); @@ -662,6 +704,8 @@ void KURL::setUser(const String& user) if (!m_isValid) return; + // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations, + // and to avoid changing more than just the user login. String u; int end = m_userEnd; if (!user.isEmpty()) { @@ -684,6 +728,8 @@ void KURL::setPass(const String& password) if (!m_isValid) return; + // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations, + // and to avoid changing more than just the user password. String p; int end = m_passwordEnd; if (!password.isEmpty()) { @@ -705,6 +751,8 @@ void KURL::setRef(const String& s) { if (!m_isValid) return; + + // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations. parse(m_string.left(m_queryEnd) + (s.isNull() ? "" : "#" + s)); } @@ -720,6 +768,9 @@ void KURL::setQuery(const String& query) if (!m_isValid) return; + // FIXME: '#' and non-ASCII characters must be encoded and escaped. + // Usually, the query is encoded using document encoding, not UTF-8, but we don't have + // access to the document in this function. if ((query.isEmpty() || query[0] != '?') && !query.isNull()) parse(m_string.left(m_pathEnd) + "?" + query + m_string.substring(m_queryEnd)); else @@ -732,6 +783,8 @@ void KURL::setPath(const String& s) if (!m_isValid) return; + // FIXME: encodeWithURLEscapeSequences does not correctly escape '#' and '?', so fragment and query parts + // may be inadvertently affected. parse(m_string.left(m_portEnd) + encodeWithURLEscapeSequences(s) + m_string.substring(m_pathEnd)); } @@ -943,8 +996,11 @@ static inline bool matchLetter(char c, char lowercaseLetter) void KURL::parse(const String& string) { - CharBuffer buffer; - encodeRelativeString(string, UTF8Encoding(), buffer); + checkEncodedString(string); + + CharBuffer buffer(string.length() + 1); + copyASCII(string.characters(), string.length(), buffer.data()); + buffer[string.length()] = '\0'; parse(buffer.data(), &string); } @@ -1480,7 +1536,7 @@ static void encodeRelativeString(const String& rel, const TextEncoding& encoding TextEncoding pathEncoding(UTF8Encoding()); // Path is always encoded as UTF-8; other parts may depend on the scheme. int pathEnd = -1; - if (encoding != pathEncoding && encoding.isValid() && !protocolIs(rel, "mailto") && !protocolIs(rel, "data")) { + if (encoding != pathEncoding && encoding.isValid() && !protocolIs(rel, "mailto") && !protocolIs(rel, "data") && !protocolIs(rel, "javascript")) { // Find the first instance of either # or ?, keep pathEnd at -1 otherwise. pathEnd = findFirstOf(s.data(), s.size(), 0, "#?"); } @@ -1563,7 +1619,7 @@ String mimeTypeFromDataURL(const String& url) const KURL& blankURL() { - static KURL staticBlankURL("about:blank"); + DEFINE_STATIC_LOCAL(KURL, staticBlankURL, ("about:blank")); return staticBlankURL; } @@ -1575,3 +1631,5 @@ void KURL::print() const #endif } + +#endif // !USE(GOOGLEURL) diff --git a/WebCore/platform/KURL.h b/WebCore/platform/KURL.h index f31c641..7f6b102 100644 --- a/WebCore/platform/KURL.h +++ b/WebCore/platform/KURL.h @@ -46,6 +46,10 @@ class QUrl; QT_END_NAMESPACE #endif +#if USE(GOOGLEURL) +#include "GoogleURLPrivate.h" +#endif + namespace WebCore { class TextEncoding; @@ -62,19 +66,8 @@ public: KURL() { invalidate(); } // The argument is an absolute URL string. The string is assumed to be - // already encoded. - // FIXME: This constructor has a special case for strings that start with - // "/", prepending "file://" to such strings; it would be good to get - // rid of that special case. + // an already encoded (ASCII-only) valid absolute URL. explicit KURL(const char*); - - // The argument is an absolute URL string. The string is assumed to be - // already encoded. - // FIXME: For characters with codes other than 0000-00FF will be chopped - // off, so this call is currently not safe to use with arbitrary strings. - // FIXME: This constructor has a special case for strings that start with - // "/", prepending "file://" to such strings; it would be good to get - // rid of that special case. explicit KURL(const String&); // Resolves the relative URL with the given base URL. If provided, the @@ -87,21 +80,37 @@ public: KURL(const KURL& base, const String& relative); KURL(const KURL& base, const String& relative, const TextEncoding&); +#if USE(GOOGLEURL) + // For conversions for other structures that have already parsed and + // canonicalized the URL. The input must be exactly what KURL would have + // done with the same input. + KURL(const char* canonicalSpec, int canonicalSpecLen, + const url_parse::Parsed& parsed, bool isValid); +#endif + // FIXME: The above functions should be harmonized so that passing a // base of null or the empty string gives the same result as the // standard String constructor. - bool isNull() const { return m_string.isNull(); } - bool isEmpty() const { return m_string.isEmpty(); } + // Makes a deep copy. Helpful only if you need to use a KURL on another + // thread. Since the underlying StringImpl objects are immutable, there's + // no other reason to ever prefer copy() over plain old assignment. + KURL copy() const; - bool isValid() const { return m_isValid; } + bool isNull() const; + bool isEmpty() const; + bool isValid() const; // Returns true if this URL has a path. Note that "http://foo.com/" has a // path of "/", so this function will return true. Only invalid or // non-hierarchical (like "javascript:") URLs will have no path. bool hasPath() const; +#if USE(GOOGLEURL) + const String& string() const { return m_url.string(); } +#else const String& string() const { return m_string; } +#endif String protocol() const; String host() const; @@ -145,20 +154,21 @@ public: void setRef(const String&); void removeRef(); - + friend bool equalIgnoringRef(const KURL&, const KURL&); friend bool protocolHostAndPortAreEqual(const KURL&, const KURL&); - - operator const String&() const { return m_string; } - operator JSC::UString() const { return m_string; } - unsigned hostStart() const { return (m_passwordEnd == m_userStart) ? m_passwordEnd : m_passwordEnd + 1; } - unsigned hostEnd() const { return m_hostEnd; } - - unsigned pathStart() const { return m_portEnd; } - unsigned pathEnd() const { return m_pathEnd; } - unsigned pathAfterLastSlash() const { return m_pathAfterLastSlash; } + unsigned hostStart() const; + unsigned hostEnd() const; + + unsigned pathStart() const; + unsigned pathEnd() const; + unsigned pathAfterLastSlash() const; + operator const String&() const { return string(); } +#if USE(JSC) + operator JSC::UString() const { return string(); } +#endif #if PLATFORM(CF) KURL(CFURLRef); @@ -170,7 +180,7 @@ public: operator NSURL*() const; #endif #ifdef __OBJC__ - operator NSString*() const { return m_string; } + operator NSString*() const { return string(); } #endif #if PLATFORM(QT) @@ -178,6 +188,12 @@ public: operator QUrl() const; #endif +#if USE(GOOGLEURL) + // Getters for the parsed structure and its corresponding 8-bit string. + const url_parse::Parsed& parsed() const { return m_url.m_parsed; } + const CString& utf8String() const { return m_url.utf8String(); } +#endif + #ifndef NDEBUG void print() const; #endif @@ -185,10 +201,16 @@ public: private: void invalidate(); bool isHierarchical() const; - void init(const KURL&, const String&, const TextEncoding&); static bool protocolIs(const String&, const char*); +#if USE(GOOGLEURL) + friend class GoogleURLPrivate; + void parse(const char* url, const String* originalString); // KURLMac calls this. + void copyToBuffer(Vector<char, 512>& buffer) const; // KURLCFNet uses this. + GoogleURLPrivate m_url; +#else // !USE(GOOGLEURL) + void init(const KURL&, const String&, const TextEncoding&); void copyToBuffer(Vector<char, 512>& buffer) const; - + // Parses the given URL. The originalString parameter allows for an // optimization: When the source is the same as the fixed-up string, // it will use the passed-in string instead of allocating a new one. @@ -207,6 +229,7 @@ private: int m_pathEnd; int m_queryEnd; int m_fragmentEnd; +#endif }; bool operator==(const KURL&, const KURL&); @@ -268,6 +291,53 @@ inline bool operator!=(const String& a, const KURL& b) return a != b.string(); } +#if !USE(GOOGLEURL) + +// Inline versions of some non-GoogleURL functions so we can get inlining +// without having to have a lot of ugly ifdefs in the class definition. + +inline bool KURL::isNull() const +{ + return m_string.isNull(); +} + +inline bool KURL::isEmpty() const +{ + return m_string.isEmpty(); +} + +inline bool KURL::isValid() const +{ + return m_isValid; +} + +inline unsigned KURL::hostStart() const +{ + return (m_passwordEnd == m_userStart) ? m_passwordEnd : m_passwordEnd + 1; +} + +inline unsigned KURL::hostEnd() const +{ + return m_hostEnd; +} + +inline unsigned KURL::pathStart() const +{ + return m_portEnd; +} + +inline unsigned KURL::pathEnd() const +{ + return m_pathEnd; +} + +inline unsigned KURL::pathAfterLastSlash() const +{ + return m_pathAfterLastSlash; +} + +#endif // !USE(GOOGLEURL) + } // namespace WebCore namespace WTF { diff --git a/WebCore/platform/LinkHash.cpp b/WebCore/platform/LinkHash.cpp new file mode 100644 index 0000000..793a65d --- /dev/null +++ b/WebCore/platform/LinkHash.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * (C) 2006 Alexey Proskuryakov (ap@webkit.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "AtomicString.h" +#include "KURL.h" +#include "LinkHash.h" +#include "PlatformString.h" +#include "StringHash.h" +#include "StringImpl.h" + +namespace WebCore { + +static inline int findSlashDotDotSlash(const UChar* characters, size_t length) +{ + if (length < 4) + return -1; + unsigned loopLimit = length - 3; + for (unsigned i = 0; i < loopLimit; ++i) { + if (characters[i] == '/' && characters[i + 1] == '.' && characters[i + 2] == '.' && characters[i + 3] == '/') + return i; + } + return -1; +} + +static inline int findSlashSlash(const UChar* characters, size_t length, int position) +{ + if (length < 2) + return -1; + unsigned loopLimit = length - 1; + for (unsigned i = position; i < loopLimit; ++i) { + if (characters[i] == '/' && characters[i + 1] == '/') + return i; + } + return -1; +} + +static inline int findSlashDotSlash(const UChar* characters, size_t length) +{ + if (length < 3) + return -1; + unsigned loopLimit = length - 2; + for (unsigned i = 0; i < loopLimit; ++i) { + if (characters[i] == '/' && characters[i + 1] == '.' && characters[i + 2] == '/') + return i; + } + return -1; +} + +static inline bool containsColonSlashSlash(const UChar* characters, unsigned length) +{ + if (length < 3) + return false; + unsigned loopLimit = length - 2; + for (unsigned i = 0; i < loopLimit; ++i) { + if (characters[i] == ':' && characters[i + 1] == '/' && characters[i + 2] == '/') + return true; + } + return false; +} + +static inline void cleanPath(Vector<UChar, 512>& path) +{ + // FIXME: Shold not do this in the query or anchor part. + int pos; + while ((pos = findSlashDotDotSlash(path.data(), path.size())) != -1) { + int prev = reverseFind(path.data(), path.size(), '/', pos - 1); + // don't remove the host, i.e. http://foo.org/../foo.html + if (prev < 0 || (prev > 3 && path[prev - 2] == ':' && path[prev - 1] == '/')) + path.remove(pos, 3); + else + path.remove(prev, pos - prev + 3); + } + + // FIXME: Shold not do this in the query part. + // Set refPos to -2 to mean "I haven't looked for the anchor yet". + // We don't want to waste a function call on the search for the the anchor + // in the vast majority of cases where there is no "//" in the path. + pos = 0; + int refPos = -2; + while ((pos = findSlashSlash(path.data(), path.size(), pos)) != -1) { + if (refPos == -2) + refPos = find(path.data(), path.size(), '#'); + if (refPos > 0 && pos >= refPos) + break; + + if (pos == 0 || path[pos - 1] != ':') + path.remove(pos); + else + pos += 2; + } + + // FIXME: Shold not do this in the query or anchor part. + while ((pos = findSlashDotSlash(path.data(), path.size())) != -1) + path.remove(pos, 2); +} + + +static inline bool matchLetter(UChar c, UChar lowercaseLetter) +{ + return (c | 0x20) == lowercaseLetter; +} + +static inline bool needsTrailingSlash(const UChar* characters, unsigned length) +{ + if (length < 6) + return false; + if (!matchLetter(characters[0], 'h') + || !matchLetter(characters[1], 't') + || !matchLetter(characters[2], 't') + || !matchLetter(characters[3], 'p')) + return false; + if (!(characters[4] == ':' + || (matchLetter(characters[4], 's') && characters[5] == ':'))) + return false; + + unsigned pos = characters[4] == ':' ? 5 : 6; + + // Skip initial two slashes if present. + if (pos + 1 < length && characters[pos] == '/' && characters[pos + 1] == '/') + pos += 2; + + // Find next slash. + while (pos < length && characters[pos] != '/') + ++pos; + + return pos == length; +} + +LinkHash visitedLinkHash(const UChar* url, unsigned length) +{ + return AlreadyHashed::avoidDeletedValue(StringImpl::computeHash(url, length)); +} + +LinkHash visitedLinkHash(const KURL& base, const AtomicString& attributeURL) +{ + const UChar* characters = attributeURL.characters(); + unsigned length = attributeURL.length(); + if (!length) + return 0; + + // This is a poor man's completeURL. Faster with less memory allocation. + // FIXME: It's missing a lot of what completeURL does and a lot of what KURL does. + // For example, it does not handle international domain names properly. + + // FIXME: It is wrong that we do not do further processing on strings that have "://" in them: + // 1) The "://" could be in the query or anchor. + // 2) The URL's path could have a "/./" or a "/../" or a "//" sequence in it. + + // FIXME: needsTrailingSlash does not properly return true for a URL that has no path, but does + // have a query or anchor. + + bool hasColonSlashSlash = containsColonSlashSlash(characters, length); + + if (hasColonSlashSlash && !needsTrailingSlash(characters, length)) + return visitedLinkHash(attributeURL.characters(), attributeURL.length()); + + Vector<UChar, 512> buffer; + + if (hasColonSlashSlash) { + // FIXME: This is incorrect for URLs that have a query or anchor; the "/" needs to go at the + // end of the path, *before* the query or anchor. + buffer.append(characters, length); + buffer.append('/'); + return visitedLinkHash(buffer.data(), buffer.size()); + } + + switch (characters[0]) { + case '/': + buffer.append(base.string().characters(), base.pathStart()); + break; + case '#': + buffer.append(base.string().characters(), base.pathEnd()); + break; + default: + buffer.append(base.string().characters(), base.pathAfterLastSlash()); + break; + } + buffer.append(characters, length); + cleanPath(buffer); + if (needsTrailingSlash(buffer.data(), buffer.size())) { + // FIXME: This is incorrect for URLs that have a query or anchor; the "/" needs to go at the + // end of the path, *before* the query or anchor. + buffer.append('/'); + } + + return visitedLinkHash(buffer.data(), buffer.size()); +} + +} // namespace WebCore diff --git a/WebCore/platform/LinkHash.h b/WebCore/platform/LinkHash.h new file mode 100644 index 0000000..1ec1e16 --- /dev/null +++ b/WebCore/platform/LinkHash.h @@ -0,0 +1,67 @@ +/* + * 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: + * 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 LinkHash_h +#define LinkHash_h + +#include "StringHash.h" + +namespace WebCore { + +class AtomicString; +class KURL; + +typedef uint64_t LinkHash; + +// Use the low 32-bits of the 64-bit LinkHash as the key for HashSets. +struct LinkHashHash { + static unsigned hash(LinkHash key) { return static_cast<unsigned>(key); } + static bool equal(LinkHash a, LinkHash b) { return a == b; } + static const bool safeToCompareToEmptyOrDeleted = true; + + // See AlreadyHashed::avoidDeletedValue. + static unsigned avoidDeletedValue(LinkHash hash64) + { + ASSERT(hash64); + unsigned hash = static_cast<unsigned>(hash64); + unsigned newHash = hash | (!(hash + 1) << 31); + ASSERT(newHash); + ASSERT(newHash != 0xFFFFFFFF); + return newHash; + } +}; + +// Returns the has of the string that will be used for visited link coloring. +LinkHash visitedLinkHash(const UChar* url, unsigned length); + +// Resolves the potentially relative URL "attributeURL" relative to the given +// base URL, and returns the hash of the string that will be used for visited +// link coloring. It will return the special value of 0 if attributeURL does not +// look like a relative URL. +LinkHash visitedLinkHash(const KURL& base, const AtomicString& attributeURL); + +} // namespace WebCore + +#endif // LinkHash_h diff --git a/WebCore/platform/LocalizedStrings.h b/WebCore/platform/LocalizedStrings.h index 9b11a92..085c6e1 100644 --- a/WebCore/platform/LocalizedStrings.h +++ b/WebCore/platform/LocalizedStrings.h @@ -76,6 +76,7 @@ namespace WebCore { String contextMenuItemTagUnderline(); String contextMenuItemTagOutline(); String contextMenuItemTagWritingDirectionMenu(); + String contextMenuItemTagTextDirectionMenu(); String contextMenuItemTagDefaultDirection(); String contextMenuItemTagLeftToRight(); String contextMenuItemTagRightToLeft(); diff --git a/WebCore/platform/MIMETypeRegistry.cpp b/WebCore/platform/MIMETypeRegistry.cpp index 70d953a..14becb5 100644 --- a/WebCore/platform/MIMETypeRegistry.cpp +++ b/WebCore/platform/MIMETypeRegistry.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,6 +36,7 @@ #include <wtf/HashSet.h> #if PLATFORM(CG) +#include "ImageSourceCG.h" #include <ApplicationServices/ApplicationServices.h> #include <wtf/RetainPtr.h> #endif @@ -52,10 +54,6 @@ static HashSet<String>* supportedJavaScriptMIMETypes; static HashSet<String>* supportedNonImageMIMETypes; static HashSet<String>* supportedMediaMIMETypes; -#if PLATFORM(CG) -extern String getMIMETypeForUTI(const String& uti); -#endif - static void initializeSupportedImageMIMETypes() { #if PLATFORM(CG) @@ -63,7 +61,7 @@ static void initializeSupportedImageMIMETypes() CFIndex count = CFArrayGetCount(supportedTypes.get()); for (CFIndex i = 0; i < count; i++) { RetainPtr<CFStringRef> supportedType(AdoptCF, reinterpret_cast<CFStringRef>(CFArrayGetValueAtIndex(supportedTypes.get(), i))); - String mimeType = getMIMETypeForUTI(supportedType.get()); + String mimeType = MIMETypeForImageSourceType(supportedType.get()); if (!mimeType.isEmpty()) { supportedImageMIMETypes->add(mimeType); supportedImageResourceMIMETypes->add(mimeType); @@ -154,7 +152,7 @@ static void initializeSupportedImageMIMETypesForEncoding() CFIndex count = CFArrayGetCount(supportedTypes.get()); for (CFIndex i = 0; i < count; i++) { RetainPtr<CFStringRef> supportedType(AdoptCF, reinterpret_cast<CFStringRef>(CFArrayGetValueAtIndex(supportedTypes.get(), i))); - String mimeType = getMIMETypeForUTI(supportedType.get()); + String mimeType = MIMETypeForImageSourceType(supportedType.get()); if (!mimeType.isEmpty()) supportedImageMIMETypesForEncoding->add(mimeType); } @@ -205,6 +203,10 @@ static void initializeSupportedJavaScriptMIMETypes() static void initializeSupportedNonImageMimeTypes() { static const char* types[] = { +#if ENABLE(WML) + "text/vnd.wap.wml", + "application/vnd.wap.wmlc", +#endif "text/html", "text/xml", "text/xsl", diff --git a/WebCore/platform/NotImplemented.h b/WebCore/platform/NotImplemented.h index 862f111..03ab424 100644 --- a/WebCore/platform/NotImplemented.h +++ b/WebCore/platform/NotImplemented.h @@ -58,7 +58,7 @@ #define notImplemented() do { \ static bool havePrinted = false; \ if (!havePrinted && !supressNotImplementedWarning()) { \ - WTFLogVerbose(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, &LogNotYetImplemented, "UNIMPLEMENTED: "); \ + WTFLogVerbose(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, &::WebCore::LogNotYetImplemented, "UNIMPLEMENTED: "); \ havePrinted = true; \ } \ } while (0) diff --git a/WebCore/platform/PurgeableBuffer.h b/WebCore/platform/PurgeableBuffer.h new file mode 100644 index 0000000..bee21b9 --- /dev/null +++ b/WebCore/platform/PurgeableBuffer.h @@ -0,0 +1,76 @@ +/* + * 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 PurgeableBuffer_h +#define PurgeableBuffer_h + +#include <wtf/Noncopyable.h> +#include <wtf/Vector.h> + +namespace WebCore { + + class PurgeableBuffer : Noncopyable { + public: + static PurgeableBuffer* create(const char* data, size_t); + static PurgeableBuffer* create(const Vector<char>& v) { return create(v.data(), v.size()); } + + ~PurgeableBuffer(); + + // Call makePurgeable(false) and check the return value before accessing the data. + const char* data() const; + size_t size() const { return m_size; } + + enum PurgePriority { PurgeLast, PurgeMiddle, PurgeFirst, PurgeDefault = PurgeMiddle }; + PurgePriority purgePriority() const { return m_purgePriority; } + void setPurgePriority(PurgePriority); + + bool isPurgeable() const { return m_state != NonVolatile; } + bool wasPurged() const; + + bool makePurgeable(bool purgeable); + + private: + PurgeableBuffer(char* data, size_t); + + char* m_data; + size_t m_size; + PurgePriority m_purgePriority; + + enum State { NonVolatile, Volatile, Purged }; + mutable State m_state; + }; + +#if !PLATFORM(DARWIN) || defined(BUILDING_ON_TIGER) || PLATFORM(QT) + inline PurgeableBuffer* PurgeableBuffer::create(const char*, size_t) { return 0; } + inline PurgeableBuffer::~PurgeableBuffer() { } + inline const char* PurgeableBuffer::data() const { return 0; } + inline void PurgeableBuffer::setPurgePriority(PurgePriority) { } + inline bool PurgeableBuffer::wasPurged() const { return false; } + inline bool PurgeableBuffer::makePurgeable(bool) { return false; } +#endif + +} + +#endif diff --git a/WebCore/platform/ScrollView.cpp b/WebCore/platform/ScrollView.cpp index 9eb6ce7..573dabe 100644 --- a/WebCore/platform/ScrollView.cpp +++ b/WebCore/platform/ScrollView.cpp @@ -33,6 +33,7 @@ #include "PlatformWheelEvent.h" #include "Scrollbar.h" #include "ScrollbarTheme.h" +#include <wtf/StdLibExtras.h> using std::max; @@ -47,10 +48,9 @@ ScrollView::ScrollView() , m_scrollbarsSuppressed(false) , m_inUpdateScrollbars(false) , m_drawPanScrollIcon(false) + , m_useFixedLayout(false) { platformInit(); - if (platformWidget()) - platformSetCanBlitOnScroll(); } ScrollView::~ScrollView() @@ -79,7 +79,7 @@ void ScrollView::removeChild(Widget* child) void ScrollView::setHasHorizontalScrollbar(bool hasBar) { if (hasBar && !m_horizontalScrollbar && !platformHasHorizontalAdjustment()) { - m_horizontalScrollbar = Scrollbar::createNativeScrollbar(this, HorizontalScrollbar, RegularScrollbar); + m_horizontalScrollbar = createScrollbar(HorizontalScrollbar); addChild(m_horizontalScrollbar.get()); } else if (!hasBar && m_horizontalScrollbar) { removeChild(m_horizontalScrollbar.get()); @@ -90,7 +90,7 @@ void ScrollView::setHasHorizontalScrollbar(bool hasBar) void ScrollView::setHasVerticalScrollbar(bool hasBar) { if (hasBar && !m_verticalScrollbar && !platformHasVerticalAdjustment()) { - m_verticalScrollbar = Scrollbar::createNativeScrollbar(this, VerticalScrollbar, RegularScrollbar); + m_verticalScrollbar = createScrollbar(VerticalScrollbar); addChild(m_verticalScrollbar.get()); } else if (!hasBar && m_verticalScrollbar) { removeChild(m_verticalScrollbar.get()); @@ -98,6 +98,11 @@ void ScrollView::setHasVerticalScrollbar(bool hasBar) } } +PassRefPtr<Scrollbar> ScrollView::createScrollbar(ScrollbarOrientation orientation) +{ + return Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar); +} + void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode) { if (horizontalMode == horizontalScrollbarMode() && verticalMode == verticalScrollbarMode()) @@ -142,11 +147,20 @@ void ScrollView::setCanHaveScrollbars(bool canScroll) void ScrollView::setCanBlitOnScroll(bool b) { - if (m_canBlitOnScroll == b) + if (platformWidget()) { + platformSetCanBlitOnScroll(b); return; + } + m_canBlitOnScroll = b; +} + +bool ScrollView::canBlitOnScroll() const +{ if (platformWidget()) - platformSetCanBlitOnScroll(); + return platformCanBlitOnScroll(); + + return m_canBlitOnScroll; } IntRect ScrollView::visibleContentRect(bool includeScrollbars) const @@ -158,6 +172,42 @@ IntRect ScrollView::visibleContentRect(bool includeScrollbars) const max(0, height() - (horizontalScrollbar() && !includeScrollbars ? horizontalScrollbar()->height() : 0)))); } +int ScrollView::layoutWidth() const +{ + return m_fixedLayoutSize.isEmpty() || !m_useFixedLayout ? visibleWidth() : m_fixedLayoutSize.width(); +} + +int ScrollView::layoutHeight() const +{ + return m_fixedLayoutSize.isEmpty() || !m_useFixedLayout ? visibleHeight() : m_fixedLayoutSize.height(); +} + +IntSize ScrollView::fixedLayoutSize() const +{ + return m_fixedLayoutSize; +} + +void ScrollView::setFixedLayoutSize(const IntSize& newSize) +{ + if (fixedLayoutSize() == newSize) + return; + m_fixedLayoutSize = newSize; + updateScrollbars(scrollOffset()); +} + +bool ScrollView::useFixedLayout() const +{ + return m_useFixedLayout; +} + +void ScrollView::setUseFixedLayout(bool enable) +{ + if (useFixedLayout() == enable) + return; + m_useFixedLayout = enable; + updateScrollbars(scrollOffset()); +} + IntSize ScrollView::contentsSize() const { if (platformWidget()) @@ -211,16 +261,27 @@ void ScrollView::scrollRectIntoViewRecursively(const IntRect& r) if (platformProhibitsScrolling()) return; #endif - if (prohibitsScrolling()) - return; - - IntPoint p(max(0, r.x()), max(0, r.y())); + // FIXME: This method is not transform-aware. It should just be moved to FrameView so that an accurate + // position for the child view can be determined. + IntRect rect = r; ScrollView* view = this; while (view) { - view->setScrollPosition(p); - p.move(view->x() - view->scrollOffset().width(), view->y() - view->scrollOffset().height()); + if (view->prohibitsScrolling()) // Allow the views to scroll into view recursively until we hit one that prohibits scrolling. + return; + view->setScrollPosition(rect.location()); + rect.move(view->x() - view->scrollOffset().width(), view->y() - view->scrollOffset().height()); + if (view->parent()) + rect.intersect(view->frameRect()); view = view->parent(); } + + // We may be embedded inside some containing platform scroll view that we don't manage. This is the case + // in Mail.app on OS X, for example, where the WebKit view for message bodies is inside a Cocoa NSScrollView + // that contains both it and message headers. Let the HostWindow know about this scroll so that it can pass the message + // on up the view chain. + // This rect is not clamped, since Mail actually relies on receiving an unclamped rect with negative coordinates in order to + // expose the headers. + hostWindow()->scrollRectIntoView(rect, this); } void ScrollView::setScrollPosition(const IntPoint& scrollPoint) @@ -395,7 +456,7 @@ void ScrollView::scrollContents(const IntSize& scrollDelta) IntPoint panIconDirtySquareLocation = IntPoint(m_panScrollIconPoint.x() - (panIconDirtySquareSizeLength / 2), m_panScrollIconPoint.y() - (panIconDirtySquareSizeLength / 2)); IntRect panScrollIconDirtyRect = IntRect(panIconDirtySquareLocation , IntSize(panIconDirtySquareSizeLength, panIconDirtySquareSizeLength)); panScrollIconDirtyRect.intersect(clipRect); - hostWindow()->repaint(panScrollIconDirtyRect, true, true); + hostWindow()->repaint(panScrollIconDirtyRect, true); } if (canBlitOnScroll() && !rootPreventsBlitting()) { // The main frame can just blit the WebView window @@ -588,7 +649,7 @@ void ScrollView::setFrameRect(const IntRect& newRect) frameRectsChanged(); } -void ScrollView::frameRectsChanged() const +void ScrollView::frameRectsChanged() { if (platformWidget()) return; @@ -673,10 +734,8 @@ void ScrollView::paint(GraphicsContext* context, const IntRect& rect) } // Paint the panScroll Icon - static RefPtr<Image> panScrollIcon; if (m_drawPanScrollIcon) { - if (!panScrollIcon) - panScrollIcon = Image::loadPlatformResource("panIcon"); + DEFINE_STATIC_LOCAL(RefPtr<Image>, panScrollIcon, (Image::loadPlatformResource("panIcon"))); context->drawImage(panScrollIcon.get(), m_panScrollIconPoint); } } @@ -694,7 +753,7 @@ void ScrollView::setParentVisible(bool visible) Widget::setParentVisible(visible); - if (!isVisible()) + if (!isSelfVisible()) return; HashSet<Widget*>::iterator end = m_children.end(); @@ -778,10 +837,6 @@ void ScrollView::platformRemoveChild(Widget*) #endif #if !PLATFORM(MAC) -void ScrollView::platformSetCanBlitOnScroll() -{ -} - void ScrollView::platformSetScrollbarsSuppressed(bool repaintOnUnsuppress) { } @@ -796,12 +851,25 @@ void ScrollView::platformSetScrollbarModes() void ScrollView::platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode& vertical) const { } +#endif + +void ScrollView::platformSetCanBlitOnScroll(bool) +{ +} + +bool ScrollView::platformCanBlitOnScroll() const +{ + return false; +} +#if !PLATFORM(ANDROID) IntRect ScrollView::platformVisibleContentRect(bool) const { return IntRect(); } +#endif +#if !PLATFORM(ANDROID) IntSize ScrollView::platformContentsSize() const { return IntSize(); diff --git a/WebCore/platform/ScrollView.h b/WebCore/platform/ScrollView.h index acd3f85..f7bfbe8 100644 --- a/WebCore/platform/ScrollView.h +++ b/WebCore/platform/ScrollView.h @@ -95,6 +95,9 @@ public: virtual void setCanHaveScrollbars(bool flag); bool canHaveScrollbars() const { return horizontalScrollbarMode() != ScrollbarAlwaysOff || verticalScrollbarMode() != ScrollbarAlwaysOff; } + // Overridden by FrameView to create custom CSS scrollbars if applicable. + virtual PassRefPtr<Scrollbar> createScrollbar(ScrollbarOrientation); + // If the prohibits scrolling flag is set, then all scrolling in the view (even programmatic scrolling) is turned off. void setProhibitsScrolling(bool b) { m_prohibitsScrolling = b; } bool prohibitsScrolling() const { return m_prohibitsScrolling; } @@ -102,7 +105,7 @@ public: // Whether or not a scroll view will blit visible contents when it is scrolled. Blitting is disabled in situations // where it would cause rendering glitches (such as with fixed backgrounds or when the view is partially transparent). void setCanBlitOnScroll(bool); - bool canBlitOnScroll() const { return m_canBlitOnScroll; } + bool canBlitOnScroll() const; // The visible content rect has a location that is the scrolled offset of the document. The width and height are the viewport width // and height. By default the scrollbars themselves are excluded from this rectangle, but an optional boolean argument allows them to be @@ -110,13 +113,22 @@ public: IntRect visibleContentRect(bool includeScrollbars = false) const; int visibleWidth() const { return visibleContentRect().width(); } int visibleHeight() const { return visibleContentRect().height(); } + + // Methods for getting/setting the size webkit should use to layout the contents. By default this is the same as the visible + // content size. Explicitly setting a layout size value will cause webkit to layout the contents using this size instead. + int layoutWidth() const; + int layoutHeight() const; + IntSize fixedLayoutSize() const; + void setFixedLayoutSize(const IntSize&); + bool useFixedLayout() const; + void setUseFixedLayout(bool enable); // Methods for getting/setting the size of the document contained inside the ScrollView (as an IntSize or as individual width and height // values). IntSize contentsSize() const; int contentsWidth() const { return contentsSize().width(); } int contentsHeight() const { return contentsSize().height(); } - void setContentsSize(const IntSize&); + virtual void setContentsSize(const IntSize&); // Methods for querying the current scrolled position (both as a point, a size, or as individual X and Y values). IntPoint scrollPosition() const { return visibleContentRect().location(); } @@ -165,7 +177,7 @@ public: virtual void setParent(ScrollView*); // Overridden to update the overlapping scrollbar count. // Called when our frame rect changes (or the rect/scroll position of an ancestor changes). - virtual void frameRectsChanged() const; + virtual void frameRectsChanged(); // Widget override to update our scrollbars and notify our contents of the resize. virtual void setFrameRect(const IntRect&); @@ -229,8 +241,13 @@ private: bool m_prohibitsScrolling; HashSet<Widget*> m_children; + + // This bool is unused on Mac OS because we directly ask the platform widget + // whether it is safe to blit on scroll. bool m_canBlitOnScroll; + IntSize m_scrollOffset; // FIXME: Would rather store this as a position, but we will wait to make this change until more code is shared. + IntSize m_fixedLayoutSize; IntSize m_contentsSize; int m_scrollbarsAvoidingResizer; @@ -240,6 +257,7 @@ private: IntPoint m_panScrollIconPoint; bool m_drawPanScrollIcon; + bool m_useFixedLayout; void init(); void destroy(); @@ -253,7 +271,8 @@ private: void platformRemoveChild(Widget*); void platformSetScrollbarModes(); void platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode& vertical) const; - void platformSetCanBlitOnScroll(); + void platformSetCanBlitOnScroll(bool); + bool platformCanBlitOnScroll() const; IntRect platformVisibleContentRect(bool includeScrollbars) const; IntSize platformContentsSize() const; void platformSetContentsSize(); diff --git a/WebCore/platform/Scrollbar.cpp b/WebCore/platform/Scrollbar.cpp index 0c7d854..13bb0c9 100644 --- a/WebCore/platform/Scrollbar.cpp +++ b/WebCore/platform/Scrollbar.cpp @@ -364,14 +364,14 @@ bool Scrollbar::mouseDown(const PlatformMouseEvent& evt) setPressedPart(theme()->hitTest(this, evt)); int pressedPos = (orientation() == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y()); - if (theme()->shouldCenterOnThumb(this, evt)) { + if ((pressedPart() == BackTrackPart || pressedPart() == ForwardTrackPart) && theme()->shouldCenterOnThumb(this, evt)) { setHoveredPart(ThumbPart); setPressedPart(ThumbPart); int thumbLen = theme()->thumbLength(this); - int desiredPos = pressedPos - thumbLen / 2; - // Set the pressed position to the top of the thumb so that when we do the move, the delta + int desiredPos = pressedPos; + // Set the pressed position to the middle of the thumb so that when we do the move, the delta // will be from the current pixel position of the thumb to the new desired position for the thumb. - m_pressedPos = theme()->trackPosition(this) + theme()->thumbPosition(this); + m_pressedPos = theme()->trackPosition(this) + theme()->thumbPosition(this) + thumbLen / 2; moveThumb(desiredPos); return true; } @@ -433,14 +433,15 @@ void Scrollbar::setEnabled(bool e) bool Scrollbar::isWindowActive() const { - return m_client->isActive(); + return m_client && m_client->isActive(); } void Scrollbar::invalidateRect(const IntRect& rect) { if (suppressInvalidation()) return; - m_client->invalidateScrollbarRect(this, rect); + if (m_client) + m_client->invalidateScrollbarRect(this, rect); } PlatformMouseEvent Scrollbar::transformEvent(const PlatformMouseEvent& event) diff --git a/WebCore/platform/ScrollbarClient.h b/WebCore/platform/ScrollbarClient.h index ea35758..f720e95 100644 --- a/WebCore/platform/ScrollbarClient.h +++ b/WebCore/platform/ScrollbarClient.h @@ -27,6 +27,7 @@ #define ScrollbarClient_h #include "IntRect.h" +#include <wtf/Vector.h> namespace WebCore { @@ -42,6 +43,8 @@ public: virtual bool isActive() const = 0; virtual bool scrollbarCornerPresent() const = 0; + + virtual void getTickmarks(Vector<IntRect>&) const { } }; } diff --git a/WebCore/platform/ScrollbarTheme.h b/WebCore/platform/ScrollbarTheme.h index 1fdb2b2..e2aebc6 100644 --- a/WebCore/platform/ScrollbarTheme.h +++ b/WebCore/platform/ScrollbarTheme.h @@ -40,7 +40,7 @@ class ScrollbarTheme { public: virtual ~ScrollbarTheme() {}; - virtual bool paint(Scrollbar*, GraphicsContext*, const IntRect& damageRect) { return false; } + virtual bool paint(Scrollbar*, GraphicsContext*, const IntRect& /*damageRect*/) { return false; } virtual ScrollbarPart hitTest(Scrollbar*, const PlatformMouseEvent&) { return NoPart; } virtual int scrollbarThickness(ScrollbarControlSize = RegularScrollbar) { return 0; } diff --git a/WebCore/platform/ScrollbarThemeComposite.cpp b/WebCore/platform/ScrollbarThemeComposite.cpp index 4ea74fe..ab5e16b 100644 --- a/WebCore/platform/ScrollbarThemeComposite.cpp +++ b/WebCore/platform/ScrollbarThemeComposite.cpp @@ -145,6 +145,8 @@ bool ScrollbarThemeComposite::paint(Scrollbar* scrollbar, GraphicsContext* graph paintTrackPiece(graphicsContext, scrollbar, startTrackRect, BackTrackPart); if (scrollMask & ForwardTrackPart) paintTrackPiece(graphicsContext, scrollbar, endTrackRect, ForwardTrackPart); + + paintTickmarks(graphicsContext, scrollbar, trackPaintRect); } // Paint the thumb. diff --git a/WebCore/platform/ScrollbarThemeComposite.h b/WebCore/platform/ScrollbarThemeComposite.h index 7748251..d8c3fbb 100644 --- a/WebCore/platform/ScrollbarThemeComposite.h +++ b/WebCore/platform/ScrollbarThemeComposite.h @@ -62,7 +62,8 @@ protected: virtual void paintTrackPiece(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart) {} virtual void paintButton(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart) {} virtual void paintThumb(GraphicsContext*, Scrollbar*, const IntRect&) {} - + virtual void paintTickmarks(GraphicsContext*, Scrollbar*, const IntRect&) {} + virtual IntRect constrainTrackRectToTrackPieces(Scrollbar*, const IntRect& rect) { return rect; } }; diff --git a/WebCore/platform/SharedBuffer.cpp b/WebCore/platform/SharedBuffer.cpp index e1e812b..4a0d0f3 100644 --- a/WebCore/platform/SharedBuffer.cpp +++ b/WebCore/platform/SharedBuffer.cpp @@ -26,6 +26,8 @@ #include "config.h" #include "SharedBuffer.h" +#include "PurgeableBuffer.h" + namespace WebCore { SharedBuffer::SharedBuffer() @@ -41,6 +43,10 @@ SharedBuffer::SharedBuffer(const unsigned char* data, int size) { m_buffer.append(data, size); } + +SharedBuffer::~SharedBuffer() +{ +} PassRefPtr<SharedBuffer> SharedBuffer::adoptVector(Vector<char>& vector) { @@ -49,11 +55,22 @@ PassRefPtr<SharedBuffer> SharedBuffer::adoptVector(Vector<char>& vector) return buffer.release(); } +PassRefPtr<SharedBuffer> SharedBuffer::adoptPurgeableBuffer(PurgeableBuffer* purgeableBuffer) +{ + ASSERT(!purgeableBuffer->isPurgeable()); + RefPtr<SharedBuffer> buffer = create(); + buffer->m_purgeableBuffer.set(purgeableBuffer); + return buffer.release(); +} + unsigned SharedBuffer::size() const { if (hasPlatformData()) return platformDataSize(); + if (m_purgeableBuffer) + return m_purgeableBuffer->size(); + return m_buffer.size(); } @@ -62,11 +79,16 @@ const char* SharedBuffer::data() const if (hasPlatformData()) return platformData(); + if (m_purgeableBuffer) + return m_purgeableBuffer->data(); + return m_buffer.data(); } void SharedBuffer::append(const char* data, int len) { + ASSERT(!m_purgeableBuffer); + maybeTransferPlatformData(); m_buffer.append(data, len); @@ -77,6 +99,7 @@ void SharedBuffer::clear() clearPlatformData(); m_buffer.clear(); + m_purgeableBuffer.clear(); } PassRefPtr<SharedBuffer> SharedBuffer::copy() const @@ -84,6 +107,11 @@ PassRefPtr<SharedBuffer> SharedBuffer::copy() const return SharedBuffer::create(data(), size()); } +PurgeableBuffer* SharedBuffer::releasePurgeableBuffer() +{ + ASSERT(hasOneRef()); + return m_purgeableBuffer.release(); +} #if !PLATFORM(CF) diff --git a/WebCore/platform/SharedBuffer.h b/WebCore/platform/SharedBuffer.h index eb5c167..3675a3b 100644 --- a/WebCore/platform/SharedBuffer.h +++ b/WebCore/platform/SharedBuffer.h @@ -26,8 +26,9 @@ #define SharedBuffer_h #include "PlatformString.h" -#include <wtf/RefCounted.h> #include <wtf/Forward.h> +#include <wtf/OwnPtr.h> +#include <wtf/RefCounted.h> #include <wtf/Vector.h> #if PLATFORM(CF) @@ -44,6 +45,8 @@ class NSData; #endif namespace WebCore { + +class PurgeableBuffer; class SharedBuffer : public RefCounted<SharedBuffer> { public: @@ -55,6 +58,12 @@ public: static PassRefPtr<SharedBuffer> adoptVector(Vector<char>& vector); + // The buffer must be in non-purgeable state before adopted to a SharedBuffer. + // It will stay that way until released. + static PassRefPtr<SharedBuffer> adoptPurgeableBuffer(PurgeableBuffer* buffer); + + ~SharedBuffer(); + #if PLATFORM(MAC) NSData *createNSData(); static PassRefPtr<SharedBuffer> wrapNSData(NSData *data); @@ -76,6 +85,11 @@ public: PassRefPtr<SharedBuffer> copy() const; + bool hasPurgeableBuffer() const { return m_purgeableBuffer.get(); } + + // Ensure this buffer has no other clients before calling this. + PurgeableBuffer* releasePurgeableBuffer(); + private: SharedBuffer(); SharedBuffer(const char*, int); @@ -86,6 +100,7 @@ private: bool hasPlatformData() const; Vector<char> m_buffer; + OwnPtr<PurgeableBuffer> m_purgeableBuffer; #if PLATFORM(CF) SharedBuffer(CFDataRef); RetainPtr<CFDataRef> m_cfData; diff --git a/WebCore/platform/SystemTime.h b/WebCore/platform/SystemTime.h index 327b2c7..2620b94 100644 --- a/WebCore/platform/SystemTime.h +++ b/WebCore/platform/SystemTime.h @@ -28,16 +28,9 @@ namespace WebCore { - // Return the current system time in seconds, using the classic POSIX epoch of January 1, 1970. - // Like time(0) from <time.h>, except with a wider range of values and higher precision. - double currentTime(); - // Return the number of seconds since a user event has been generated float userIdleTime(); -#if PLATFORM(ANDROID) - uint32_t get_thread_msec(); -#endif } #endif diff --git a/WebCore/platform/Theme.cpp b/WebCore/platform/Theme.cpp index 185c7ca..5cf4af9 100644 --- a/WebCore/platform/Theme.cpp +++ b/WebCore/platform/Theme.cpp @@ -28,7 +28,7 @@ namespace WebCore { -LengthBox Theme::controlBorder(ControlPart part, const Font&, const LengthBox& zoomedBox, float zoomFactor) const +LengthBox Theme::controlBorder(ControlPart part, const Font&, const LengthBox& zoomedBox, float) const { switch (part) { case PushButtonPart: @@ -42,7 +42,7 @@ LengthBox Theme::controlBorder(ControlPart part, const Font&, const LengthBox& z } } -LengthBox Theme::controlPadding(ControlPart part, const Font&, const LengthBox& zoomedBox, float zoomFactor) const +LengthBox Theme::controlPadding(ControlPart part, const Font&, const LengthBox& zoomedBox, float) const { switch (part) { case MenulistPart: diff --git a/WebCore/platform/Theme.h b/WebCore/platform/Theme.h index 85c3f24..5574bd7 100644 --- a/WebCore/platform/Theme.h +++ b/WebCore/platform/Theme.h @@ -73,7 +73,7 @@ public: virtual Font systemFont(ThemeFont, FontDescription&) const { return Font(); } // How fast the caret blinks in text fields. - virtual double caretBlinkFrequency() const { return 0.5; } + virtual double caretBlinkInterval() const { return 0.5; } // Notification when the theme has changed virtual void themeChanged() { } @@ -81,13 +81,13 @@ public: // Methods used to adjust the RenderStyles of controls. // The font description result should have a zoomed font size. - virtual FontDescription controlFont(ControlPart, const Font& font, float zoomFactor) const { return font.fontDescription(); } + virtual FontDescription controlFont(ControlPart, const Font& font, float /*zoomFactor*/) const { return font.fontDescription(); } // The size here is in zoomed coordinates already. If a new size is returned, it also needs to be in zoomed coordinates. - virtual LengthSize controlSize(ControlPart, const Font&, const LengthSize& zoomedSize, float zoomFactor) const { return zoomedSize; } + virtual LengthSize controlSize(ControlPart, const Font&, const LengthSize& zoomedSize, float /*zoomFactor*/) const { return zoomedSize; } // Returns the minimum size for a control in zoomed coordinates. - virtual LengthSize minimumControlSize(ControlPart, const Font&, float zoomFactor) const { return LengthSize(Length(0, Fixed), Length(0, Fixed)); } + virtual LengthSize minimumControlSize(ControlPart, const Font&, float /*zoomFactor*/) const { return LengthSize(Length(0, Fixed), Length(0, Fixed)); } // Allows the theme to modify the existing padding/border. virtual LengthBox controlPadding(ControlPart, const Font&, const LengthBox& zoomedBox, float zoomFactor) const; @@ -96,14 +96,14 @@ public: // Whether or not whitespace: pre should be forced on always. virtual bool controlRequiresPreWhiteSpace(ControlPart) const { return false; } - // Method for painting a control. The rect is in zoomed coordinates. - virtual void paint(ControlPart, ControlStates, GraphicsContext*, const IntRect& zoomedRect, float zoomFactor, ScrollView*) const { }; + // Method for painting a control. The rect is in zoomed coordinates. + virtual void paint(ControlPart, ControlStates, GraphicsContext*, const IntRect& /*zoomedRect*/, float /*zoomFactor*/, ScrollView*) const { } // Some controls may spill out of their containers (e.g., the check on an OS X checkbox). When these controls repaint, // the theme needs to communicate this inflated rect to the engine so that it can invalidate the whole control. // The rect passed in is in zoomed coordinates, so the inflation should take that into account and make sure the inflation // amount is also scaled by the zoomFactor. - virtual void inflateControlPaintRect(ControlPart, ControlStates, IntRect& zoomedRect, float zoomFactor) const { } + virtual void inflateControlPaintRect(ControlPart, ControlStates, IntRect& /*zoomedRect*/, float /*zoomFactor*/) const { } // This method is called once, from RenderTheme::adjustDefaultStyleSheet(), to let each platform adjust // the default CSS rules in html4.css. diff --git a/WebCore/platform/ThemeTypes.h b/WebCore/platform/ThemeTypes.h index 8d73ea3..ae85a63 100644 --- a/WebCore/platform/ThemeTypes.h +++ b/WebCore/platform/ThemeTypes.h @@ -46,8 +46,9 @@ typedef unsigned ControlStates; enum ControlPart { NoControlPart, CheckboxPart, RadioPart, PushButtonPart, SquareButtonPart, ButtonPart, ButtonBevelPart, DefaultButtonPart, ListboxPart, ListItemPart, - MediaFullscreenButtonPart, MediaMuteButtonPart, MediaPlayButtonPart, - MediaSeekBackButtonPart, MediaSeekForwardButtonPart, MediaSliderPart, MediaSliderThumbPart, + MediaFullscreenButtonPart, MediaMuteButtonPart, MediaPlayButtonPart, MediaSeekBackButtonPart, + MediaSeekForwardButtonPart, MediaSliderPart, MediaSliderThumbPart, MediaTimelineContainerPart, + MediaCurrentTimePart, MediaTimeRemainingPart, MenulistPart, MenulistButtonPart, MenulistTextPart, MenulistTextFieldPart, SliderHorizontalPart, SliderVerticalPart, SliderThumbHorizontalPart, SliderThumbVerticalPart, CaretPart, SearchFieldPart, SearchFieldDecorationPart, diff --git a/WebCore/platform/ThreadGlobalData.cpp b/WebCore/platform/ThreadGlobalData.cpp new file mode 100644 index 0000000..9bf0bf2 --- /dev/null +++ b/WebCore/platform/ThreadGlobalData.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "config.h" +#include "ThreadGlobalData.h" + +#include "EventNames.h" +#include "StringImpl.h" +#include <wtf/UnusedParam.h> + +#if USE(ICU_UNICODE) +#include "TextCodecICU.h" +#endif + +#if PLATFORM(MAC) +#include "TextCodecMac.h" +#endif + +#if ENABLE(WORKERS) +#include <wtf/Threading.h> +#include <wtf/ThreadSpecific.h> +using namespace WTF; +#endif + +namespace WebCore { + +ThreadGlobalData& threadGlobalData() +{ + // FIXME: Workers are not necessarily the only feature that make per-thread global data necessary. + // We need to check for e.g. database objects manipulating strings on secondary threads. +#if ENABLE(WORKERS) + // ThreadGlobalData is used on main thread before it could possibly be used on secondary ones, so there is no need for synchronization here. + static ThreadSpecific<ThreadGlobalData>* threadGlobalData = new ThreadSpecific<ThreadGlobalData>; + return **threadGlobalData; +#else + static ThreadGlobalData* staticData; + if (!staticData) { + staticData = static_cast<ThreadGlobalData*>(fastMalloc(sizeof(ThreadGlobalData))); + // ThreadGlobalData constructor indirectly uses staticData, so we need to set up the memory before invoking it. + new (staticData) ThreadGlobalData; + } + return *staticData; +#endif +} + +ThreadGlobalData::ThreadGlobalData() + : m_emptyString(new StringImpl) + , m_atomicStringTable(new HashSet<StringImpl*>) + , m_eventNames(new EventNames) +#if USE(ICU_UNICODE) + , m_cachedConverterICU(new ICUConverterWrapper) +#endif +#if PLATFORM(MAC) + , m_cachedConverterTEC(new TECConverterWrapper) +#endif +{ +} + +ThreadGlobalData::~ThreadGlobalData() +{ +#if PLATFORM(MAC) + delete m_cachedConverterTEC; +#endif +#if USE(ICU_UNICODE) + delete m_cachedConverterICU; +#endif + + delete m_eventNames; + delete m_atomicStringTable; + + ASSERT(isMainThread() || m_emptyString->hasOneRef()); // We intentionally don't clean up static data on application quit, so there will be many strings remaining on the main thread. + delete m_emptyString; +} + +} // namespace WebCore diff --git a/WebCore/platform/ThreadGlobalData.h b/WebCore/platform/ThreadGlobalData.h new file mode 100644 index 0000000..17637aa --- /dev/null +++ b/WebCore/platform/ThreadGlobalData.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef ThreadGlobalData_h +#define ThreadGlobalData_h + +#include "StringHash.h" +#include <wtf/HashSet.h> +#include <wtf/Noncopyable.h> + +namespace WebCore { + + class EventNames; + struct ICUConverterWrapper; + struct TECConverterWrapper; + + class ThreadGlobalData : Noncopyable { + public: + ThreadGlobalData(); + ~ThreadGlobalData(); + + EventNames& eventNames() { return *m_eventNames; } + StringImpl* emptyString() { return m_emptyString; } + HashSet<StringImpl*>& atomicStringTable() { return *m_atomicStringTable; } + +#if USE(ICU_UNICODE) + ICUConverterWrapper& cachedConverterICU() { return *m_cachedConverterICU; } +#endif + +#if PLATFORM(MAC) + TECConverterWrapper& cachedConverterTEC() { return *m_cachedConverterTEC; } +#endif + + private: + StringImpl* m_emptyString; + HashSet<StringImpl*>* m_atomicStringTable; + EventNames* m_eventNames; + +#if USE(ICU_UNICODE) + ICUConverterWrapper* m_cachedConverterICU; +#endif + +#if PLATFORM(MAC) + TECConverterWrapper* m_cachedConverterTEC; +#endif + }; + + ThreadGlobalData& threadGlobalData(); + +} // namespace WebCore + +#endif // ThreadGlobalData_h diff --git a/WebCore/platform/Timer.cpp b/WebCore/platform/Timer.cpp index 94e2af8..a8fcbb8 100644 --- a/WebCore/platform/Timer.cpp +++ b/WebCore/platform/Timer.cpp @@ -27,10 +27,10 @@ #include "Timer.h" #include "SharedTimer.h" -#include "SystemTime.h" #include <limits.h> #include <limits> #include <math.h> +#include <wtf/CurrentTime.h> #include <wtf/HashSet.h> #include <wtf/Vector.h> @@ -46,7 +46,9 @@ namespace WebCore { // ---------------- -static bool deferringTimers; +#ifdef ANDROID_FIX // it is removed in http://trac.webkit.org/changeset/40080, but Android needs it +static bool deferringTimers; +#endif static Vector<TimerBase*>* timerHeap; static HashSet<const TimerBase*>* timersReadyToFire; @@ -64,7 +66,8 @@ public: TimerBase* timer() const { return m_timer; } - void checkConsistency() const { + void checkConsistency() const + { ASSERT(m_index >= 0); ASSERT(m_index < (timerHeap ? static_cast<int>(timerHeap->size()) : 0)); } @@ -131,9 +134,10 @@ public: int index() const { return m_index; } - void checkConsistency(int offset = 0) const { - ASSERT(m_index + offset >= 0); - ASSERT(m_index + offset <= (timerHeap ? static_cast<int>(timerHeap->size()) : 0)); + void checkConsistency(int offset = 0) const + { + ASSERT_UNUSED(offset, m_index + offset >= 0); + ASSERT_UNUSED(offset, m_index + offset <= (timerHeap ? static_cast<int>(timerHeap->size()) : 0)); } private: @@ -154,7 +158,11 @@ inline int operator-(TimerHeapIterator a, TimerHeapIterator b) { return a.index( void updateSharedTimer() { - if (timersReadyToFire || deferringTimers || !timerHeap || timerHeap->isEmpty()) +#ifdef ANDROID_FIX // it is removed in http://trac.webkit.org/changeset/40080, but Android needs it + if (timersReadyToFire || deferringTimers || !timerHeap || timerHeap->isEmpty()) +#else + if (timersReadyToFire || !timerHeap || timerHeap->isEmpty()) +#endif stopSharedTimer(); else setSharedTimerFireTime(timerHeap->first()->m_nextFireTime); @@ -378,19 +386,21 @@ void TimerBase::fireTimersInNestedEventLoop() updateSharedTimer(); } -// ---------------- +#ifdef ANDROID_FIX // it is removed in http://trac.webkit.org/changeset/40080, but Android needs it +// ---------------- -bool isDeferringTimers() -{ - return deferringTimers; -} +bool isDeferringTimers() +{ + return deferringTimers; +} -void setDeferringTimers(bool shouldDefer) -{ - if (shouldDefer == deferringTimers) - return; - deferringTimers = shouldDefer; - updateSharedTimer(); +void setDeferringTimers(bool shouldDefer) +{ + if (shouldDefer == deferringTimers) + return; + deferringTimers = shouldDefer; + updateSharedTimer(); } +#endif } diff --git a/WebCore/platform/Timer.h b/WebCore/platform/Timer.h index ba98ec5..a2589f7 100644 --- a/WebCore/platform/Timer.h +++ b/WebCore/platform/Timer.h @@ -83,7 +83,9 @@ private: unsigned m_heapInsertionOrder; // Used to keep order among equal-fire-time timers friend void updateSharedTimer(); +#ifdef ANDROID_FIX // it is removed in http://trac.webkit.org/changeset/40080, but Android needs it friend void setDeferringTimers(bool); +#endif friend class TimerHeapElement; friend bool operator<(const TimerHeapElement&, const TimerHeapElement&); }; @@ -102,10 +104,12 @@ private: TimerFiredFunction m_function; }; +#ifdef ANDROID_FIX // it is removed in http://trac.webkit.org/changeset/40080, but Android needs it // Set to true to prevent any timers from firing. // When set back to false, timers that were deferred will fire. bool isDeferringTimers(); void setDeferringTimers(bool); +#endif } diff --git a/WebCore/platform/Widget.h b/WebCore/platform/Widget.h index 1b82ab4..6684eb2 100644 --- a/WebCore/platform/Widget.h +++ b/WebCore/platform/Widget.h @@ -173,7 +173,7 @@ public: IntPoint convertFromContainingWindow(const IntPoint&) const; // See comment above about when not to use this method. IntRect convertFromContainingWindow(const IntRect&) const; - virtual void frameRectsChanged() const {} + virtual void frameRectsChanged() {} #if PLATFORM(MAC) NSView* getOuterView() const; diff --git a/WebCore/platform/android/FileChooserAndroid.cpp b/WebCore/platform/android/FileChooserAndroid.cpp index 2c75373..a8c4150 100644 --- a/WebCore/platform/android/FileChooserAndroid.cpp +++ b/WebCore/platform/android/FileChooserAndroid.cpp @@ -31,7 +31,10 @@ namespace WebCore { String FileChooser::basenameForWidth(const Font& font, int width) const -{ +{ + if (m_filenames.size() == 0) { + return String(); + } // FIXME: This could be a lot faster, but assuming the data will not // often be much longer than the provided width, this may be fast enough. String output = m_filenames[0].copy(); diff --git a/WebCore/platform/android/FileSystemAndroid.cpp b/WebCore/platform/android/FileSystemAndroid.cpp index b6d58bc..fcb0413 100644 --- a/WebCore/platform/android/FileSystemAndroid.cpp +++ b/WebCore/platform/android/FileSystemAndroid.cpp @@ -29,7 +29,9 @@ #include "FileSystem.h" #include "CString.h" +#include <fnmatch.h> #include <dlfcn.h> +#include <dirent.h> #include <errno.h> #include <sys/stat.h> #include "cutils/log.h" @@ -98,4 +100,33 @@ String homeDirectoryPath() return sPluginPath; } +// new as of webkit4, Feb 28, 2009 +Vector<String> listDirectory(const String& path, const String& filter) +{ + Vector<String> entries; + CString cpath = path.utf8(); + CString cfilter = filter.utf8(); + DIR* dir = opendir(cpath.data()); + if (dir) { + struct dirent * dp; + while ((dp = readdir(dir)) != NULL) { + const char* name = dp->d_name; + if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { + continue; + } + if (fnmatch(cfilter.data(), name, 0) != 0) { + continue; + } + char filePath[1024]; + if ((int) (sizeof(filePath) - 1) < snprintf(filePath, + sizeof(filePath), "%s/%s", cpath.data(), name)) { + continue; // buffer overflow + } + entries.append(filePath); + } + closedir(dir); + } + return entries; +} + } diff --git a/WebCore/platform/android/SharedTimerAndroid.cpp b/WebCore/platform/android/SharedTimerAndroid.cpp index d797cfb..3ff9705 100644 --- a/WebCore/platform/android/SharedTimerAndroid.cpp +++ b/WebCore/platform/android/SharedTimerAndroid.cpp @@ -27,10 +27,10 @@ #include "config.h" #include "SharedTimer.h" -#include "SystemTime.h" #include "JavaSharedClient.h" #include "TimerClient.h" #include <utils/Log.h> +#include <wtf/CurrentTime.h> using namespace android; @@ -48,7 +48,7 @@ void setSharedTimerFiredFunction(void (*f)()) // as the result of currentTime() is. void setSharedTimerFireTime(double fireTime) { - long long timeInMS = (long long)((fireTime - currentTime()) * 1000); + long long timeInMS = (long long)((fireTime - WTF::currentTime()) * 1000); LOGV("setSharedTimerFireTime: in %ld millisec", timeInMS); if (JavaSharedClient::GetTimerClient()) diff --git a/WebCore/platform/android/SoundAndroid.cpp b/WebCore/platform/android/SoundAndroid.cpp new file mode 100644 index 0000000..50cbfa5 --- /dev/null +++ b/WebCore/platform/android/SoundAndroid.cpp @@ -0,0 +1,36 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Sound.h" + +namespace WebCore { + +void systemBeep() +{ + // do nothing +} + +} // namespace WebCore diff --git a/WebCore/platform/android/SystemTimeAndroid.cpp b/WebCore/platform/android/SystemTimeAndroid.cpp index 9ac32dc..a9c862a 100644 --- a/WebCore/platform/android/SystemTimeAndroid.cpp +++ b/WebCore/platform/android/SystemTimeAndroid.cpp @@ -26,34 +26,12 @@ #include "config.h" #include "SystemTime.h" -#include <sys/time.h> - namespace WebCore { -double currentTime() -{ - struct timeval tv; - - gettimeofday(&tv, (struct timezone *) NULL); - double now = tv.tv_sec + (tv.tv_usec / 1000000.0); - - return now; -} - -uint32_t get_thread_msec() +float userIdleTime() { -#if defined(HAVE_POSIX_CLOCKS) - struct timespec tm; - - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm); - - return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000; -#else - struct timeval tv; - - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000LL + tv.tv_usec / 1000; -#endif + // Needed for PageCache, which we currently have disabled. + return 0.0F; } } // namespace WebCore diff --git a/WebCore/platform/android/TemporaryLinkStubs.cpp b/WebCore/platform/android/TemporaryLinkStubs.cpp index 01789f4..5d71dd0 100644 --- a/WebCore/platform/android/TemporaryLinkStubs.cpp +++ b/WebCore/platform/android/TemporaryLinkStubs.cpp @@ -424,6 +424,12 @@ String contextMenuItemTagRightToLeft() return String(); } +String contextMenuItemTagTextDirectionMenu() +{ + ASSERT(0); + return String(); +} + } // namespace WebCore // FIXME, no support for spelling yet. @@ -601,14 +607,6 @@ void ContextMenuItem::setEnabled(bool) notImplemented(); } -namespace WebCore { - -float userIdleTime() -{ - notImplemented(); - return 0; -} - // systemBeep() is called by the Editor to indicate that there was nothing to copy, and may be called from // other places too. void systemBeep() @@ -616,8 +614,6 @@ void systemBeep() notImplemented(); } -} - // functions new to Jun-07 tip of tree merge: // void WebCore::CachedPage::close() {} @@ -750,14 +746,14 @@ PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String&) namespace JSC { namespace Bindings { -bool dispatchJNICall(ExecState*, void const*, _jobject*, bool, JNIType, - _jmethodID*, jvalue*, jvalue&, char const*, JSValue*&) +bool dispatchJNICall(ExecState*, const void* targetAppletView, jobject obj, bool isStatic, JNIType returnType, + jmethodID methodID, jvalue* args, jvalue& result, const char* callingURL, JSValuePtr& exceptionDescription) { notImplemented(); return false; } -} } // namespace JSC::Bindings +} } // namespace Bindings char* dirname(const char*) { @@ -811,12 +807,6 @@ ScrollbarTheme* ScrollbarTheme::nativeTheme() return &theme; } -JSC::JSValue* toJS(JSC::ExecState*, JSC::Profile*) -{ - notImplemented(); - return 0; -} - } // namespace WebCore FileList::FileList() @@ -862,30 +852,38 @@ OpaqueJSClassContextData::~OpaqueJSClassContextData() notImplemented(); } +// as we don't use inspector/*.cpp, add stub here. + namespace WebCore { -JSC::JSValue* JavaScriptCallFrame::evaluate(JSC::UString const&, JSC::JSValue*&) const +JSValuePtr toJS(ExecState*, Profile*) { notImplemented(); - return 0; + return jsNull(); +} + +JSValuePtr JavaScriptCallFrame::evaluate(const UString& script, JSValuePtr& exception) const +{ + notImplemented(); + return jsNull(); } -const JSC::ScopeChainNode* JavaScriptCallFrame::scopeChain() const +const ScopeChainNode* JavaScriptCallFrame::scopeChain() const { notImplemented(); return 0; } -JSC::JSObject* JavaScriptCallFrame::thisObject() const +JSObject* JavaScriptCallFrame::thisObject() const { notImplemented(); return 0; } -JSC::DebuggerCallFrame::Type JavaScriptCallFrame::type() const +DebuggerCallFrame::Type JavaScriptCallFrame::type() const { notImplemented(); - return (JSC::DebuggerCallFrame::Type) 0; + return (DebuggerCallFrame::Type) 0; } JavaScriptCallFrame* JavaScriptCallFrame::caller() @@ -899,6 +897,7 @@ String JavaScriptCallFrame::functionName() const notImplemented(); return String(); } + } JavaScriptDebugServer::JavaScriptDebugServer() : diff --git a/WebCore/platform/animation/Animation.cpp b/WebCore/platform/animation/Animation.cpp new file mode 100644 index 0000000..5df4480 --- /dev/null +++ b/WebCore/platform/animation/Animation.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "Animation.h" + +namespace WebCore { + +Animation::Animation() + : m_delay(initialAnimationDelay()) + , m_direction(initialAnimationDirection()) + , m_duration(initialAnimationDuration()) + , m_iterationCount(initialAnimationIterationCount()) + , m_name(initialAnimationName()) + , m_property(initialAnimationProperty()) + , m_timingFunction(initialAnimationTimingFunction()) + , m_playState(initialAnimationPlayState()) + , m_delaySet(false) + , m_directionSet(false) + , m_durationSet(false) + , m_iterationCountSet(false) + , m_nameSet(false) + , m_playStateSet(false) + , m_propertySet(false) + , m_timingFunctionSet(false) + , m_isNone(false) +{ +} + +Animation::Animation(const Animation& o) + : RefCounted<Animation>() + , m_delay(o.m_delay) + , m_direction(o.m_direction) + , m_duration(o.m_duration) + , m_iterationCount(o.m_iterationCount) + , m_name(o.m_name) + , m_property(o.m_property) + , m_timingFunction(o.m_timingFunction) + , m_playState(o.m_playState) + , m_delaySet(o.m_delaySet) + , m_directionSet(o.m_directionSet) + , m_durationSet(o.m_durationSet) + , m_iterationCountSet(o.m_iterationCountSet) + , m_nameSet(o.m_nameSet) + , m_playStateSet(o.m_playStateSet) + , m_propertySet(o.m_propertySet) + , m_timingFunctionSet(o.m_timingFunctionSet) + , m_isNone(o.m_isNone) +{ +} + +Animation& Animation::operator=(const Animation& o) +{ + m_delay = o.m_delay; + m_direction = o.m_direction; + m_duration = o.m_duration; + m_iterationCount = o.m_iterationCount; + m_name = o.m_name; + m_playState = o.m_playState; + m_property = o.m_property; + m_timingFunction = o.m_timingFunction; + + m_delaySet = o.m_delaySet; + m_directionSet = o.m_directionSet; + m_durationSet = o.m_durationSet; + m_iterationCountSet = o.m_iterationCountSet; + m_nameSet = o.m_nameSet; + m_playStateSet = o.m_playStateSet; + m_propertySet = o.m_propertySet; + m_timingFunctionSet = o.m_timingFunctionSet; + + m_isNone = o.m_isNone; + + return *this; +} + +Animation::~Animation() +{ +} + +bool Animation::animationsMatch(const Animation* o, bool matchPlayStates) const +{ + if (!o) + return false; + + bool result = m_delay == o->m_delay && + m_direction == o->m_direction && + m_duration == o->m_duration && + m_iterationCount == o->m_iterationCount && + m_name == o->m_name && + m_property == o->m_property && + m_timingFunction == o->m_timingFunction && + m_delaySet == o->m_delaySet && + m_directionSet == o->m_directionSet && + m_durationSet == o->m_durationSet && + m_iterationCountSet == o->m_iterationCountSet && + m_nameSet == o->m_nameSet && + m_propertySet == o->m_propertySet && + m_timingFunctionSet == o->m_timingFunctionSet && + m_isNone == o->m_isNone; + + if (!result) + return false; + + return !matchPlayStates || (m_playState == o->m_playState && m_playStateSet == o->m_playStateSet); +} + +} // namespace WebCore diff --git a/WebCore/platform/animation/Animation.h b/WebCore/platform/animation/Animation.h new file mode 100644 index 0000000..294acdf --- /dev/null +++ b/WebCore/platform/animation/Animation.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.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 Animation_h +#define Animation_h + +#include "PlatformString.h" +#include "TimingFunction.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +const int cAnimateNone = 0; +const int cAnimateAll = -2; + +class Animation : public RefCounted<Animation> { +public: + ~Animation(); + + static PassRefPtr<Animation> create() { return adoptRef(new Animation); }; + + bool isDelaySet() const { return m_delaySet; } + bool isDirectionSet() const { return m_directionSet; } + bool isDurationSet() const { return m_durationSet; } + bool isIterationCountSet() const { return m_iterationCountSet; } + bool isNameSet() const { return m_nameSet; } + bool isPlayStateSet() const { return m_playStateSet; } + bool isPropertySet() const { return m_propertySet; } + bool isTimingFunctionSet() const { return m_timingFunctionSet; } + + // Flags this to be the special "none" animation (animation-name: none) + bool isNoneAnimation() const { return m_isNone; } + // We can make placeholder Animation objects to keep the comma-separated lists + // of properties in sync. isValidAnimation means this is not a placeholder. + bool isValidAnimation() const { return !m_isNone && !m_name.isEmpty(); } + + bool isEmpty() const + { + return (!m_directionSet && !m_durationSet && !m_nameSet && !m_playStateSet && + !m_iterationCountSet && !m_delaySet && !m_timingFunctionSet && !m_propertySet); + } + + bool isEmptyOrZeroDuration() const + { + return isEmpty() || (m_duration == 0 && m_delay <= 0); + } + + void clearDelay() { m_delaySet = false; } + void clearDirection() { m_directionSet = false; } + void clearDuration() { m_durationSet = false; } + void clearIterationCount() { m_iterationCountSet = false; } + void clearName() { m_nameSet = false; } + void clearPlayState() { m_playStateSet = AnimPlayStatePlaying; } + void clearProperty() { m_propertySet = false; } + void clearTimingFunction() { m_timingFunctionSet = false; } + + double delay() const { return m_delay; } + bool direction() const { return m_direction; } + double duration() const { return m_duration; } + int iterationCount() const { return m_iterationCount; } + const String& name() const { return m_name; } + unsigned playState() const { return m_playState; } + int property() const { return m_property; } + const TimingFunction& timingFunction() const { return m_timingFunction; } + + void setDelay(double c) { m_delay = c; m_delaySet = true; } + void setDirection(bool d) { m_direction = d; m_directionSet = true; } + void setDuration(double d) { ASSERT(d >= 0); m_duration = d; m_durationSet = true; } + void setIterationCount(int c) { m_iterationCount = c; m_iterationCountSet = true; } + void setName(const String& n) { m_name = n; m_nameSet = true; } + void setPlayState(unsigned d) { m_playState = d; m_playStateSet = true; } + void setProperty(int t) { m_property = t; m_propertySet = true; } + void setTimingFunction(const TimingFunction& f) { m_timingFunction = f; m_timingFunctionSet = true; } + + void setIsNoneAnimation(bool n) { m_isNone = n; } + + Animation& operator=(const Animation& o); + + // return true if all members of this class match (excluding m_next) + bool animationsMatch(const Animation*, bool matchPlayStates = true) const; + + // return true every Animation in the chain (defined by m_next) match + bool operator==(const Animation& o) const { return animationsMatch(&o); } + bool operator!=(const Animation& o) const { return !(*this == o); } + +private: + Animation(); + Animation(const Animation& o); + + double m_delay; + bool m_direction; + double m_duration; + int m_iterationCount; + String m_name; + int m_property; + TimingFunction m_timingFunction; + + unsigned m_playState : 2; + + bool m_delaySet : 1; + bool m_directionSet : 1; + bool m_durationSet : 1; + bool m_iterationCountSet : 1; + bool m_nameSet : 1; + bool m_playStateSet : 1; + bool m_propertySet : 1; + bool m_timingFunctionSet : 1; + + bool m_isNone : 1; + +public: + static float initialAnimationDelay() { return 0; } + static bool initialAnimationDirection() { return false; } + static double initialAnimationDuration() { return 0; } + static int initialAnimationIterationCount() { return 1; } + static String initialAnimationName() { return String("none"); } + static unsigned initialAnimationPlayState() { return AnimPlayStatePlaying; } + static int initialAnimationProperty() { return cAnimateAll; } + static TimingFunction initialAnimationTimingFunction() { return TimingFunction(); } +}; + +} // namespace WebCore + +#endif // Animation_h diff --git a/WebCore/platform/animation/AnimationList.cpp b/WebCore/platform/animation/AnimationList.cpp new file mode 100644 index 0000000..804dede --- /dev/null +++ b/WebCore/platform/animation/AnimationList.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "AnimationList.h" + +namespace WebCore { + +#define FILL_UNSET_PROPERTY(test, propGet, propSet) \ +for (i = 0; i < size() && animation(i)->test(); ++i) { } \ +if (i < size() && i != 0) { \ + for (size_t j = 0; i < size(); ++i, ++j) \ + animation(i)->propSet(animation(j)->propGet()); \ +} + +void AnimationList::fillUnsetProperties() +{ + size_t i; + FILL_UNSET_PROPERTY(isDelaySet, delay, setDelay); + FILL_UNSET_PROPERTY(isDirectionSet, direction, setDirection); + FILL_UNSET_PROPERTY(isDurationSet, duration, setDuration); + FILL_UNSET_PROPERTY(isIterationCountSet, iterationCount, setIterationCount); + FILL_UNSET_PROPERTY(isPlayStateSet, playState, setPlayState); + FILL_UNSET_PROPERTY(isNameSet, name, setName); + FILL_UNSET_PROPERTY(isTimingFunctionSet, timingFunction, setTimingFunction); + FILL_UNSET_PROPERTY(isPropertySet, property, setProperty); +} + +bool AnimationList::operator==(const AnimationList& o) const +{ + if (size() != o.size()) + return false; + for (size_t i = 0; i < size(); ++i) + if (*animation(i) != *o.animation(i)) + return false; + return true; +} + +} // namespace WebCore diff --git a/WebCore/platform/animation/AnimationList.h b/WebCore/platform/animation/AnimationList.h new file mode 100644 index 0000000..9901424 --- /dev/null +++ b/WebCore/platform/animation/AnimationList.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.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 AnimationList_h +#define AnimationList_h + +#include "Animation.h" +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class AnimationList { +public: + void fillUnsetProperties(); + bool operator==(const AnimationList& o) const; + bool operator!=(const AnimationList& o) const + { + return !(*this == o); + } + + size_t size() const { return m_animations.size(); } + bool isEmpty() const { return m_animations.isEmpty(); } + + void resize(size_t n) { m_animations.resize(n); } + void remove(size_t i) { m_animations.remove(i); } + void append(PassRefPtr<Animation> anim) { m_animations.append(anim); } + + Animation* animation(size_t i) { return m_animations[i].get(); } + const Animation* animation(size_t i) const { return m_animations[i].get(); } + +private: + Vector<RefPtr<Animation> > m_animations; +}; + + +} // namespace WebCore + +#endif // AnimationList_h diff --git a/WebCore/platform/animation/TimingFunction.h b/WebCore/platform/animation/TimingFunction.h new file mode 100644 index 0000000..f114596 --- /dev/null +++ b/WebCore/platform/animation/TimingFunction.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.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 TimingFunction_h +#define TimingFunction_h + +#include "RenderStyleConstants.h" + +namespace WebCore { + +struct TimingFunction { + TimingFunction() + : m_type(CubicBezierTimingFunction) + , m_x1(0.25) + , m_y1(0.1) + , m_x2(0.25) + , m_y2(1.0) + { + } + + TimingFunction(ETimingFunctionType timingFunction, double x1 = 0.0, double y1 = 0.0, double x2 = 1.0, double y2 = 1.0) + : m_type(timingFunction) + , m_x1(x1) + , m_y1(y1) + , m_x2(x2) + , m_y2(y2) + { + } + + bool operator==(const TimingFunction& o) const + { + return m_type == o.m_type && m_x1 == o.m_x1 && m_y1 == o.m_y1 && m_x2 == o.m_x2 && m_y2 == o.m_y2; + } + + double x1() const { return m_x1; } + double y1() const { return m_y1; } + double x2() const { return m_x2; } + double y2() const { return m_y2; } + + ETimingFunctionType type() const { return m_type; } + +private: + ETimingFunctionType m_type; + + double m_x1; + double m_y1; + double m_x2; + double m_y2; +}; + +} // namespace WebCore + +#endif // TimingFunction_h diff --git a/WebCore/platform/cf/SharedBufferCF.cpp b/WebCore/platform/cf/SharedBufferCF.cpp index c0e471a..7213c7e 100644 --- a/WebCore/platform/cf/SharedBufferCF.cpp +++ b/WebCore/platform/cf/SharedBufferCF.cpp @@ -28,6 +28,8 @@ #include "config.h" #include "SharedBuffer.h" +#include "PurgeableBuffer.h" + namespace WebCore { SharedBuffer::SharedBuffer(CFDataRef cfData) diff --git a/WebCore/platform/chromium/ChromiumBridge.h b/WebCore/platform/chromium/ChromiumBridge.h new file mode 100644 index 0000000..dd36c1a --- /dev/null +++ b/WebCore/platform/chromium/ChromiumBridge.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2008, 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 ChromiumBridge_h +#define ChromiumBridge_h + +#include "LinkHash.h" +#include "PassRefPtr.h" +#include "PasteboardPrivate.h" + +class NativeImageSkia; + +typedef struct NPObject NPObject; +typedef struct _NPP NPP_t; +typedef NPP_t* NPP; + +#if PLATFORM(WIN_OS) +typedef struct HFONT__* HFONT; +#endif + +namespace WebCore { + + class Color; + class Cursor; + class Document; + class Frame; + class GraphicsContext; + class Image; + class IntRect; + class KURL; + class String; + class Widget; + + struct PluginInfo; + + // An interface to the embedding layer, which has the ability to answer + // questions about the system and so on... + + class ChromiumBridge { + public: + // Clipboard ---------------------------------------------------------- + static bool clipboardIsFormatAvailable(PasteboardPrivate::ClipboardFormat); + + static String clipboardReadPlainText(); + static void clipboardReadHTML(String*, KURL*); + + static void clipboardWriteSelection(const String&, const KURL&, const String&, bool); + static void clipboardWriteURL(const KURL&, const String&); + static void clipboardWriteImage(const NativeImageSkia*, const KURL&, const String&); + + // Cookies ------------------------------------------------------------ + static void setCookies(const KURL& url, const KURL& policyURL, const String& value); + static String cookies(const KURL& url, const KURL& policyURL); + + // DNS ---------------------------------------------------------------- + static void prefetchDNS(const String& hostname); + + // Font --------------------------------------------------------------- +#if PLATFORM(WIN_OS) + static bool ensureFontLoaded(HFONT font); +#endif + + // Forms -------------------------------------------------------------- + static void notifyFormStateChanged(const Document*); + + // JavaScript --------------------------------------------------------- + static void notifyJSOutOfMemory(Frame*); + + // Language ----------------------------------------------------------- + static String computedDefaultLanguage(); + + // LayoutTestMode ----------------------------------------------------- + static bool layoutTestMode(); + + // MimeType ----------------------------------------------------------- + static bool isSupportedImageMIMEType(const char* mimeType); + static bool isSupportedJavascriptMIMEType(const char* mimeType); + static bool isSupportedNonImageMIMEType(const char* mimeType); + static bool matchesMIMEType(const String& pattern, const String& type); + static String mimeTypeForExtension(const String& ext); + static String mimeTypeFromFile(const String& filePath); + static String preferredExtensionForMIMEType(const String& mimeType); + + // Plugin ------------------------------------------------------------- + static bool plugins(bool refresh, Vector<PluginInfo*>*); + static NPObject* pluginScriptableObject(Widget*); + static bool popupsAllowed(NPP); + + // Protocol ----------------------------------------------------------- + static String uiResourceProtocol(); + + // Resources ---------------------------------------------------------- + static PassRefPtr<Image> loadPlatformImageResource(const char* name); + + // Screen ------------------------------------------------------------- + static int screenDepth(Widget*); + static int screenDepthPerComponent(Widget*); + static bool screenIsMonochrome(Widget*); + static IntRect screenRect(Widget*); + static IntRect screenAvailableRect(Widget*); + + // SharedTimers ------------------------------------------------------- + static void setSharedTimerFiredFunction(void (*func)()); + static void setSharedTimerFireTime(double fireTime); + static void stopSharedTimer(); + + // StatsCounters ------------------------------------------------------ + static void decrementStatsCounter(const char* name); + static void incrementStatsCounter(const char* name); + static void initV8CounterFunction(); + + // SystemTime --------------------------------------------------------- + static double currentTime(); + + // Theming ------------------------------------------------------------ +#if PLATFORM(WIN_OS) + static void paintButton( + GraphicsContext*, int part, int state, int classicState, const IntRect&); + static void paintMenuList( + GraphicsContext*, int part, int state, int classicState, const IntRect&); + static void paintScrollbarArrow( + GraphicsContext*, int state, int classicState, const IntRect&); + static void paintScrollbarThumb( + GraphicsContext*, int part, int state, int classicState, const IntRect&); + static void paintScrollbarTrack( + GraphicsContext*, int part, int state, int classicState, const IntRect&, const IntRect& alignRect); + static void paintTextField( + GraphicsContext*, int part, int state, int classicState, const IntRect&, const Color&, bool fillContentArea, bool drawEdges); +#endif + + // Trace Event -------------------------------------------------------- + static void traceEventBegin(const char* name, void* id, const char* extra); + static void traceEventEnd(const char* name, void* id, const char* extra); + + // URL ---------------------------------------------------------------- + static KURL inspectorURL(); + + // Visited links ------------------------------------------------------ + static LinkHash visitedLinkHash(const UChar* url, unsigned length); + static LinkHash visitedLinkHash(const KURL& base, const AtomicString& attributeURL); + static bool isLinkVisited(LinkHash); + + // Widget ------------------------------------------------------------- + static void widgetSetCursor(Widget*, const Cursor&); + static void widgetSetFocus(Widget*); + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/chromium/ChromiumDataObject.cpp b/WebCore/platform/chromium/ChromiumDataObject.cpp new file mode 100644 index 0000000..67e9d00 --- /dev/null +++ b/WebCore/platform/chromium/ChromiumDataObject.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2008, 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 "ChromiumDataObject.h" + +namespace WebCore { + +void ChromiumDataObject::clear() +{ + url = KURL(); + urlTitle = ""; + filenames.clear(); + plainText = ""; + textHtml = ""; + htmlBaseUrl = KURL(); + fileContentFilename = ""; + if (fileContent) + fileContent->clear(); +} + +bool ChromiumDataObject::hasData() +{ + return !url.isEmpty() + || !filenames.isEmpty() + || !plainText.isEmpty() + || !textHtml.isEmpty() + || fileContent; +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/ChromiumDataObject.h b/WebCore/platform/chromium/ChromiumDataObject.h new file mode 100644 index 0000000..448e763 --- /dev/null +++ b/WebCore/platform/chromium/ChromiumDataObject.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2008, 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 ChromiumDataObject_h +#define ChromiumDataObject_h + +#include "KURL.h" +#include "PlatformString.h" +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + + // A data object for holding data that would be in a clipboard or moved + // during a drag-n-drop operation. This is the data that WebCore is aware + // of and is not specific to a platform. + class ChromiumDataObject : public RefCounted<ChromiumDataObject> { + public: + static PassRefPtr<ChromiumDataObject> create() + { + return adoptRef(new ChromiumDataObject); + } + + void clear(); + bool hasData(); + + KURL url; + String urlTitle; + + Vector<String> filenames; + + String plainText; + + String textHtml; + KURL htmlBaseUrl; + + String fileContentFilename; + RefPtr<SharedBuffer> fileContent; + + private: + ChromiumDataObject() {} + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/chromium/ClipboardChromium.cpp b/WebCore/platform/chromium/ClipboardChromium.cpp new file mode 100644 index 0000000..7fc156e --- /dev/null +++ b/WebCore/platform/chromium/ClipboardChromium.cpp @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Google 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 "ClipboardChromium.h" + +#include "CachedImage.h" +#include "ChromiumBridge.h" +#include "ChromiumDataObject.h" +#include "ClipboardUtilitiesChromium.h" +#include "Document.h" +#include "Element.h" +#include "Frame.h" +#include "HTMLNames.h" +#include "MIMETypeRegistry.h" +#include "markup.h" +#include "PlatformString.h" +#include "Range.h" +#include "RenderImage.h" +#include "StringBuilder.h" + +namespace WebCore { + +using namespace HTMLNames; + +// We provide the IE clipboard types (URL and Text), and the clipboard types specified in the WHATWG Web Applications 1.0 draft +// see http://www.whatwg.org/specs/web-apps/current-work/ Section 6.3.5.3 + +enum ClipboardDataType { ClipboardDataTypeNone, ClipboardDataTypeURL, ClipboardDataTypeText }; + +static ClipboardDataType clipboardTypeFromMIMEType(const String& type) +{ + String cleanType = type.stripWhiteSpace().lower(); + + // two special cases for IE compatibility + if (cleanType == "text" || cleanType == "text/plain" || cleanType.startsWith("text/plain;")) + return ClipboardDataTypeText; + if (cleanType == "url" || cleanType == "text/uri-list") + return ClipboardDataTypeURL; + + return ClipboardDataTypeNone; +} + +ClipboardChromium::ClipboardChromium(bool isForDragging, + PassRefPtr<ChromiumDataObject> dataObject, + ClipboardAccessPolicy policy) + : Clipboard(policy, isForDragging) + , m_dataObject(dataObject) +{ +} + +PassRefPtr<ClipboardChromium> ClipboardChromium::create(bool isForDragging, + PassRefPtr<ChromiumDataObject> dataObject, ClipboardAccessPolicy policy) +{ + return adoptRef(new ClipboardChromium(isForDragging, dataObject, policy)); +} + +void ClipboardChromium::clearData(const String& type) +{ + if (policy() != ClipboardWritable || !m_dataObject) + return; + + ClipboardDataType dataType = clipboardTypeFromMIMEType(type); + + if (dataType == ClipboardDataTypeURL) { + m_dataObject->url = KURL(); + m_dataObject->urlTitle = ""; + } + if (dataType == ClipboardDataTypeText) + m_dataObject->plainText = ""; +} + +void ClipboardChromium::clearAllData() +{ + if (policy() != ClipboardWritable) + return; + + m_dataObject->clear(); +} + +String ClipboardChromium::getData(const String& type, bool& success) const +{ + success = false; + if (policy() != ClipboardReadable || !m_dataObject) + return String(); + + ClipboardDataType dataType = clipboardTypeFromMIMEType(type); + String text; + if (dataType == ClipboardDataTypeText) { + 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(); + success = !text.isEmpty(); + } else if (!m_dataObject->plainText.isEmpty()) { + success = true; + text = m_dataObject->plainText; + } + } else if (dataType == ClipboardDataTypeURL) { + // FIXME: Handle the cut/paste event. This requires adding a new IPC + // message to get the URL from the clipboard directly. + if (!m_dataObject->url.isEmpty()) { + success = true; + text = m_dataObject->url.string(); + } + } + + return text; +} + +bool ClipboardChromium::setData(const String& type, const String& data) +{ + if (policy() != ClipboardWritable) + return false; + + ClipboardDataType winType = clipboardTypeFromMIMEType(type); + + if (winType == ClipboardDataTypeURL) { + m_dataObject->url = KURL(data); + return m_dataObject->url.isValid(); + } + + if (winType == ClipboardDataTypeText) { + m_dataObject->plainText = data; + return true; + } + return false; +} + +// extensions beyond IE's API +HashSet<String> ClipboardChromium::types() const +{ + HashSet<String> results; + if (policy() != ClipboardReadable && policy() != ClipboardTypesReadable) + return results; + + if (!m_dataObject) + return results; + + if (m_dataObject->url.isValid()) { + results.add("URL"); + results.add("text/uri-list"); + } + + if (!m_dataObject->plainText.isEmpty()) { + results.add("Text"); + results.add("text/plain"); + } + + return results; +} + +void ClipboardChromium::setDragImage(CachedImage* image, Node* node, const IntPoint& loc) +{ + if (policy() != ClipboardImageWritable && policy() != ClipboardWritable) + return; + + if (m_dragImage) + m_dragImage->removeClient(this); + m_dragImage = image; + if (m_dragImage) + m_dragImage->addClient(this); + + m_dragLoc = loc; + m_dragImageElement = node; +} + +void ClipboardChromium::setDragImage(CachedImage* img, const IntPoint& loc) +{ + setDragImage(img, 0, loc); +} + +void ClipboardChromium::setDragImageElement(Node* node, const IntPoint& loc) +{ + setDragImage(0, node, loc); +} + +DragImageRef ClipboardChromium::createDragImage(IntPoint& loc) const +{ + DragImageRef result = 0; + if (m_dragImage) { + result = createDragImageFromImage(m_dragImage->image()); + loc = m_dragLoc; + } + return result; +} + +static String imageToMarkup(const String& url, Element* element) +{ + StringBuilder markup; + markup.append("<img src=\""); + markup.append(url); + markup.append("\""); + // Copy over attributes. If we are dragging an image, we expect things like + // the id to be copied as well. + NamedAttrMap* attrs = element->attributes(); + unsigned length = attrs->length(); + for (unsigned i = 0; i < length; ++i) { + Attribute* attr = attrs->attributeItem(i); + if (attr->localName() == "src") + continue; + markup.append(" "); + markup.append(attr->localName()); + markup.append("=\""); + String escapedAttr = attr->value(); + escapedAttr.replace("\"", """); + markup.append(escapedAttr); + markup.append("\""); + } + + markup.append("/>"); + return markup.toString(); +} + +static CachedImage* getCachedImage(Element* element) +{ + // Attempt to pull CachedImage from element + ASSERT(element); + RenderObject* renderer = element->renderer(); + if (!renderer || !renderer->isImage()) + return 0; + + RenderImage* image = static_cast<RenderImage*>(renderer); + if (image->cachedImage() && !image->cachedImage()->errorOccurred()) + return image->cachedImage(); + + return 0; +} + +static void writeImageToDataObject(ChromiumDataObject* dataObject, Element* element, + const KURL& url) +{ + // Shove image data into a DataObject for use as a file + CachedImage* cachedImage = getCachedImage(element); + if (!cachedImage || !cachedImage->image() || !cachedImage->isLoaded()) + return; + + SharedBuffer* imageBuffer = cachedImage->image()->data(); + if (!imageBuffer || !imageBuffer->size()) + return; + + dataObject->fileContent = imageBuffer; + + // Determine the filename for the file contents of the image. We try to + // use the alt tag if one exists, otherwise we fall back on the suggested + // filename in the http header, and finally we resort to using the filename + // in the URL. + String extension("."); + extension += MIMETypeRegistry::getPreferredExtensionForMIMEType( + cachedImage->response().mimeType()); + String title = element->getAttribute(altAttr); + if (title.isEmpty()) { + title = cachedImage->response().suggestedFilename(); + // FIXME: If title is empty, get the filename from the URL. + } + dataObject->fileContentFilename = title + extension; +} + +void ClipboardChromium::declareAndWriteDragImage(Element* element, const KURL& url, const String& title, Frame* frame) +{ + if (!m_dataObject) + return; + + m_dataObject->url = url; + m_dataObject->urlTitle = title; + + // Write the bytes in the image to the file format. + writeImageToDataObject(m_dataObject.get(), element, url); + + AtomicString imageURL = element->getAttribute(srcAttr); + if (imageURL.isEmpty()) + return; + + String fullURL = frame->document()->completeURL(parseURL(imageURL)); + if (fullURL.isEmpty()) + return; + + // Put img tag on the clipboard referencing the image + m_dataObject->textHtml = imageToMarkup(fullURL, element); +} + +void ClipboardChromium::writeURL(const KURL& url, const String& title, Frame*) +{ + if (!m_dataObject) + return; + m_dataObject->url = url; + m_dataObject->urlTitle = title; + + // The URL can also be used as plain text. + m_dataObject->plainText = url.string(); + + // The URL can also be used as an HTML fragment. + m_dataObject->textHtml = urlToMarkup(url, title); + m_dataObject->htmlBaseUrl = url; +} + +void ClipboardChromium::writeRange(Range* selectedRange, Frame* frame) +{ + ASSERT(selectedRange); + if (!m_dataObject) + return; + + m_dataObject->textHtml = createMarkup(selectedRange, 0, + AnnotateForInterchange); + m_dataObject->htmlBaseUrl = frame->document()->url(); + + String str = frame->selectedText(); +#if PLATFORM(WIN_OS) + replaceNewlinesWithWindowsStyleNewlines(str); +#endif + replaceNBSPWithSpace(str); + m_dataObject->plainText = str; +} + +bool ClipboardChromium::hasData() +{ + if (!m_dataObject) + return false; + + return m_dataObject->hasData(); +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/ClipboardChromium.h b/WebCore/platform/chromium/ClipboardChromium.h new file mode 100644 index 0000000..1864c1a --- /dev/null +++ b/WebCore/platform/chromium/ClipboardChromium.h @@ -0,0 +1,84 @@ +// 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. + +#ifndef ClipboardChromium_h +#define ClipboardChromium_h + +#include "Clipboard.h" + +#include "CachedResourceClient.h" + +namespace WebCore { + + class CachedImage; + class ChromiumDataObject; + class IntPoint; + + class ClipboardChromium : public Clipboard, public CachedResourceClient { + public: + ~ClipboardChromium() {} + + static PassRefPtr<ClipboardChromium> create( + bool isForDragging, PassRefPtr<ChromiumDataObject>, ClipboardAccessPolicy); + + virtual void clearData(const String& type); + void clearAllData(); + String getData(const String& type, bool& success) const; + bool setData(const String& type, const String& data); + + // extensions beyond IE's API + HashSet<String> types() const; + + void setDragImage(CachedImage*, const IntPoint&); + void setDragImageElement(Node*, const IntPoint&); + + PassRefPtr<ChromiumDataObject> dataObject() + { + return m_dataObject; + } + + virtual DragImageRef createDragImage(IntPoint& dragLoc) const; + virtual void declareAndWriteDragImage(Element*, const KURL&, const String& title, Frame*); + virtual void writeURL(const KURL&, const String&, Frame*); + virtual void writeRange(Range*, Frame*); + + virtual bool hasData(); + + private: + ClipboardChromium(bool, PassRefPtr<ChromiumDataObject>, ClipboardAccessPolicy); + + void resetFromClipboard(); + void setDragImage(CachedImage*, Node*, const IntPoint&); + RefPtr<ChromiumDataObject> m_dataObject; + Frame* m_frame; + }; + +} // namespace WebCore + +#endif // ClipboardChromium_h diff --git a/WebCore/platform/chromium/ClipboardUtilitiesChromium.cpp b/WebCore/platform/chromium/ClipboardUtilitiesChromium.cpp new file mode 100644 index 0000000..7efcb3c --- /dev/null +++ b/WebCore/platform/chromium/ClipboardUtilitiesChromium.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2008, 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 "ClipboardUtilitiesChromium.h" + +#include "KURL.h" +#include "PlatformString.h" + +namespace WebCore { + +#if PLATFORM(WIN_OS) +void replaceNewlinesWithWindowsStyleNewlines(String& str) +{ + static const UChar Newline = '\n'; + static const char* const WindowsNewline("\r\n"); + str.replace(Newline, WindowsNewline); +} +#endif + +void replaceNBSPWithSpace(String& str) +{ + static const UChar NonBreakingSpaceCharacter = 0xA0; + static const UChar SpaceCharacter = ' '; + str.replace(NonBreakingSpaceCharacter, SpaceCharacter); +} + +String urlToMarkup(const KURL& url, const String& title) +{ + String markup("<a href=\""); + markup.append(url.string()); + markup.append("\">"); + // FIXME: HTML escape this, possibly by moving into the glue layer so we + // can use net/base/escape.h. + markup.append(title); + markup.append("</a>"); + return markup; +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/ClipboardUtilitiesChromium.h b/WebCore/platform/chromium/ClipboardUtilitiesChromium.h new file mode 100644 index 0000000..c597089 --- /dev/null +++ b/WebCore/platform/chromium/ClipboardUtilitiesChromium.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2008, 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. + */ + +namespace WebCore { + +class KURL; +class String; + +#if PLATFORM(WIN_OS) +void replaceNewlinesWithWindowsStyleNewlines(String&); +#endif +void replaceNBSPWithSpace(String&); + +String urlToMarkup(const KURL&, const String&); + +} // namespace WebCore diff --git a/WebCore/platform/chromium/ContextMenuChromium.cpp b/WebCore/platform/chromium/ContextMenuChromium.cpp new file mode 100644 index 0000000..0614e3e --- /dev/null +++ b/WebCore/platform/chromium/ContextMenuChromium.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2008, 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 "ContextMenu.h" + +namespace WebCore { + +// This is a stub implementation of WebKit's ContextMenu class that does +// nothing. + +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) +{ +} + +ContextMenu::~ContextMenu() +{ +} + +unsigned ContextMenu::itemCount() const +{ + return 0; +} + +void ContextMenu::insertItem(unsigned position, ContextMenuItem& item) +{ +} + +void ContextMenu::appendItem(ContextMenuItem& item) +{ +} + +ContextMenuItem* ContextMenu::itemWithAction(unsigned action) +{ + return 0; +} + +ContextMenuItem* ContextMenu::itemAtIndex(unsigned index, const PlatformMenuDescription platformDescription) +{ + return 0; +} + +void ContextMenu::setPlatformDescription(PlatformMenuDescription menu) +{ +} + +PlatformMenuDescription ContextMenu::platformDescription() const +{ + return m_platformDescription; +} + +PlatformMenuDescription ContextMenu::releasePlatformDescription() +{ + return 0; +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/ContextMenuItemChromium.cpp b/WebCore/platform/chromium/ContextMenuItemChromium.cpp new file mode 100644 index 0000000..f34ea23 --- /dev/null +++ b/WebCore/platform/chromium/ContextMenuItemChromium.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2008, 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 "ContextMenuItem.h" + +namespace WebCore { + +// This is a stub implementation of WebKit's ContextMenu class that does +// nothing. + +ContextMenuItem::ContextMenuItem(PlatformMenuItemDescription item) +{ +} + +ContextMenuItem::ContextMenuItem(ContextMenu* subMenu) +{ +} + +ContextMenuItem::ContextMenuItem(ContextMenuItemType type, ContextMenuAction action, const String& title, ContextMenu* subMenu) +{ +} + +ContextMenuItem::~ContextMenuItem() +{ +} + +PlatformMenuItemDescription ContextMenuItem::releasePlatformDescription() +{ + return PlatformMenuItemDescription(); +} + +ContextMenuItemType ContextMenuItem::type() const +{ + return ContextMenuItemType(); +} + +ContextMenuAction ContextMenuItem::action() const +{ + return ContextMenuAction(); +} + +String ContextMenuItem::title() const +{ + return String(); +} + +PlatformMenuDescription ContextMenuItem::platformSubMenu() const +{ + return PlatformMenuDescription(); +} + +void ContextMenuItem::setType(ContextMenuItemType type) +{ +} + +void ContextMenuItem::setAction(ContextMenuAction action) +{ +} + +void ContextMenuItem::setTitle(const String& title) +{ +} + +void ContextMenuItem::setSubMenu(ContextMenu* subMenu) +{ +} + +void ContextMenuItem::setChecked(bool checked) +{ +} + +void ContextMenuItem::setEnabled(bool enabled) +{ +} + +bool ContextMenuItem::enabled() const +{ + return false; +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/CursorChromium.cpp b/WebCore/platform/chromium/CursorChromium.cpp new file mode 100644 index 0000000..16fa634 --- /dev/null +++ b/WebCore/platform/chromium/CursorChromium.cpp @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2008, 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 "Cursor.h" + +namespace WebCore { + +Cursor::Cursor(const Cursor& other) + : m_impl(other.m_impl) +{ +} + +Cursor::Cursor(Image* image, const IntPoint& hotSpot) + : m_impl(image, hotSpot) +{ +} + +Cursor::~Cursor() +{ +} + +Cursor& Cursor::operator=(const Cursor& other) +{ + m_impl = other.m_impl; + return *this; +} + +Cursor::Cursor(PlatformCursor c) + : m_impl(c) +{ +} + +const Cursor& pointerCursor() +{ + static const Cursor c(PlatformCursor::TypePointer); + return c; +} + +const Cursor& crossCursor() +{ + static const Cursor c(PlatformCursor::TypeCross); + return c; +} + +const Cursor& handCursor() +{ + static const Cursor c(PlatformCursor::TypeHand); + return c; +} + +const Cursor& iBeamCursor() +{ + static const Cursor c(PlatformCursor::TypeIBeam); + return c; +} + +const Cursor& waitCursor() +{ + static const Cursor c(PlatformCursor::TypeWait); + return c; +} + +const Cursor& helpCursor() +{ + static const Cursor c(PlatformCursor::TypeHelp); + return c; +} + +const Cursor& eastResizeCursor() +{ + static const Cursor c(PlatformCursor::TypeEastResize); + return c; +} + +const Cursor& northResizeCursor() +{ + static const Cursor c(PlatformCursor::TypeNorthResize); + return c; +} + +const Cursor& northEastResizeCursor() +{ + static const Cursor c(PlatformCursor::TypeNorthEastResize); + return c; +} + +const Cursor& northWestResizeCursor() +{ + static const Cursor c(PlatformCursor::TypeNorthWestResize); + return c; +} + +const Cursor& southResizeCursor() +{ + static const Cursor c(PlatformCursor::TypeSouthResize); + return c; +} + +const Cursor& southEastResizeCursor() +{ + static const Cursor c(PlatformCursor::TypeSouthEastResize); + return c; +} + +const Cursor& southWestResizeCursor() +{ + static const Cursor c(PlatformCursor::TypeSouthWestResize); + return c; +} + +const Cursor& westResizeCursor() +{ + static const Cursor c(PlatformCursor::TypeWestResize); + return c; +} + +const Cursor& northSouthResizeCursor() +{ + static const Cursor c(PlatformCursor::TypeNorthSouthResize); + return c; +} + +const Cursor& eastWestResizeCursor() +{ + static const Cursor c(PlatformCursor::TypeEastWestResize); + return c; +} + +const Cursor& northEastSouthWestResizeCursor() +{ + static const Cursor c(PlatformCursor::TypeNorthEastSouthWestResize); + return c; +} + +const Cursor& northWestSouthEastResizeCursor() +{ + static const Cursor c(PlatformCursor::TypeNorthWestSouthEastResize); + return c; +} + +const Cursor& columnResizeCursor() +{ + static const Cursor c(PlatformCursor::TypeColumnResize); + return c; +} + +const Cursor& rowResizeCursor() +{ + static const Cursor c(PlatformCursor::TypeRowResize); + return c; +} + +const Cursor& middlePanningCursor() +{ + static const Cursor c(PlatformCursor::TypeMiddlePanning); + return c; +} + +const Cursor& eastPanningCursor() +{ + static const Cursor c(PlatformCursor::TypeEastPanning); + return c; +} + +const Cursor& northPanningCursor() +{ + static const Cursor c(PlatformCursor::TypeNorthPanning); + return c; +} + +const Cursor& northEastPanningCursor() +{ + static const Cursor c(PlatformCursor::TypeNorthEastPanning); + return c; +} + +const Cursor& northWestPanningCursor() +{ + static const Cursor c(PlatformCursor::TypeNorthWestPanning); + return c; +} + +const Cursor& southPanningCursor() +{ + static const Cursor c(PlatformCursor::TypeSouthPanning); + return c; +} + +const Cursor& southEastPanningCursor() +{ + static const Cursor c(PlatformCursor::TypeSouthEastPanning); + return c; +} + +const Cursor& southWestPanningCursor() +{ + static const Cursor c(PlatformCursor::TypeSouthWestPanning); + return c; +} + +const Cursor& westPanningCursor() +{ + static const Cursor c(PlatformCursor::TypeWestPanning); + return c; +} + +const Cursor& moveCursor() +{ + static const Cursor c(PlatformCursor::TypeMove); + return c; +} + +const Cursor& verticalTextCursor() +{ + static const Cursor c(PlatformCursor::TypeVerticalText); + return c; +} + +const Cursor& cellCursor() +{ + static const Cursor c(PlatformCursor::TypeCell); + return c; +} + +const Cursor& contextMenuCursor() +{ + static const Cursor c(PlatformCursor::TypeContextMenu); + return c; +} + +const Cursor& aliasCursor() +{ + static const Cursor c(PlatformCursor::TypeAlias); + return c; +} + +const Cursor& progressCursor() +{ + static const Cursor c(PlatformCursor::TypeProgress); + return c; +} + +const Cursor& noDropCursor() +{ + static const Cursor c(PlatformCursor::TypeNoDrop); + return c; +} + +const Cursor& copyCursor() +{ + static const Cursor c(PlatformCursor::TypeCopy); + return c; +} + +const Cursor& noneCursor() +{ + static const Cursor c(PlatformCursor::TypeNone); + return c; +} + +const Cursor& notAllowedCursor() +{ + static const Cursor c(PlatformCursor::TypeNotAllowed); + return c; +} + +const Cursor& zoomInCursor() +{ + static const Cursor c(PlatformCursor::TypeZoomIn); + return c; +} + +const Cursor& zoomOutCursor() +{ + static const Cursor c(PlatformCursor::TypeZoomOut); + return c; +} + +const Cursor& grabCursor() +{ + return pointerCursor(); +} + +const Cursor& grabbingCursor() +{ + return pointerCursor(); +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/DragDataChromium.cpp b/WebCore/platform/chromium/DragDataChromium.cpp new file mode 100644 index 0000000..eaec025 --- /dev/null +++ b/WebCore/platform/chromium/DragDataChromium.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Google 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. + */ + +// Modified from DragDataWin.cpp to not directly call any windows methods as +// they may not be available to us in the multiprocess + +#include "config.h" +#include "DragData.h" + +#include "ChromiumDataObject.h" +#include "Clipboard.h" +#include "ClipboardChromium.h" +#include "DocumentFragment.h" +#include "KURL.h" +#include "markup.h" +#include "NotImplemented.h" +#include "PlatformString.h" + +namespace WebCore { + +static bool containsHTML(const ChromiumDataObject* dropData) +{ + return dropData->textHtml.length() > 0; +} + +PassRefPtr<Clipboard> DragData::createClipboard(ClipboardAccessPolicy policy) const +{ + RefPtr<ClipboardChromium> clipboard = ClipboardChromium::create(true, + m_platformDragData, policy); + + return clipboard.release(); +} + +bool DragData::containsURL() const +{ + return m_platformDragData->url.isValid(); +} + +String DragData::asURL(String* title) const +{ + if (!m_platformDragData->url.isValid()) + return String(); + + // |title| can be NULL + if (title) + *title = m_platformDragData->urlTitle; + return m_platformDragData->url.string(); +} + +bool DragData::containsFiles() const +{ + return !m_platformDragData->filenames.isEmpty(); +} + +void DragData::asFilenames(Vector<String>& result) const +{ + for (size_t i = 0; i < m_platformDragData->filenames.size(); ++i) + result.append(m_platformDragData->filenames[i]); +} + +bool DragData::containsPlainText() const +{ + return !m_platformDragData->plainText.isEmpty(); +} + +String DragData::asPlainText() const +{ + return m_platformDragData->plainText; +} + +bool DragData::containsColor() const +{ + notImplemented(); + return false; +} + +bool DragData::canSmartReplace() const +{ + // Mimic the situations in which mac allows drag&drop to do a smart replace. + // This is allowed whenever the drag data contains a 'range' (ie., + // ClipboardWin::writeRange is called). For example, dragging a link + // should not result in a space being added. + return !m_platformDragData->plainText.isEmpty() + && !m_platformDragData->url.isValid(); +} + +bool DragData::containsCompatibleContent() const +{ + return containsPlainText() + || containsURL() + || containsHTML(m_platformDragData) + || containsColor(); +} + +PassRefPtr<DocumentFragment> DragData::asFragment(Document* doc) const +{ + /* + * Order is richest format first. On OSX this is: + * * Web Archive + * * Filenames + * * HTML + * * RTF + * * TIFF + * * PICT + */ + + if (containsFiles()) { + // FIXME: Implement this. Should be pretty simple to make some HTML + // and call createFragmentFromMarkup. + //if (RefPtr<DocumentFragment> fragment = createFragmentFromMarkup(doc, + // ?, KURL())) + // return fragment; + } + + if (!m_platformDragData->textHtml.isEmpty()) { + RefPtr<DocumentFragment> fragment = createFragmentFromMarkup(doc, + m_platformDragData->textHtml, m_platformDragData->htmlBaseUrl); + return fragment.release(); + } + + return 0; +} + +Color DragData::asColor() const +{ + notImplemented(); + return Color(); +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/DragDataRef.h b/WebCore/platform/chromium/DragDataRef.h new file mode 100644 index 0000000..de1fa1c --- /dev/null +++ b/WebCore/platform/chromium/DragDataRef.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2008, 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 DragDataRef_h +#define DragDataRef_h + +#include "ChromiumDataObject.h" + +namespace WebCore { + + typedef ChromiumDataObject* DragDataRef; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/chromium/DragImageChromium.cpp b/WebCore/platform/chromium/DragImageChromium.cpp new file mode 100644 index 0000000..8c1484e --- /dev/null +++ b/WebCore/platform/chromium/DragImageChromium.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2008, 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 "DragImage.h" + +#include "NotImplemented.h" + +namespace WebCore { + +IntSize dragImageSize(DragImageRef image) +{ + notImplemented(); + return IntSize(); +} + +void deleteDragImage(DragImageRef image) +{ + notImplemented(); +} + +DragImageRef scaleDragImage(DragImageRef image, FloatSize scale) +{ + notImplemented(); + return 0; +} + +DragImageRef dissolveDragImageToFraction(DragImageRef image, float) +{ + notImplemented(); + return image; +} + +DragImageRef createDragImageFromImage(Image* img) +{ + notImplemented(); + return 0; +} + +DragImageRef createDragImageIconForCachedImage(CachedImage*) +{ + notImplemented(); + return 0; +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/DragImageRef.h b/WebCore/platform/chromium/DragImageRef.h new file mode 100644 index 0000000..53edd4f --- /dev/null +++ b/WebCore/platform/chromium/DragImageRef.h @@ -0,0 +1,40 @@ +// Copyright (c) 2008, 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 DragImageRef_h +#define DragImageRef_h + +namespace WebCore { + + // FIXME: Need to support image drag-n-drop. For now, we just allow things + // to compile by defining this dummy type. + typedef void* DragImageRef; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/DeprecatedPtrQueue.h b/WebCore/platform/chromium/FileChooserChromium.cpp index 226cb18..7603e92 100644 --- a/WebCore/platform/DeprecatedPtrQueue.h +++ b/WebCore/platform/chromium/FileChooserChromium.cpp @@ -1,5 +1,6 @@ /* - * Copyright (C) 2003 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,27 +24,27 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DeprecatedPtrQueue_h -#define DeprecatedPtrQueue_h +#include "config.h" +#include "FileChooser.h" -#include "DeprecatedPtrList.h" +#include "FileSystem.h" +#include "LocalizedStrings.h" +#include "StringTruncator.h" namespace WebCore { -template<class T> class DeprecatedPtrQueue +String FileChooser::basenameForWidth(const Font& font, int width) const { -public: - bool isEmpty() const { return list.isEmpty(); } - T *dequeue() { T *tmp = list.getFirst(); list.removeFirst(); return tmp; } - void enqueue(const T *item) { list.append (item); } - unsigned count() const { return list.count(); } - T *head() const { return list.getFirst(); } - DeprecatedPtrQueue<T> &operator=(const DeprecatedPtrQueue<T> &q) { list = q.list; return *this; } + if (width <= 0) + return String(); - private: - DeprecatedPtrList<T> list; -}; + String string; + if (!m_filenames.size()) + string = fileButtonNoFileSelectedLabel(); + else + string = pathGetFileName(m_filenames[0]); + return StringTruncator::centerTruncate(string, static_cast<float>(width), font, false); } -#endif /* DeprecatedPtrQueue_h */ +} // namespace WebCore diff --git a/WebCore/platform/chromium/FileSystemChromium.cpp b/WebCore/platform/chromium/FileSystemChromium.cpp new file mode 100644 index 0000000..afa0c27 --- /dev/null +++ b/WebCore/platform/chromium/FileSystemChromium.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2008, 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 "FileSystem.h" + +#include "NotImplemented.h" +#include "PlatformString.h" + +namespace WebCore { + +bool deleteFile(const String&) +{ + notImplemented(); + return false; +} + +bool deleteEmptyDirectory(const String&) +{ + notImplemented(); + return false; +} + +bool getFileSize(const String&, long long& result) +{ + notImplemented(); + return false; +} + +bool getFileModificationTime(const String&, time_t& result) +{ + notImplemented(); + return false; +} + +String directoryName(const String&) +{ + notImplemented(); + return String(); +} + +String pathByAppendingComponent(const String& path, const String& component) +{ + notImplemented(); + return String(); +} + +bool makeAllDirectories(const String& path) +{ + notImplemented(); + return false; +} + +bool fileExists(const String&) +{ + notImplemented(); + return false; +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/FileSystemChromiumLinux.cpp b/WebCore/platform/chromium/FileSystemChromiumLinux.cpp new file mode 100644 index 0000000..e388dee --- /dev/null +++ b/WebCore/platform/chromium/FileSystemChromiumLinux.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008, 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 "FileSystem.h" + +namespace WebCore { + +String pathGetFileName(const String& path) +{ + return path.substring(path.reverseFind('/') + 1); +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/FileSystemChromiumMac.mm b/WebCore/platform/chromium/FileSystemChromiumMac.mm new file mode 100644 index 0000000..7e880e1 --- /dev/null +++ b/WebCore/platform/chromium/FileSystemChromiumMac.mm @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2008, 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 "FileSystem.h" + +#import <Foundation/NSFileManager.h> +#include "PlatformString.h" + +namespace WebCore { + +String pathGetFileName(const String& path) +{ + return [[NSFileManager defaultManager] displayNameAtPath:path]; +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/FileSystemChromiumWin.cpp b/WebCore/platform/chromium/FileSystemChromiumWin.cpp new file mode 100644 index 0000000..704c39a --- /dev/null +++ b/WebCore/platform/chromium/FileSystemChromiumWin.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2008, 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 "FileSystem.h" + +#include <windows.h> +#include <shlwapi.h> + +namespace WebCore { + +String pathGetFileName(const String& path) +{ + return String(PathFindFileName(String(path).charactersWithNullTermination())); +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/FramelessScrollView.cpp b/WebCore/platform/chromium/FramelessScrollView.cpp new file mode 100644 index 0000000..114eabb --- /dev/null +++ b/WebCore/platform/chromium/FramelessScrollView.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2008, 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 "FramelessScrollView.h" + +#include "FramelessScrollViewClient.h" + +namespace WebCore { + +FramelessScrollView::~FramelessScrollView() +{ + // Remove native scrollbars now before we lose the connection to the HostWindow. + setHasHorizontalScrollbar(false); + setHasVerticalScrollbar(false); +} + +void FramelessScrollView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect) +{ + // Add in our offset within the ScrollView. + IntRect dirtyRect = rect; + dirtyRect.move(scrollbar->x(), scrollbar->y()); + invalidateRect(dirtyRect); +} + +bool FramelessScrollView::isActive() const +{ + // FIXME + return true; +} + +void FramelessScrollView::invalidateRect(const IntRect& rect) +{ + if (HostWindow* h = hostWindow()) + h->repaint(rect, true); +} + +HostWindow* FramelessScrollView::hostWindow() const +{ + return const_cast<FramelessScrollViewClient*>(m_client); +} + +IntRect FramelessScrollView::windowClipRect(bool clipToContents) const +{ + return contentsToWindow(visibleContentRect(!clipToContents)); +} + +void FramelessScrollView::paintContents(GraphicsContext*, const IntRect& damageRect) +{ +} + +void FramelessScrollView::contentsResized() +{ +} + +void FramelessScrollView::visibleContentsResized() +{ +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/FramelessScrollView.h b/WebCore/platform/chromium/FramelessScrollView.h new file mode 100644 index 0000000..300f418 --- /dev/null +++ b/WebCore/platform/chromium/FramelessScrollView.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2008, 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 FramelessScrollView_h +#define FramelessScrollView_h + +#include "ScrollView.h" + +namespace WebCore { + + class FramelessScrollViewClient; + class PlatformKeyboardEvent; + class PlatformMouseEvent; + class PlatformWheelEvent; + + // A FramelessScrollView is a ScrollView that can be used to render custom + // content, which does not have an associated Frame. + // + // NOTE: It may be better to just develop a custom subclass of Widget that + // can have scroll bars for this instead of trying to reuse ScrollView. + // + class FramelessScrollView : public ScrollView { + public: + FramelessScrollView() : m_client(0) {} + ~FramelessScrollView(); + + FramelessScrollViewClient* client() const { return m_client; } + void setClient(FramelessScrollViewClient* client) { m_client = client; } + + // Event handlers that subclasses must implement. + virtual bool handleMouseDownEvent(const PlatformMouseEvent&) = 0; + virtual bool handleMouseMoveEvent(const PlatformMouseEvent&) = 0; + virtual bool handleMouseReleaseEvent(const PlatformMouseEvent&) = 0; + virtual bool handleWheelEvent(const PlatformWheelEvent&) = 0; + virtual bool handleKeyEvent(const PlatformKeyboardEvent&) = 0; + + // ScrollbarClient public methods: + virtual void invalidateScrollbarRect(Scrollbar*, const IntRect&); + virtual bool isActive() const; + + // Widget public methods: + virtual void invalidateRect(const IntRect&); + + // ScrollView public methods: + virtual HostWindow* hostWindow() const; + virtual IntRect windowClipRect(bool clipToContents = true) const; + + protected: + // ScrollView protected methods: + virtual void paintContents(GraphicsContext*, const IntRect& damageRect); + virtual void contentsResized(); + virtual void visibleContentsResized(); + + private: + FramelessScrollViewClient* m_client; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/chromium/FramelessScrollViewClient.h b/WebCore/platform/chromium/FramelessScrollViewClient.h new file mode 100644 index 0000000..4b32a43 --- /dev/null +++ b/WebCore/platform/chromium/FramelessScrollViewClient.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2008, 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 FramelessScrollViewClient_h +#define FramelessScrollViewClient_h + +#include "HostWindow.h" + +namespace WebCore { + + class FramelessScrollViewClient : public HostWindow { + public: + virtual void popupClosed(FramelessScrollView* popup_view) = 0; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/chromium/KeyCodeConversion.h b/WebCore/platform/chromium/KeyCodeConversion.h new file mode 100644 index 0000000..8bd0b46 --- /dev/null +++ b/WebCore/platform/chromium/KeyCodeConversion.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008, 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 KeyCodeConversion_h +#define KeyCodeConversion_h + +namespace WebCore { + + int windowsKeyCodeForKeyEvent(unsigned keycode); + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/chromium/KeyCodeConversionGtk.cpp b/WebCore/platform/chromium/KeyCodeConversionGtk.cpp new file mode 100644 index 0000000..a3efe44 --- /dev/null +++ b/WebCore/platform/chromium/KeyCodeConversionGtk.cpp @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2008 Collabora, Ltd. All rights reserved. + * Copyright (C) 2008, 2009 Google 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. + */ + +// windowsKeyCodeForKeyEvent is copied from platform/gtk/KeyEventGtk.cpp + +#include "config.h" +#include "KeyCodeConversion.h" + +#include "KeyboardCodes.h" + +#include <gdk/gdkkeysyms.h> + +namespace WebCore { + +int windowsKeyCodeForKeyEvent(unsigned keycode) +{ + switch (keycode) { + case GDK_KP_0: + return VKEY_NUMPAD0; // (60) Numeric keypad 0 key + case GDK_KP_1: + return VKEY_NUMPAD1; // (61) Numeric keypad 1 key + case GDK_KP_2: + return VKEY_NUMPAD2; // (62) Numeric keypad 2 key + case GDK_KP_3: + return VKEY_NUMPAD3; // (63) Numeric keypad 3 key + case GDK_KP_4: + return VKEY_NUMPAD4; // (64) Numeric keypad 4 key + case GDK_KP_5: + return VKEY_NUMPAD5; //(65) Numeric keypad 5 key + case GDK_KP_6: + return VKEY_NUMPAD6; // (66) Numeric keypad 6 key + case GDK_KP_7: + return VKEY_NUMPAD7; // (67) Numeric keypad 7 key + case GDK_KP_8: + return VKEY_NUMPAD8; // (68) Numeric keypad 8 key + case GDK_KP_9: + return VKEY_NUMPAD9; // (69) Numeric keypad 9 key + case GDK_KP_Multiply: + return VKEY_MULTIPLY; // (6A) Multiply key + case GDK_KP_Add: + return VKEY_ADD; // (6B) Add key + case GDK_KP_Subtract: + return VKEY_SUBTRACT; // (6D) Subtract key + case GDK_KP_Decimal: + return VKEY_DECIMAL; // (6E) Decimal key + case GDK_KP_Divide: + return VKEY_DIVIDE; // (6F) Divide key + + case GDK_BackSpace: + return VKEY_BACK; // (08) BACKSPACE key + case GDK_ISO_Left_Tab: + case GDK_3270_BackTab: + case GDK_Tab: + return VKEY_TAB; // (09) TAB key + case GDK_Clear: + return VKEY_CLEAR; // (0C) CLEAR key + case GDK_ISO_Enter: + case GDK_KP_Enter: + case GDK_Return: + return VKEY_RETURN; //(0D) Return key + case GDK_Shift_L: + case GDK_Shift_R: + return VKEY_SHIFT; // (10) SHIFT key + case GDK_Control_L: + case GDK_Control_R: + return VKEY_CONTROL; // (11) CTRL key + case GDK_Menu: + case GDK_Alt_L: + case GDK_Alt_R: + return VKEY_MENU; // (12) ALT key + + case GDK_Pause: + return VKEY_PAUSE; // (13) PAUSE key + case GDK_Caps_Lock: + return VKEY_CAPITAL; // (14) CAPS LOCK key + case GDK_Kana_Lock: + case GDK_Kana_Shift: + return VKEY_KANA; // (15) Input Method Editor (IME) Kana mode + case GDK_Hangul: + return VKEY_HANGUL; // VKEY_HANGUL (15) IME Hangul mode + // VKEY_JUNJA (17) IME Junja mode + // VKEY_FINAL (18) IME final mode + case GDK_Hangul_Hanja: + return VKEY_HANJA; // (19) IME Hanja mode + case GDK_Kanji: + return VKEY_KANJI; // (19) IME Kanji mode + case GDK_Escape: + return VKEY_ESCAPE; // (1B) ESC key + // VKEY_CONVERT (1C) IME convert + // VKEY_NONCONVERT (1D) IME nonconvert + // VKEY_ACCEPT (1E) IME accept + // VKEY_MODECHANGE (1F) IME mode change request + case GDK_space: + return VKEY_SPACE; // (20) SPACEBAR + case GDK_Page_Up: + return VKEY_PRIOR; // (21) PAGE UP key + case GDK_Page_Down: + return VKEY_NEXT; // (22) PAGE DOWN key + case GDK_End: + return VKEY_END; // (23) END key + case GDK_Home: + return VKEY_HOME; // (24) HOME key + case GDK_Left: + return VKEY_LEFT; // (25) LEFT ARROW key + case GDK_Up: + return VKEY_UP; // (26) UP ARROW key + case GDK_Right: + return VKEY_RIGHT; // (27) RIGHT ARROW key + case GDK_Down: + return VKEY_DOWN; // (28) DOWN ARROW key + case GDK_Select: + return VKEY_SELECT; // (29) SELECT key + case GDK_Print: + return VKEY_PRINT; // (2A) PRINT key + case GDK_Execute: + return VKEY_EXECUTE;// (2B) EXECUTE key + //dunno on this + //case GDK_PrintScreen: + // return VKEY_SNAPSHOT; // (2C) PRINT SCREEN key + case GDK_Insert: + return VKEY_INSERT; // (2D) INS key + case GDK_Delete: + return VKEY_DELETE; // (2E) DEL key + case GDK_Help: + return VKEY_HELP; // (2F) HELP key + case GDK_0: + case GDK_parenleft: + return VKEY_0; // (30) 0) key + case GDK_1: + return VKEY_1; // (31) 1 ! key + case GDK_2: + case GDK_at: + return VKEY_2; // (32) 2 & key + case GDK_3: + case GDK_numbersign: + return VKEY_3; //case '3': case '#'; + case GDK_4: + case GDK_dollar: // (34) 4 key '$'; + return VKEY_4; + case GDK_5: + case GDK_percent: + return VKEY_5; // (35) 5 key '%' + case GDK_6: + case GDK_asciicircum: + return VKEY_6; // (36) 6 key '^' + case GDK_7: + case GDK_ampersand: + return VKEY_7; // (37) 7 key case '&' + case GDK_8: + case GDK_asterisk: + return VKEY_8; // (38) 8 key '*' + case GDK_9: + case GDK_parenright: + return VKEY_9; // (39) 9 key '(' + case GDK_a: + case GDK_A: + return VKEY_A; // (41) A key case 'a': case 'A': return 0x41; + case GDK_b: + case GDK_B: + return VKEY_B; // (42) B key case 'b': case 'B': return 0x42; + case GDK_c: + case GDK_C: + return VKEY_C; // (43) C key case 'c': case 'C': return 0x43; + case GDK_d: + case GDK_D: + return VKEY_D; // (44) D key case 'd': case 'D': return 0x44; + case GDK_e: + case GDK_E: + return VKEY_E; // (45) E key case 'e': case 'E': return 0x45; + case GDK_f: + case GDK_F: + return VKEY_F; // (46) F key case 'f': case 'F': return 0x46; + case GDK_g: + case GDK_G: + return VKEY_G; // (47) G key case 'g': case 'G': return 0x47; + case GDK_h: + case GDK_H: + return VKEY_H; // (48) H key case 'h': case 'H': return 0x48; + case GDK_i: + case GDK_I: + return VKEY_I; // (49) I key case 'i': case 'I': return 0x49; + case GDK_j: + case GDK_J: + return VKEY_J; // (4A) J key case 'j': case 'J': return 0x4A; + case GDK_k: + case GDK_K: + return VKEY_K; // (4B) K key case 'k': case 'K': return 0x4B; + case GDK_l: + case GDK_L: + return VKEY_L; // (4C) L key case 'l': case 'L': return 0x4C; + case GDK_m: + case GDK_M: + return VKEY_M; // (4D) M key case 'm': case 'M': return 0x4D; + case GDK_n: + case GDK_N: + return VKEY_N; // (4E) N key case 'n': case 'N': return 0x4E; + case GDK_o: + case GDK_O: + return VKEY_O; // (4F) O key case 'o': case 'O': return 0x4F; + case GDK_p: + case GDK_P: + return VKEY_P; // (50) P key case 'p': case 'P': return 0x50; + case GDK_q: + case GDK_Q: + return VKEY_Q; // (51) Q key case 'q': case 'Q': return 0x51; + case GDK_r: + case GDK_R: + return VKEY_R; // (52) R key case 'r': case 'R': return 0x52; + case GDK_s: + case GDK_S: + return VKEY_S; // (53) S key case 's': case 'S': return 0x53; + case GDK_t: + case GDK_T: + return VKEY_T; // (54) T key case 't': case 'T': return 0x54; + case GDK_u: + case GDK_U: + return VKEY_U; // (55) U key case 'u': case 'U': return 0x55; + case GDK_v: + case GDK_V: + return VKEY_V; // (56) V key case 'v': case 'V': return 0x56; + case GDK_w: + case GDK_W: + return VKEY_W; // (57) W key case 'w': case 'W': return 0x57; + case GDK_x: + case GDK_X: + return VKEY_X; // (58) X key case 'x': case 'X': return 0x58; + case GDK_y: + case GDK_Y: + return VKEY_Y; // (59) Y key case 'y': case 'Y': return 0x59; + case GDK_z: + case GDK_Z: + return VKEY_Z; // (5A) Z key case 'z': case 'Z': return 0x5A; + case GDK_Meta_L: + return VKEY_LWIN; // (5B) Left Windows key (Microsoft Natural keyboard) + case GDK_Meta_R: + return VKEY_RWIN; // (5C) Right Windows key (Natural keyboard) + // VKEY_APPS (5D) Applications key (Natural keyboard) + // VKEY_SLEEP (5F) Computer Sleep key + // VKEY_SEPARATOR (6C) Separator key + // VKEY_SUBTRACT (6D) Subtract key + // VKEY_DECIMAL (6E) Decimal key + // VKEY_DIVIDE (6F) Divide key + // handled by key code above + + case GDK_Num_Lock: + return VKEY_NUMLOCK; // (90) NUM LOCK key + + case GDK_Scroll_Lock: + return VKEY_SCROLL; // (91) SCROLL LOCK key + + // VKEY_LSHIFT (A0) Left SHIFT key + // VKEY_RSHIFT (A1) Right SHIFT key + // VKEY_LCONTROL (A2) Left CONTROL key + // VKEY_RCONTROL (A3) Right CONTROL key + // VKEY_LMENU (A4) Left MENU key + // VKEY_RMENU (A5) Right MENU key + // VKEY_BROWSER_BACK (A6) Windows 2000/XP: Browser Back key + // VKEY_BROWSER_FORWARD (A7) Windows 2000/XP: Browser Forward key + // VKEY_BROWSER_REFRESH (A8) Windows 2000/XP: Browser Refresh key + // VKEY_BROWSER_STOP (A9) Windows 2000/XP: Browser Stop key + // VKEY_BROWSER_SEARCH (AA) Windows 2000/XP: Browser Search key + // VKEY_BROWSER_FAVORITES (AB) Windows 2000/XP: Browser Favorites key + // VKEY_BROWSER_HOME (AC) Windows 2000/XP: Browser Start and Home key + // VKEY_VOLUME_MUTE (AD) Windows 2000/XP: Volume Mute key + // VKEY_VOLUME_DOWN (AE) Windows 2000/XP: Volume Down key + // VKEY_VOLUME_UP (AF) Windows 2000/XP: Volume Up key + // VKEY_MEDIA_NEXT_TRACK (B0) Windows 2000/XP: Next Track key + // VKEY_MEDIA_PREV_TRACK (B1) Windows 2000/XP: Previous Track key + // VKEY_MEDIA_STOP (B2) Windows 2000/XP: Stop Media key + // VKEY_MEDIA_PLAY_PAUSE (B3) Windows 2000/XP: Play/Pause Media key + // VKEY_LAUNCH_MAIL (B4) Windows 2000/XP: Start Mail key + // VKEY_LAUNCH_MEDIA_SELECT (B5) Windows 2000/XP: Select Media key + // VKEY_LAUNCH_APP1 (B6) Windows 2000/XP: Start Application 1 key + // VKEY_LAUNCH_APP2 (B7) Windows 2000/XP: Start Application 2 key + + // VKEY_OEM_1 (BA) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ';:' key + case GDK_semicolon: + case GDK_colon: + return VKEY_OEM_1; //case ';': case ':': return 0xBA; + // VKEY_OEM_PLUS (BB) Windows 2000/XP: For any country/region, the '+' key + case GDK_plus: + case GDK_equal: + return VKEY_OEM_PLUS; //case '=': case '+': return 0xBB; + // VKEY_OEM_COMMA (BC) Windows 2000/XP: For any country/region, the ',' key + case GDK_comma: + case GDK_less: + return VKEY_OEM_COMMA; //case ',': case '<': return 0xBC; + // VKEY_OEM_MINUS (BD) Windows 2000/XP: For any country/region, the '-' key + case GDK_minus: + case GDK_underscore: + return VKEY_OEM_MINUS; //case '-': case '_': return 0xBD; + // VKEY_OEM_PERIOD (BE) Windows 2000/XP: For any country/region, the '.' key + case GDK_period: + case GDK_greater: + return VKEY_OEM_PERIOD; //case '.': case '>': return 0xBE; + // VKEY_OEM_2 (BF) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '/?' key + case GDK_slash: + case GDK_question: + return VKEY_OEM_2; //case '/': case '?': return 0xBF; + // VKEY_OEM_3 (C0) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '`~' key + case GDK_asciitilde: + case GDK_quoteleft: + return VKEY_OEM_3; //case '`': case '~': return 0xC0; + // VKEY_OEM_4 (DB) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '[{' key + case GDK_bracketleft: + case GDK_braceleft: + return VKEY_OEM_4; //case '[': case '{': return 0xDB; + // VKEY_OEM_5 (DC) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '\|' key + case GDK_backslash: + case GDK_bar: + return VKEY_OEM_5; //case '\\': case '|': return 0xDC; + // VKEY_OEM_6 (DD) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ']}' key + case GDK_bracketright: + case GDK_braceright: + return VKEY_OEM_6; // case ']': case '}': return 0xDD; + // VKEY_OEM_7 (DE) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key + case GDK_quoteright: + case GDK_quotedbl: + return VKEY_OEM_7; // case '\'': case '"': return 0xDE; + // VKEY_OEM_8 (DF) Used for miscellaneous characters; it can vary by keyboard. + // VKEY_OEM_102 (E2) Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard + // VKEY_PROCESSKEY (E5) Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCESS key + // VKEY_PACKET (E7) Windows 2000/XP: Used to pass Unicode characters as if they were keystrokes. The VKEY_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT,SendInput, WM_KEYDOWN, and WM_KEYUP + // VKEY_ATTN (F6) Attn key + // VKEY_CRSEL (F7) CrSel key + // VKEY_EXSEL (F8) ExSel key + // VKEY_EREOF (F9) Erase EOF key + // VKEY_PLAY (FA) Play key + // VKEY_ZOOM (FB) Zoom key + // VKEY_NONAME (FC) Reserved for future use + // VKEY_PA1 (FD) PA1 key + // VKEY_OEM_CLEAR (FE) Clear key + default: + return 0; + } +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/KeyboardCodes.h b/WebCore/platform/chromium/KeyboardCodes.h new file mode 100644 index 0000000..10eb0cd --- /dev/null +++ b/WebCore/platform/chromium/KeyboardCodes.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008, 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 KeyboardCodes_h +#define KeyboardCodes_h + +#if PLATFORM(WIN_OS) +#include "KeyboardCodesWin.h" +#else +#include "KeyboardCodesPosix.h" +#endif + +#endif diff --git a/WebCore/platform/chromium/KeyboardCodesPosix.h b/WebCore/platform/chromium/KeyboardCodesPosix.h new file mode 100644 index 0000000..1dfe77e --- /dev/null +++ b/WebCore/platform/chromium/KeyboardCodesPosix.h @@ -0,0 +1,545 @@ +/* + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com. All rights reserved. + * Copyright (C) 2008, 2009 Google 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. + */ + +#ifndef KeyboardCodesPosix_h +#define KeyboardCodesPosix_h + +namespace WebCore { + + enum { + // VKEY_LBUTTON (01) Left mouse button + // VKEY_RBUTTON (02) Right mouse button + // VKEY_CANCEL (03) Control-break processing + // VKEY_MBUTTON (04) Middle mouse button (three-button mouse) + // VKEY_XBUTTON1 (05) + // VKEY_XBUTTON2 (06) + + // VKEY_BACK (08) BACKSPACE key + VKEY_BACK = 0x08, + + // VKEY_TAB (09) TAB key + VKEY_TAB = 0x09, + + // VKEY_CLEAR (0C) CLEAR key + VKEY_CLEAR = 0x0C, + + // VKEY_RETURN (0D) + VKEY_RETURN = 0x0D, + + // VKEY_SHIFT (10) SHIFT key + VKEY_SHIFT = 0x10, + + // VKEY_CONTROL (11) CTRL key + VKEY_CONTROL = 0x11, + + // VKEY_MENU (12) ALT key + VKEY_MENU = 0x12, + + // VKEY_PAUSE (13) PAUSE key + VKEY_PAUSE = 0x13, + + // VKEY_CAPITAL (14) CAPS LOCK key + VKEY_CAPITAL = 0x14, + + // VKEY_KANA (15) Input Method Editor (IME) Kana mode + VKEY_KANA = 0x15, + + // VKEY_HANGUEL (15) IME Hanguel mode (maintained for compatibility, use VKEY_HANGUL) + // VKEY_HANGUL (15) IME Hangul mode + VKEY_HANGUL = 0x15, + + // VKEY_JUNJA (17) IME Junja mode + VKEY_JUNJA = 0x17, + + // VKEY_FINAL (18) IME final mode + VKEY_FINAL = 0x18, + + // VKEY_HANJA (19) IME Hanja mode + VKEY_HANJA = 0x19, + + // VKEY_KANJI (19) IME Kanji mode + VKEY_KANJI = 0x19, + + // VKEY_ESCAPE (1B) ESC key + VKEY_ESCAPE = 0x1B, + + // VKEY_CONVERT (1C) IME convert + VKEY_CONVERT = 0x1C, + + // VKEY_NONCONVERT (1D) IME nonconvert + VKEY_NONCONVERT = 0x1D, + + // VKEY_ACCEPT (1E) IME accept + VKEY_ACCEPT = 0x1E, + + // VKEY_MODECHANGE (1F) IME mode change request + VKEY_MODECHANGE = 0x1F, + + // VKEY_SPACE (20) SPACEBAR + VKEY_SPACE = 0x20, + + // VKEY_PRIOR (21) PAGE UP key + VKEY_PRIOR = 0x21, + + // VKEY_NEXT (22) PAGE DOWN key + VKEY_NEXT = 0x22, + + // VKEY_END (23) END key + VKEY_END = 0x23, + + // VKEY_HOME (24) HOME key + VKEY_HOME = 0x24, + + // VKEY_LEFT (25) LEFT ARROW key + VKEY_LEFT = 0x25, + + // VKEY_UP (26) UP ARROW key + VKEY_UP = 0x26, + + // VKEY_RIGHT (27) RIGHT ARROW key + VKEY_RIGHT = 0x27, + + // VKEY_DOWN (28) DOWN ARROW key + VKEY_DOWN = 0x28, + + // VKEY_SELECT (29) SELECT key + VKEY_SELECT = 0x29, + + // VKEY_PRINT (2A) PRINT key + VKEY_PRINT = 0x2A, + + // VKEY_EXECUTE (2B) EXECUTE key + VKEY_EXECUTE = 0x2B, + + // VKEY_SNAPSHOT (2C) PRINT SCREEN key + VKEY_SNAPSHOT = 0x2C, + + // VKEY_INSERT (2D) INS key + VKEY_INSERT = 0x2D, + + // VKEY_DELETE (2E) DEL key + VKEY_DELETE = 0x2E, + + // VKEY_HELP (2F) HELP key + VKEY_HELP = 0x2F, + + // (30) 0 key + VKEY_0 = 0x30, + + // (31) 1 key + VKEY_1 = 0x31, + + // (32) 2 key + VKEY_2 = 0x32, + + // (33) 3 key + VKEY_3 = 0x33, + + // (34) 4 key + VKEY_4 = 0x34, + + // (35) 5 key, + + VKEY_5 = 0x35, + + // (36) 6 key + VKEY_6 = 0x36, + + // (37) 7 key + VKEY_7 = 0x37, + + // (38) 8 key + VKEY_8 = 0x38, + + // (39) 9 key + VKEY_9 = 0x39, + + // (41) A key + VKEY_A = 0x41, + + // (42) B key + VKEY_B = 0x42, + + // (43) C key + VKEY_C = 0x43, + + // (44) D key + VKEY_D = 0x44, + + // (45) E key + VKEY_E = 0x45, + + // (46) F key + VKEY_F = 0x46, + + // (47) G key + VKEY_G = 0x47, + + // (48) H key + VKEY_H = 0x48, + + // (49) I key + VKEY_I = 0x49, + + // (4A) J key + VKEY_J = 0x4A, + + // (4B) K key + VKEY_K = 0x4B, + + // (4C) L key + VKEY_L = 0x4C, + + // (4D) M key + VKEY_M = 0x4D, + + // (4E) N key + VKEY_N = 0x4E, + + // (4F) O key + VKEY_O = 0x4F, + + // (50) P key + VKEY_P = 0x50, + + // (51) Q key + VKEY_Q = 0x51, + + // (52) R key + VKEY_R = 0x52, + + // (53) S key + VKEY_S = 0x53, + + // (54) T key + VKEY_T = 0x54, + + // (55) U key + VKEY_U = 0x55, + + // (56) V key + VKEY_V = 0x56, + + // (57) W key + VKEY_W = 0x57, + + // (58) X key + VKEY_X = 0x58, + + // (59) Y key + VKEY_Y = 0x59, + + // (5A) Z key + VKEY_Z = 0x5A, + + // VKEY_LWIN (5B) Left Windows key (Microsoft Natural keyboard) + VKEY_LWIN = 0x5B, + + // VKEY_RWIN (5C) Right Windows key (Natural keyboard) + VKEY_RWIN = 0x5C, + + // VKEY_APPS (5D) Applications key (Natural keyboard) + VKEY_APPS = 0x5D, + + // VKEY_SLEEP (5F) Computer Sleep key + VKEY_SLEEP = 0x5F, + + // VKEY_NUMPAD0 (60) Numeric keypad 0 key + VKEY_NUMPAD0 = 0x60, + + // VKEY_NUMPAD1 (61) Numeric keypad 1 key + VKEY_NUMPAD1 = 0x61, + + // VKEY_NUMPAD2 (62) Numeric keypad 2 key + VKEY_NUMPAD2 = 0x62, + + // VKEY_NUMPAD3 (63) Numeric keypad 3 key + VKEY_NUMPAD3 = 0x63, + + // VKEY_NUMPAD4 (64) Numeric keypad 4 key + VKEY_NUMPAD4 = 0x64, + + // VKEY_NUMPAD5 (65) Numeric keypad 5 key + VKEY_NUMPAD5 = 0x65, + + // VKEY_NUMPAD6 (66) Numeric keypad 6 key + VKEY_NUMPAD6 = 0x66, + + // VKEY_NUMPAD7 (67) Numeric keypad 7 key + VKEY_NUMPAD7 = 0x67, + + // VKEY_NUMPAD8 (68) Numeric keypad 8 key + VKEY_NUMPAD8 = 0x68, + + // VKEY_NUMPAD9 (69) Numeric keypad 9 key + VKEY_NUMPAD9 = 0x69, + + // VKEY_MULTIPLY (6A) Multiply key + VKEY_MULTIPLY = 0x6A, + + // VKEY_ADD (6B) Add key + VKEY_ADD = 0x6B, + + // VKEY_SEPARATOR (6C) Separator key + VKEY_SEPARATOR = 0x6C, + + // VKEY_SUBTRACT (6D) Subtract key + VKEY_SUBTRACT = 0x6D, + + // VKEY_DECIMAL (6E) Decimal key + VKEY_DECIMAL = 0x6E, + + // VKEY_DIVIDE (6F) Divide key + VKEY_DIVIDE = 0x6F, + + // VKEY_F1 (70) F1 key + VKEY_F1 = 0x70, + + // VKEY_F2 (71) F2 key + VKEY_F2 = 0x71, + + // VKEY_F3 (72) F3 key + VKEY_F3 = 0x72, + + // VKEY_F4 (73) F4 key + VKEY_F4 = 0x73, + + // VKEY_F5 (74) F5 key + VKEY_F5 = 0x74, + + // VKEY_F6 (75) F6 key + VKEY_F6 = 0x75, + + // VKEY_F7 (76) F7 key + VKEY_F7 = 0x76, + + // VKEY_F8 (77) F8 key + VKEY_F8 = 0x77, + + // VKEY_F9 (78) F9 key + VKEY_F9 = 0x78, + + // VKEY_F10 (79) F10 key + VKEY_F10 = 0x79, + + // VKEY_F11 (7A) F11 key + VKEY_F11 = 0x7A, + + // VKEY_F12 (7B) F12 key + VKEY_F12 = 0x7B, + + // VKEY_F13 (7C) F13 key + VKEY_F13 = 0x7C, + + // VKEY_F14 (7D) F14 key + VKEY_F14 = 0x7D, + + // VKEY_F15 (7E) F15 key + VKEY_F15 = 0x7E, + + // VKEY_F16 (7F) F16 key + VKEY_F16 = 0x7F, + + // VKEY_F17 (80H) F17 key + VKEY_F17 = 0x80, + + // VKEY_F18 (81H) F18 key + VKEY_F18 = 0x81, + + // VKEY_F19 (82H) F19 key + VKEY_F19 = 0x82, + + // VKEY_F20 (83H) F20 key + VKEY_F20 = 0x83, + + // VKEY_F21 (84H) F21 key + VKEY_F21 = 0x84, + + // VKEY_F22 (85H) F22 key + VKEY_F22 = 0x85, + + // VKEY_F23 (86H) F23 key + VKEY_F23 = 0x86, + + // VKEY_F24 (87H) F24 key + VKEY_F24 = 0x87, + + // VKEY_NUMLOCK (90) NUM LOCK key + VKEY_NUMLOCK = 0x90, + + // VKEY_SCROLL (91) SCROLL LOCK key + VKEY_SCROLL = 0x91, + + // VKEY_LSHIFT (A0) Left SHIFT key + VKEY_LSHIFT = 0xA0, + + // VKEY_RSHIFT (A1) Right SHIFT key + VKEY_RSHIFT = 0xA1, + + // VKEY_LCONTROL (A2) Left CONTROL key + VKEY_LCONTROL = 0xA2, + + // VKEY_RCONTROL (A3) Right CONTROL key + VKEY_RCONTROL = 0xA3, + + // VKEY_LMENU (A4) Left MENU key + VKEY_LMENU = 0xA4, + + // VKEY_RMENU (A5) Right MENU key + VKEY_RMENU = 0xA5, + + // VKEY_BROWSER_BACK (A6) Windows 2000/XP: Browser Back key + VKEY_BROWSER_BACK = 0xA6, + + // VKEY_BROWSER_FORWARD (A7) Windows 2000/XP: Browser Forward key + VKEY_BROWSER_FORWARD = 0xA7, + + // VKEY_BROWSER_REFRESH (A8) Windows 2000/XP: Browser Refresh key + VKEY_BROWSER_REFRESH = 0xA8, + + // VKEY_BROWSER_STOP (A9) Windows 2000/XP: Browser Stop key + VKEY_BROWSER_STOP = 0xA9, + + // VKEY_BROWSER_SEARCH (AA) Windows 2000/XP: Browser Search key + VKEY_BROWSER_SEARCH = 0xAA, + + // VKEY_BROWSER_FAVORITES (AB) Windows 2000/XP: Browser Favorites key + VKEY_BROWSER_FAVORITES = 0xAB, + + // VKEY_BROWSER_HOME (AC) Windows 2000/XP: Browser Start and Home key + VKEY_BROWSER_HOME = 0xAC, + + // VKEY_VOLUME_MUTE (AD) Windows 2000/XP: Volume Mute key + VKEY_VOLUME_MUTE = 0xAD, + + // VKEY_VOLUME_DOWN (AE) Windows 2000/XP: Volume Down key + VKEY_VOLUME_DOWN = 0xAE, + + // VKEY_VOLUME_UP (AF) Windows 2000/XP: Volume Up key + VKEY_VOLUME_UP = 0xAF, + + // VKEY_MEDIA_NEXT_TRACK (B0) Windows 2000/XP: Next Track key + VKEY_MEDIA_NEXT_TRACK = 0xB0, + + // VKEY_MEDIA_PREV_TRACK (B1) Windows 2000/XP: Previous Track key + VKEY_MEDIA_PREV_TRACK = 0xB1, + + // VKEY_MEDIA_STOP (B2) Windows 2000/XP: Stop Media key + VKEY_MEDIA_STOP = 0xB2, + + // VKEY_MEDIA_PLAY_PAUSE (B3) Windows 2000/XP: Play/Pause Media key + VKEY_MEDIA_PLAY_PAUSE = 0xB3, + + // VKEY_LAUNCH_MAIL (B4) Windows 2000/XP: Start Mail key + VKEY_MEDIA_LAUNCH_MAIL = 0xB4, + + // VKEY_LAUNCH_MEDIA_SELECT (B5) Windows 2000/XP: Select Media key + VKEY_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5, + + // VKEY_LAUNCH_APP1 (B6) Windows 2000/XP: Start Application 1 key + VKEY_MEDIA_LAUNCH_APP1 = 0xB6, + + // VKEY_LAUNCH_APP2 (B7) Windows 2000/XP: Start Application 2 key + VKEY_MEDIA_LAUNCH_APP2 = 0xB7, + + // VKEY_OEM_1 (BA) Used for miscellaneous characters, it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ',:' key + VKEY_OEM_1 = 0xBA, + + // VKEY_OEM_PLUS (BB) Windows 2000/XP: For any country/region, the '+' key + VKEY_OEM_PLUS = 0xBB, + + // VKEY_OEM_COMMA (BC) Windows 2000/XP: For any country/region, the ',' key + VKEY_OEM_COMMA = 0xBC, + + // VKEY_OEM_MINUS (BD) Windows 2000/XP: For any country/region, the '-' key + VKEY_OEM_MINUS = 0xBD, + + // VKEY_OEM_PERIOD (BE) Windows 2000/XP: For any country/region, the '.' key + VKEY_OEM_PERIOD = 0xBE, + + // VKEY_OEM_2 (BF) Used for miscellaneous characters, it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '/?' key + VKEY_OEM_2 = 0xBF, + + // VKEY_OEM_3 (C0) Used for miscellaneous characters, it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '`~' key + VKEY_OEM_3 = 0xC0, + + // VKEY_OEM_4 (DB) Used for miscellaneous characters, it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '[{' key + VKEY_OEM_4 = 0xDB, + + // VKEY_OEM_5 (DC) Used for miscellaneous characters, it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '\|' key + VKEY_OEM_5 = 0xDC, + + // VKEY_OEM_6 (DD) Used for miscellaneous characters, it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ']}' key + VKEY_OEM_6 = 0xDD, + + // VKEY_OEM_7 (DE) Used for miscellaneous characters, it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key + VKEY_OEM_7 = 0xDE, + + // VKEY_OEM_8 (DF) Used for miscellaneous characters, it can vary by keyboard. + VKEY_OEM_8 = 0xDF, + + // VKEY_OEM_102 (E2) Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard + VKEY_OEM_102 = 0xE2, + + // VKEY_PROCESSKEY (E5) Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCESS key + VKEY_PROCESSKEY = 0xE5, + + // VKEY_PACKET (E7) Windows 2000/XP: Used to pass Unicode characters as if they were keystrokes. The VKEY_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT,SendInput, WM_KEYDOWN, and WM_KEYUP + VKEY_PACKET = 0xE7, + + // VKEY_ATTN (F6) Attn key + VKEY_ATTN = 0xF6, + + // VKEY_CRSEL (F7) CrSel key + VKEY_CRSEL = 0xF7, + + // VKEY_EXSEL (F8) ExSel key + VKEY_EXSEL = 0xF8, + + // VKEY_EREOF (F9) Erase EOF key + VKEY_EREOF = 0xF9, + + // VKEY_PLAY (FA) Play key + VKEY_PLAY = 0xFA, + + // VKEY_ZOOM (FB) Zoom key + VKEY_ZOOM = 0xFB, + + // VKEY_NONAME (FC) Reserved for future use + VKEY_NONAME = 0xFC, + + // VKEY_PA1 (FD) PA1 key + VKEY_PA1 = 0xFD, + + // VKEY_OEM_CLEAR (FE) Clear key + VKEY_OEM_CLEAR = 0xFE, + + VKEY_UNKNOWN = 0 + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/chromium/KeyboardCodesWin.h b/WebCore/platform/chromium/KeyboardCodesWin.h new file mode 100644 index 0000000..bccd017 --- /dev/null +++ b/WebCore/platform/chromium/KeyboardCodesWin.h @@ -0,0 +1,551 @@ +/* + * Copyright (c) 2008, 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 KeyboardCodesWin_h +#define KeyboardCodesWin_h + +#include <windows.h> + +namespace WebCore { + + enum { + // VKEY_LBUTTON (01) Left mouse button + // VKEY_RBUTTON (02) Right mouse button + // VKEY_CANCEL (03) Control-break processing + // VKEY_MBUTTON (04) Middle mouse button (three-button mouse) + // VKEY_XBUTTON1 (05) + // VKEY_XBUTTON2 (06) + + // VKEY_BACK (08) BACKSPACE key + VKEY_BACK = VK_BACK, + + // VKEY_TAB (09) TAB key + VKEY_TAB = VK_TAB, + + // VKEY_CLEAR (0C) CLEAR key + VKEY_CLEAR = VK_CLEAR, + + // VKEY_RETURN (0D) + VKEY_RETURN = VK_RETURN, + + // VKEY_SHIFT (10) SHIFT key + VKEY_SHIFT = VK_SHIFT, + + // VKEY_CONTROL (11) CTRL key + VKEY_CONTROL = VK_CONTROL, + + // VKEY_MENU (12) ALT key + VKEY_MENU = VK_MENU, + + // VKEY_PAUSE (13) PAUSE key + VKEY_PAUSE = VK_PAUSE, + + // VKEY_CAPITAL (14) CAPS LOCK key + VKEY_CAPITAL = VK_CAPITAL, + + // VKEY_KANA (15) Input Method Editor (IME) Kana mode + VKEY_KANA = VK_KANA, + + // VKEY_HANGUEL (15) IME Hanguel mode (maintained for compatibility, use VKEY_HANGUL) + // VKEY_HANGUL (15) IME Hangul mode + VKEY_HANGUL = VK_HANGUL, + + // VKEY_JUNJA (17) IME Junja mode + VKEY_JUNJA = VK_JUNJA, + + // VKEY_FINAL (18) IME final mode + VKEY_FINAL = VK_FINAL, + + // VKEY_HANJA (19) IME Hanja mode + VKEY_HANJA = VK_HANJA, + + // VKEY_KANJI (19) IME Kanji mode + VKEY_KANJI = VK_KANJI, + + // VKEY_ESCAPE (1B) ESC key + VKEY_ESCAPE = VK_ESCAPE, + + // VKEY_CONVERT (1C) IME convert + VKEY_CONVERT = VK_CONVERT, + + // VKEY_NONCONVERT (1D) IME nonconvert + VKEY_NONCONVERT = VK_NONCONVERT, + + // VKEY_ACCEPT (1E) IME accept + VKEY_ACCEPT = VK_ACCEPT, + + // VKEY_MODECHANGE (1F) IME mode change request + VKEY_MODECHANGE = VK_MODECHANGE, + + // VKEY_SPACE (20) SPACEBAR + VKEY_SPACE = VK_SPACE, + + // VKEY_PRIOR (21) PAGE UP key + VKEY_PRIOR = VK_PRIOR, + + // VKEY_NEXT (22) PAGE DOWN key + VKEY_NEXT = VK_NEXT, + + // VKEY_END (23) END key + VKEY_END = VK_END, + + // VKEY_HOME (24) HOME key + VKEY_HOME = VK_HOME, + + // VKEY_LEFT (25) LEFT ARROW key + VKEY_LEFT = VK_LEFT, + + // VKEY_UP (26) UP ARROW key + VKEY_UP = VK_UP, + + // VKEY_RIGHT (27) RIGHT ARROW key + VKEY_RIGHT = VK_RIGHT, + + // VKEY_DOWN (28) DOWN ARROW key + VKEY_DOWN = VK_DOWN, + + // VKEY_SELECT (29) SELECT key + VKEY_SELECT = VK_SELECT, + + // VKEY_PRINT (2A) PRINT key + VKEY_PRINT = VK_PRINT, + + // VKEY_EXECUTE (2B) EXECUTE key + VKEY_EXECUTE = VK_EXECUTE, + + // VKEY_SNAPSHOT (2C) PRINT SCREEN key + VKEY_SNAPSHOT = VK_SNAPSHOT, + + // VKEY_INSERT (2D) INS key + VKEY_INSERT = VK_INSERT, + + // VKEY_DELETE (2E) DEL key + VKEY_DELETE = VK_DELETE, + + // VKEY_HELP (2F) HELP key + VKEY_HELP = VK_HELP, + + // (30) 0 key + VKEY_0 = '0', + + // (31) 1 key + VKEY_1 = '1', + + // (32) 2 key + VKEY_2 = '2', + + // (33) 3 key + VKEY_3 = '3', + + // (34) 4 key + VKEY_4 = '4', + + // (35) 5 key, + + VKEY_5 = '5', + + // (36) 6 key + VKEY_6 = '6', + + // (37) 7 key + VKEY_7 = '7', + + // (38) 8 key + VKEY_8 = '8', + + // (39) 9 key + VKEY_9 = '9', + + // (41) A key + VKEY_A = 'A', + + // (42) B key + VKEY_B = 'B', + + // (43) C key + VKEY_C = 'C', + + // (44) D key + VKEY_D = 'D', + + // (45) E key + VKEY_E = 'E', + + // (46) F key + VKEY_F = 'F', + + // (47) G key + VKEY_G = 'G', + + // (48) H key + VKEY_H = 'H', + + // (49) I key + VKEY_I = 'I', + + // (4A) J key + VKEY_J = 'J', + + // (4B) K key + VKEY_K = 'K', + + // (4C) L key + VKEY_L = 'L', + + // (4D) M key + VKEY_M = 'M', + + // (4E) N key + VKEY_N = 'N', + + // (4F) O key + VKEY_O = 'O', + + // (50) P key + VKEY_P = 'P', + + // (51) Q key + VKEY_Q = 'Q', + + // (52) R key + VKEY_R = 'R', + + // (53) S key + VKEY_S = 'S', + + // (54) T key + VKEY_T = 'T', + + // (55) U key + VKEY_U = 'U', + + // (56) V key + VKEY_V = 'V', + + // (57) W key + VKEY_W = 'W', + + // (58) X key + VKEY_X = 'X', + + // (59) Y key + VKEY_Y = 'Y', + + // (5A) Z key + VKEY_Z = 'Z', + + // VKEY_LWIN (5B) Left Windows key (Microsoft Natural keyboard) + VKEY_LWIN = VK_LWIN, + + // VKEY_RWIN (5C) Right Windows key (Natural keyboard) + VKEY_RWIN = VK_RWIN, + + // VKEY_APPS (5D) Applications key (Natural keyboard) + VKEY_APPS = VK_APPS, + + // VKEY_SLEEP (5F) Computer Sleep key + VKEY_SLEEP = VK_SLEEP, + + // VKEY_NUMPAD0 (60) Numeric keypad 0 key + VKEY_NUMPAD0 = VK_NUMPAD0, + + // VKEY_NUMPAD1 (61) Numeric keypad 1 key + VKEY_NUMPAD1 = VK_NUMPAD1, + + // VKEY_NUMPAD2 (62) Numeric keypad 2 key + VKEY_NUMPAD2 = VK_NUMPAD2, + + // VKEY_NUMPAD3 (63) Numeric keypad 3 key + VKEY_NUMPAD3 = VK_NUMPAD3, + + // VKEY_NUMPAD4 (64) Numeric keypad 4 key + VKEY_NUMPAD4 = VK_NUMPAD4, + + // VKEY_NUMPAD5 (65) Numeric keypad 5 key + VKEY_NUMPAD5 = VK_NUMPAD5, + + // VKEY_NUMPAD6 (66) Numeric keypad 6 key + VKEY_NUMPAD6 = VK_NUMPAD6, + + // VKEY_NUMPAD7 (67) Numeric keypad 7 key + VKEY_NUMPAD7 = VK_NUMPAD7, + + // VKEY_NUMPAD8 (68) Numeric keypad 8 key + VKEY_NUMPAD8 = VK_NUMPAD8, + + // VKEY_NUMPAD9 (69) Numeric keypad 9 key + VKEY_NUMPAD9 = VK_NUMPAD9, + + // VKEY_MULTIPLY (6A) Multiply key + VKEY_MULTIPLY = VK_MULTIPLY, + + // VKEY_ADD (6B) Add key + VKEY_ADD = VK_ADD, + + // VKEY_SEPARATOR (6C) Separator key + VKEY_SEPARATOR = VK_SEPARATOR, + + // VKEY_SUBTRACT (6D) Subtract key + VKEY_SUBTRACT = VK_SUBTRACT, + + // VKEY_DECIMAL (6E) Decimal key + VKEY_DECIMAL = VK_DECIMAL, + + // VKEY_DIVIDE (6F) Divide key + VKEY_DIVIDE = VK_DIVIDE, + + // VKEY_F1 (70) F1 key + VKEY_F1 = VK_F1, + + // VKEY_F2 (71) F2 key + VKEY_F2 = VK_F2, + + // VKEY_F3 (72) F3 key + VKEY_F3 = VK_F3, + + // VKEY_F4 (73) F4 key + VKEY_F4 = VK_F4, + + // VKEY_F5 (74) F5 key + VKEY_F5 = VK_F5, + + // VKEY_F6 (75) F6 key + VKEY_F6 = VK_F6, + + // VKEY_F7 (76) F7 key + VKEY_F7 = VK_F7, + + // VKEY_F8 (77) F8 key + VKEY_F8 = VK_F8, + + // VKEY_F9 (78) F9 key + VKEY_F9 = VK_F9, + + // VKEY_F10 (79) F10 key + VKEY_F10 = VK_F10, + + // VKEY_F11 (7A) F11 key + VKEY_F11 = VK_F11, + + // VKEY_F12 (7B) F12 key + VKEY_F12 = VK_F12, + + // VKEY_F13 (7C) F13 key + VKEY_F13 = VK_F13, + + // VKEY_F14 (7D) F14 key + VKEY_F14 = VK_F14, + + // VKEY_F15 (7E) F15 key + VKEY_F15 = VK_F15, + + // VKEY_F16 (7F) F16 key + VKEY_F16 = VK_F16, + + // VKEY_F17 (80H) F17 key + VKEY_F17 = VK_F17, + + // VKEY_F18 (81H) F18 key + VKEY_F18 = VK_F18, + + // VKEY_F19 (82H) F19 key + VKEY_F19 = VK_F19, + + // VKEY_F20 (83H) F20 key + VKEY_F20 = VK_F20, + + // VKEY_F21 (84H) F21 key + VKEY_F21 = VK_F21, + + // VKEY_F22 (85H) F22 key + VKEY_F22 = VK_F22, + + // VKEY_F23 (86H) F23 key + VKEY_F23 = VK_F23, + + // VKEY_F24 (87H) F24 key + VKEY_F24 = VK_F24, + + // VKEY_NUMLOCK (90) NUM LOCK key + VKEY_NUMLOCK = VK_NUMLOCK, + + // VKEY_SCROLL (91) SCROLL LOCK key + VKEY_SCROLL = VK_SCROLL, + + // VKEY_LSHIFT (A0) Left SHIFT key + VKEY_LSHIFT = VK_LSHIFT, + + // VKEY_RSHIFT (A1) Right SHIFT key + VKEY_RSHIFT = VK_RSHIFT, + + // VKEY_LCONTROL (A2) Left CONTROL key + VKEY_LCONTROL = VK_LCONTROL, + + // VKEY_RCONTROL (A3) Right CONTROL key + VKEY_RCONTROL = VK_RCONTROL, + + // VKEY_LMENU (A4) Left MENU key + VKEY_LMENU = VK_LMENU, + + // VKEY_RMENU (A5) Right MENU key + VKEY_RMENU = VK_RMENU, + + // VKEY_BROWSER_BACK (A6) Windows 2000/XP: Browser Back key + VKEY_BROWSER_BACK = VK_BROWSER_BACK, + + // VKEY_BROWSER_FORWARD (A7) Windows 2000/XP: Browser Forward key + VKEY_BROWSER_FORWARD = VK_BROWSER_FORWARD, + + // VKEY_BROWSER_REFRESH (A8) Windows 2000/XP: Browser Refresh key + VKEY_BROWSER_REFRESH = VK_BROWSER_REFRESH, + + // VKEY_BROWSER_STOP (A9) Windows 2000/XP: Browser Stop key + VKEY_BROWSER_STOP = VK_BROWSER_STOP, + + // VKEY_BROWSER_SEARCH (AA) Windows 2000/XP: Browser Search key + VKEY_BROWSER_SEARCH = VK_BROWSER_SEARCH, + + // VKEY_BROWSER_FAVORITES (AB) Windows 2000/XP: Browser Favorites key + VKEY_BROWSER_FAVORITES = VK_BROWSER_FAVORITES, + + // VKEY_BROWSER_HOME (AC) Windows 2000/XP: Browser Start and Home key + VKEY_BROWSER_HOME = VK_BROWSER_HOME, + + // VKEY_VOLUME_MUTE (AD) Windows 2000/XP: Volume Mute key + VKEY_VOLUME_MUTE = VK_VOLUME_MUTE, + + // VKEY_VOLUME_DOWN (AE) Windows 2000/XP: Volume Down key + VKEY_VOLUME_DOWN = VK_VOLUME_DOWN, + + // VKEY_VOLUME_UP (AF) Windows 2000/XP: Volume Up key + VKEY_VOLUME_UP = VK_VOLUME_UP, + + // VKEY_MEDIA_NEXT_TRACK (B0) Windows 2000/XP: Next Track key + VKEY_MEDIA_NEXT_TRACK = VK_MEDIA_NEXT_TRACK, + + // VKEY_MEDIA_PREV_TRACK (B1) Windows 2000/XP: Previous Track key + VKEY_MEDIA_PREV_TRACK = VK_MEDIA_PREV_TRACK, + + // VKEY_MEDIA_STOP (B2) Windows 2000/XP: Stop Media key + VKEY_MEDIA_STOP = VK_MEDIA_STOP, + + // VKEY_MEDIA_PLAY_PAUSE (B3) Windows 2000/XP: Play/Pause Media key + VKEY_MEDIA_PLAY_PAUSE = VK_MEDIA_PLAY_PAUSE, + + // VKEY_LAUNCH_MAIL (B4) Windows 2000/XP: Start Mail key + VKEY_MEDIA_LAUNCH_MAIL = 0xB4, + + // VKEY_LAUNCH_MEDIA_SELECT (B5) Windows 2000/XP: Select Media key + VKEY_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5, + + // VKEY_LAUNCH_APP1 (B6) Windows 2000/XP: Start Application 1 key + VKEY_MEDIA_LAUNCH_APP1 = 0xB6, + + // VKEY_LAUNCH_APP2 (B7) Windows 2000/XP: Start Application 2 key + VKEY_MEDIA_LAUNCH_APP2 = 0xB7, + + // VKEY_OEM_1 (BA) Used for miscellaneous characters, it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ',:' key + VKEY_OEM_1 = VK_OEM_1, + + // VKEY_OEM_PLUS (BB) Windows 2000/XP: For any country/region, the '+' key + VKEY_OEM_PLUS = VK_OEM_PLUS, + + // VKEY_OEM_COMMA (BC) Windows 2000/XP: For any country/region, the ',' key + VKEY_OEM_COMMA = VK_OEM_COMMA, + + // VKEY_OEM_MINUS (BD) Windows 2000/XP: For any country/region, the '-' key + VKEY_OEM_MINUS = VK_OEM_MINUS, + + // VKEY_OEM_PERIOD (BE) Windows 2000/XP: For any country/region, the '.' key + VKEY_OEM_PERIOD = VK_OEM_PERIOD, + + // VKEY_OEM_2 (BF) Used for miscellaneous characters, it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '/?' key + VKEY_OEM_2 = VK_OEM_2, + + // VKEY_OEM_3 (C0) Used for miscellaneous characters, it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '`~' key + VKEY_OEM_3 = VK_OEM_3, + + // VKEY_OEM_4 (DB) Used for miscellaneous characters, it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '[{' key + VKEY_OEM_4 = VK_OEM_4, + + // VKEY_OEM_5 (DC) Used for miscellaneous characters, it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '\|' key + VKEY_OEM_5 = VK_OEM_5, + + // VKEY_OEM_6 (DD) Used for miscellaneous characters, it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ']}' key + VKEY_OEM_6 = VK_OEM_6, + + // VKEY_OEM_7 (DE) Used for miscellaneous characters, it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key + VKEY_OEM_7 = VK_OEM_7, + + // VKEY_OEM_8 (DF) Used for miscellaneous characters, it can vary by keyboard. + VKEY_OEM_8 = VK_OEM_8, + + // VKEY_OEM_102 (E2) Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard + VKEY_OEM_102 = VK_OEM_102, + + // VKEY_PROCESSKEY (E5) Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCESS key + VKEY_PROCESSKEY = VK_PROCESSKEY, + + // VKEY_PACKET (E7) Windows 2000/XP: Used to pass Unicode characters as if they were keystrokes. The VKEY_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT,SendInput, WM_KEYDOWN, and WM_KEYUP + VKEY_PACKET = VK_PACKET, + + // VKEY_ATTN (F6) Attn key + VKEY_ATTN = VK_ATTN, + + // VKEY_CRSEL (F7) CrSel key + VKEY_CRSEL = VK_CRSEL, + + // VKEY_EXSEL (F8) ExSel key + VKEY_EXSEL = VK_EXSEL, + + // VKEY_EREOF (F9) Erase EOF key + VKEY_EREOF = VK_EREOF, + + // VKEY_PLAY (FA) Play key + VKEY_PLAY = VK_PLAY, + + // VKEY_ZOOM (FB) Zoom key + VKEY_ZOOM = VK_ZOOM, + + // VKEY_NONAME (FC) Reserved for future use + VKEY_NONAME = VK_NONAME, + + // VKEY_PA1 (FD) PA1 key + VKEY_PA1 = VK_PA1, + + // VKEY_OEM_CLEAR (FE) Clear key + VKEY_OEM_CLEAR = VK_OEM_CLEAR, + + VKEY_UNKNOWN = 0 + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/chromium/Language.cpp b/WebCore/platform/chromium/Language.cpp new file mode 100644 index 0000000..2612af4 --- /dev/null +++ b/WebCore/platform/chromium/Language.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2008, 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 "Language.h" + +#include "ChromiumBridge.h" +#include "PlatformString.h" + +namespace WebCore { + +String defaultLanguage() +{ + static String computedDefaultLanguage; + if (computedDefaultLanguage.isEmpty()) + computedDefaultLanguage = ChromiumBridge::computedDefaultLanguage(); + return computedDefaultLanguage; +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/LinkHashChromium.cpp b/WebCore/platform/chromium/LinkHashChromium.cpp new file mode 100644 index 0000000..9cb93ea --- /dev/null +++ b/WebCore/platform/chromium/LinkHashChromium.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2008, 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 "LinkHash.h" + +#include "ChromiumBridge.h" + +namespace WebCore { + +LinkHash visitedLinkHash(const UChar* url, unsigned length) +{ + return ChromiumBridge::visitedLinkHash(url, length); +} + +LinkHash visitedLinkHash(const KURL& base, const AtomicString& attributeURL) +{ + return ChromiumBridge::visitedLinkHash(base, attributeURL); +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/MimeTypeRegistryChromium.cpp b/WebCore/platform/chromium/MimeTypeRegistryChromium.cpp new file mode 100644 index 0000000..5d6f426 --- /dev/null +++ b/WebCore/platform/chromium/MimeTypeRegistryChromium.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2008, 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 "MIMETypeRegistry.h" + +#include "ChromiumBridge.h" +#include "CString.h" +#include "MediaPlayer.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 +// ChromiumBridge to the embedder. + +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); +} + +// Returns the file extension if one is found. Does not include the dot in the +// filename. E.g., 'html'. +String MIMETypeRegistry::getPreferredExtensionForMIMEType(const String& type) +{ + // Prune out any parameters in case they happen to have snuck in there... + // FIXME: Is this really necessary?? + String mimeType = type.substring(0, static_cast<unsigned>(type.find(';'))); + + String ext = ChromiumBridge::preferredExtensionForMIMEType(type); + if (!ext.isEmpty() && ext[0] == '.') + ext = ext.substring(1); + + return ext; +} + +String MIMETypeRegistry::getMIMETypeForPath(const String& path) +{ + int pos = path.reverseFind('.'); + if (pos < 0) + return "application/octet-stream"; + String extension = path.substring(pos + 1); + String mimeType = getMIMETypeForExtension(extension); + if (mimeType.isEmpty()) { + // If there's no mimetype registered for the extension, check to see + // if a plugin can handle the extension. + mimeType = getPluginMimeTypeFromExtension(extension); + } + return mimeType; +} + +bool MIMETypeRegistry::isSupportedImageMIMEType(const String& mimeType) +{ + return !mimeType.isEmpty() + && ChromiumBridge::isSupportedImageMIMEType(mimeType.latin1().data()); +} + +bool MIMETypeRegistry::isSupportedImageResourceMIMEType(const String& mimeType) +{ + return isSupportedImageMIMEType(mimeType); +} + +bool MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(const String& mimeType) +{ + // FIXME: Fill this out. See: http://trac.webkit.org/changeset/30888 + return isSupportedImageMIMEType(mimeType); +} + +bool MIMETypeRegistry::isSupportedJavaScriptMIMEType(const String& mimeType) +{ + return !mimeType.isEmpty() + && ChromiumBridge::isSupportedJavascriptMIMEType(mimeType.latin1().data()); +} + +bool MIMETypeRegistry::isSupportedNonImageMIMEType(const String& mimeType) +{ + return !mimeType.isEmpty() + && ChromiumBridge::isSupportedNonImageMIMEType(mimeType.latin1().data()); +} + +bool MIMETypeRegistry::isSupportedMediaMIMEType(const String& mimeType) +{ + HashSet<String> supportedMediaMIMETypes; +#if ENABLE(VIDEO) + MediaPlayer::getSupportedTypes(supportedMediaMIMETypes); +#endif + return !mimeType.isEmpty() && supportedMediaMIMETypes.contains(mimeType); +} + +bool MIMETypeRegistry::isJavaAppletMIMEType(const String& mimeType) +{ + // Since this set is very limited and is likely to remain so we won't bother with the overhead + // of using a hash set. + // Any of the MIME types below may be followed by any number of specific versions of the JVM, + // which is why we use startsWith() + return mimeType.startsWith("application/x-java-applet", false) + || mimeType.startsWith("application/x-java-bean", false) + || mimeType.startsWith("application/x-java-vm", false); +} + +static HashSet<String>& dummyHashSet() +{ + ASSERT_NOT_REACHED(); + static HashSet<String> dummy; + return dummy; +} + +// NOTE: the following methods should never be reached +HashSet<String>& MIMETypeRegistry::getSupportedImageMIMETypes() { return dummyHashSet(); } +HashSet<String>& MIMETypeRegistry::getSupportedImageResourceMIMETypes() { return dummyHashSet(); } +HashSet<String>& MIMETypeRegistry::getSupportedImageMIMETypesForEncoding() { return dummyHashSet(); } +HashSet<String>& MIMETypeRegistry::getSupportedNonImageMIMETypes() { return dummyHashSet(); } +HashSet<String>& MIMETypeRegistry::getSupportedMediaMIMETypes() { return dummyHashSet(); } + +} // namespace WebCore diff --git a/WebCore/platform/chromium/PasteboardChromium.cpp b/WebCore/platform/chromium/PasteboardChromium.cpp new file mode 100644 index 0000000..e7b2203 --- /dev/null +++ b/WebCore/platform/chromium/PasteboardChromium.cpp @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2008, 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 "Pasteboard.h" + +#include "ChromiumBridge.h" +#include "ClipboardUtilitiesChromium.h" +#include "DocumentFragment.h" +#include "Document.h" +#include "Element.h" +#include "Frame.h" +#include "HTMLNames.h" +#include "Image.h" +#include "KURL.h" +#include "markup.h" +#include "NativeImageSkia.h" +#include "Range.h" +#include "RenderImage.h" + +#if ENABLE(SVG) +#include "SVGNames.h" +#include "XLinkNames.h" +#endif + +namespace WebCore { + +Pasteboard* Pasteboard::generalPasteboard() +{ + static Pasteboard* pasteboard = new Pasteboard; + return pasteboard; +} + +Pasteboard::Pasteboard() +{ +} + +void Pasteboard::clear() +{ + // The ScopedClipboardWriter class takes care of clearing the clipboard's + // previous contents. +} + +void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame) +{ + String html = createMarkup(selectedRange, 0, AnnotateForInterchange); + ExceptionCode ec = 0; + KURL url = selectedRange->startContainer(ec)->document()->url(); + String plainText = frame->selectedText(); +#if PLATFORM(WIN_OS) + replaceNewlinesWithWindowsStyleNewlines(plainText); +#endif + replaceNBSPWithSpace(plainText); + + ChromiumBridge::clipboardWriteSelection(html, url, plainText, canSmartCopyOrDelete); +} + +void Pasteboard::writeURL(const KURL& url, const String& titleStr, Frame* frame) +{ + ASSERT(!url.isEmpty()); + + String title(titleStr); + if (title.isEmpty()) { + title = url.lastPathComponent(); + if (title.isEmpty()) + title = url.host(); + } + + ChromiumBridge::clipboardWriteURL(url, title); +} + +void Pasteboard::writeImage(Node* node, const KURL&, const String& title) +{ + // If the image is wrapped in a link, |url| points to the target of the + // link. This isn't useful to us, so get the actual image URL. + AtomicString urlString; + if (node->hasTagName(HTMLNames::imgTag) || node->hasTagName(HTMLNames::inputTag)) + urlString = static_cast<Element*>(node)->getAttribute(HTMLNames::srcAttr); +#if ENABLE(SVG) + else if (node->hasTagName(SVGNames::imageTag)) + urlString = static_cast<Element*>(node)->getAttribute(XLinkNames::hrefAttr); +#endif + else if (node->hasTagName(HTMLNames::embedTag) || node->hasTagName(HTMLNames::objectTag)) { + Element* element = static_cast<Element*>(node); + urlString = element->getAttribute(element->imageSourceAttributeName()); + } + KURL url = urlString.isEmpty() ? KURL() : node->document()->completeURL(parseURL(urlString)); + + ASSERT(node); + ASSERT(node->renderer()); + ASSERT(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); + + NativeImageSkia* bitmap = 0; +#if !PLATFORM(CG) + bitmap = image->nativeImageForCurrentFrame(); +#endif + ChromiumBridge::clipboardWriteImage(bitmap, url, title); +} + +bool Pasteboard::canSmartReplace() +{ + return ChromiumBridge::clipboardIsFormatAvailable( + PasteboardPrivate::WebSmartPasteFormat); +} + +String Pasteboard::plainText(Frame* frame) +{ + return ChromiumBridge::clipboardReadPlainText(); +} + +PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefPtr<Range> context, bool allowPlainText, bool& chosePlainText) +{ + chosePlainText = false; + + if (ChromiumBridge::clipboardIsFormatAvailable(PasteboardPrivate::HTMLFormat)) { + String markup; + KURL srcURL; + ChromiumBridge::clipboardReadHTML(&markup, &srcURL); + + RefPtr<DocumentFragment> fragment = + createFragmentFromMarkup(frame->document(), markup, srcURL); + if (fragment) + return fragment.release(); + } + + if (allowPlainText) { + String markup = ChromiumBridge::clipboardReadPlainText(); + if (!markup.isEmpty()) { + chosePlainText = true; + + RefPtr<DocumentFragment> fragment = + createFragmentFromText(context.get(), markup); + if (fragment) + return fragment.release(); + } + } + + return 0; +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/PasteboardPrivate.h b/WebCore/platform/chromium/PasteboardPrivate.h new file mode 100644 index 0000000..26d45a0 --- /dev/null +++ b/WebCore/platform/chromium/PasteboardPrivate.h @@ -0,0 +1,48 @@ +/* + * 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. + */ + +#ifndef PasteboardPrivate_h +#define PasteboardPrivate_h + +namespace WebCore { + + class PasteboardPrivate + { + public: + enum ClipboardFormat { + HTMLFormat, + BookmarkFormat, + WebSmartPasteFormat, + }; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/chromium/PlatformCursor.h b/WebCore/platform/chromium/PlatformCursor.h new file mode 100644 index 0000000..692c007 --- /dev/null +++ b/WebCore/platform/chromium/PlatformCursor.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2008, 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 PlatformCursor_h +#define PlatformCursor_h + +#include "Image.h" +#include "IntPoint.h" +#include "RefPtr.h" + +namespace WebCore { + + class PlatformCursor { + public: + enum Type { + TypePointer, + TypeCross, + TypeHand, + TypeIBeam, + TypeWait, + TypeHelp, + TypeEastResize, + TypeNorthResize, + TypeNorthEastResize, + TypeNorthWestResize, + TypeSouthResize, + TypeSouthEastResize, + TypeSouthWestResize, + TypeWestResize, + TypeNorthSouthResize, + TypeEastWestResize, + TypeNorthEastSouthWestResize, + TypeNorthWestSouthEastResize, + TypeColumnResize, + TypeRowResize, + TypeMiddlePanning, + TypeEastPanning, + TypeNorthPanning, + TypeNorthEastPanning, + TypeNorthWestPanning, + TypeSouthPanning, + TypeSouthEastPanning, + TypeSouthWestPanning, + TypeWestPanning, + TypeMove, + TypeVerticalText, + TypeCell, + TypeContextMenu, + TypeAlias, + TypeProgress, + TypeNoDrop, + TypeCopy, + TypeNone, + TypeNotAllowed, + TypeZoomIn, + TypeZoomOut, + TypeCustom + }; + + // Cursor.h assumes that it can initialize us to 0. + explicit PlatformCursor(int type = 0) : m_type(TypePointer) {} + + PlatformCursor(Type type) : m_type(type) {} + + PlatformCursor(Image* image, const IntPoint& hotSpot) + : m_image(image) + , m_hotSpot(hotSpot) + , m_type(TypeCustom) {} + + PassRefPtr<Image> customImage() const { return m_image; } + const IntPoint& hotSpot() const { return m_hotSpot; } + Type type() const { return m_type; } + + private: + RefPtr<Image> m_image; + IntPoint m_hotSpot; + Type m_type; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/chromium/PlatformKeyboardEventChromium.cpp b/WebCore/platform/chromium/PlatformKeyboardEventChromium.cpp new file mode 100644 index 0000000..6840bdf --- /dev/null +++ b/WebCore/platform/chromium/PlatformKeyboardEventChromium.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Google 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 "PlatformKeyboardEvent.h" + +#if PLATFORM(WIN_OS) +#include <windows.h> +#elif PLATFORM(DARWIN) +#import <Carbon/Carbon.h> +#else +#include "NotImplemented.h" +#endif + +namespace WebCore { + +void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool backwardCompatibilityMode) +{ +#if PLATFORM(WIN_OS) + // No KeyDown events on Windows to disambiguate. + ASSERT_NOT_REACHED(); +#elif PLATFORM(DARWIN) + // Can only change type from KeyDown to RawKeyDown or Char, as we lack information for other conversions. + ASSERT(m_type == KeyDown); + ASSERT(type == RawKeyDown || type == Char); + m_type = type; + if (backwardCompatibilityMode) + return; + + if (type == RawKeyDown) { + m_text = String(); + m_unmodifiedText = String(); + } else { + m_keyIdentifier = String(); + m_windowsVirtualKeyCode = 0; + if (m_text.length() == 1 && (m_text[0U] >= 0xF700 && m_text[0U] <= 0xF7FF)) { + // According to NSEvents.h, OpenStep reserves the range 0xF700-0xF8FF for function keys. However, some actual private use characters + // happen to be in this range, e.g. the Apple logo (Option+Shift+K). + // 0xF7FF is an arbitrary cut-off. + m_text = String(); + m_unmodifiedText = String(); + } + } +#endif +} + +bool PlatformKeyboardEvent::currentCapsLockState() +{ +#if PLATFORM(WIN_OS) + // FIXME: Does this even work inside the sandbox? + return GetKeyState(VK_CAPITAL) & 1; +#elif PLATFORM(DARWIN) + return GetCurrentKeyModifiers() & alphaLock; +#else + notImplemented(); + return false; +#endif +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/PlatformScreenChromium.cpp b/WebCore/platform/chromium/PlatformScreenChromium.cpp new file mode 100644 index 0000000..e659ef5 --- /dev/null +++ b/WebCore/platform/chromium/PlatformScreenChromium.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2008, 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 "PlatformScreen.h" + +#include "ChromiumBridge.h" +#include "IntRect.h" + +namespace WebCore { + +int screenDepth(Widget* widget) +{ + return ChromiumBridge::screenDepth(widget); +} + +int screenDepthPerComponent(Widget* widget) +{ + return ChromiumBridge::screenDepthPerComponent(widget); +} + +bool screenIsMonochrome(Widget* widget) +{ + return ChromiumBridge::screenIsMonochrome(widget); +} + +FloatRect screenRect(Widget* widget) +{ + return ChromiumBridge::screenRect(widget); +} + +FloatRect screenAvailableRect(Widget* widget) +{ + return ChromiumBridge::screenAvailableRect(widget); +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/PlatformWidget.h b/WebCore/platform/chromium/PlatformWidget.h new file mode 100644 index 0000000..e4e6a18 --- /dev/null +++ b/WebCore/platform/chromium/PlatformWidget.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008, 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 PlatformWidget_h +#define PlatformWidget_h + +// PlatformWidget is an opaque identifier corresponding to whatever native +// view type the embedder may use. PlatformWidget CANNOT be assumed to be +// a valid pointer. Some embedders may not use this identifier at all. + +typedef void* PlatformWidget; + +#endif diff --git a/WebCore/platform/chromium/PopupMenuChromium.cpp b/WebCore/platform/chromium/PopupMenuChromium.cpp new file mode 100644 index 0000000..fad0a6b --- /dev/null +++ b/WebCore/platform/chromium/PopupMenuChromium.cpp @@ -0,0 +1,1181 @@ +/* + * Copyright (c) 2008, 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 "PopupMenuChromium.h" + +#include "CharacterNames.h" +#include "ChromeClientChromium.h" +#include "Font.h" +#include "FontSelector.h" +#include "FrameView.h" +#include "Frame.h" +#include "FramelessScrollView.h" +#include "FramelessScrollViewClient.h" +#include "GraphicsContext.h" +#include "IntRect.h" +#include "KeyboardCodes.h" +#include "Page.h" +#include "PlatformKeyboardEvent.h" +#include "PlatformMouseEvent.h" +#include "PlatformScreen.h" +#include "PlatformWheelEvent.h" +#include "PopupMenu.h" +#include "RenderTheme.h" +#include "ScrollbarTheme.h" +#include "SystemTime.h" + +#include <wtf/CurrentTime.h> + +using namespace WTF; +using namespace Unicode; + +using std::min; +using std::max; + +namespace WebCore { + +typedef unsigned long long TimeStamp; + +static const int kMaxVisibleRows = 20; +static const int kMaxHeight = 500; +static const int kBorderSize = 1; +static const TimeStamp kTypeAheadTimeoutMs = 1000; + +// This class uses WebCore code to paint and handle events for a drop-down list +// box ("combobox" on Windows). +class PopupListBox : public FramelessScrollView, public RefCounted<PopupListBox> { +public: + // FramelessScrollView + virtual void paint(GraphicsContext*, const IntRect&); + virtual bool handleMouseDownEvent(const PlatformMouseEvent&); + virtual bool handleMouseMoveEvent(const PlatformMouseEvent&); + virtual bool handleMouseReleaseEvent(const PlatformMouseEvent&); + virtual bool handleWheelEvent(const PlatformWheelEvent&); + virtual bool handleKeyEvent(const PlatformKeyboardEvent&); + + // ScrollView + virtual HostWindow* hostWindow() const; + + // Widget + virtual void invalidateRect(const IntRect&); + + // PopupListBox methods + + // Shows the popup + void showPopup(); + + // Hides the popup. Do not call this directly: use client->hidePopup(). + void hidePopup(); + + // Updates our internal list to match the client. + void updateFromElement(); + + // Frees any allocated resources used in a particular popup session. + void clear(); + + // Sets the index of the option that is displayed in the <select> widget in the page + void setOriginalIndex(int index); + + // Gets the index of the item that the user is currently moused over or has selected with + // the keyboard. This is not the same as the original index, since the user has not yet + // accepted this input. + int selectedIndex() const { return m_selectedIndex; } + + // Moves selection down/up the given number of items, scrolling if necessary. + // Positive is down. The resulting index will be clamped to the range + // [0, numItems), and non-option items will be skipped. + void adjustSelectedIndex(int delta); + + // Returns the number of items in the list. + int numItems() const { return static_cast<int>(m_items.size()); } + + void setBaseWidth(int width) { m_baseWidth = width; } + + // Computes the size of widget and children. + void layout(); + + // Returns whether the popup wants to process events for the passed key. + bool isInterestedInEventForKey(int keyCode); + + // Sets whether the PopupMenuClient should be told to change its text when a + // new item is selected (by using the arrow keys). Default is true. + void setTextOnIndexChange(bool value) { m_setTextOnIndexChange = value; } + + // Sets whether we should accept the selected index when the popup is + // abandonned. + void setAcceptOnAbandon(bool value) { m_shouldAcceptOnAbandon = value; } + + // Sets whether pressing the down/up arrow when the last/first row is + // selected clears the selection on the first key press and then selects the + // first/last row on the next key press. If false, the selected row stays + // the last/first row. + void setLoopSelectionNavigation(bool value) { m_loopSelectionNavigation = value; } + +private: + friend class PopupContainer; + friend class RefCounted<PopupListBox>; + + // A type of List Item + enum ListItemType { + TypeOption, + TypeGroup, + TypeSeparator + }; + + // A item (represented by <option> or <optgroup>) in the <select> widget. + struct ListItem { + ListItem(const String& label, ListItemType type) + : label(label.copy()), type(type), y(0) {} + String label; + ListItemType type; + int y; // y offset of this item, relative to the top of the popup. + }; + + PopupListBox(PopupMenuClient* client) + : m_originalIndex(0) + , m_selectedIndex(0) + , m_shouldAcceptOnAbandon(true) + , m_willAcceptOnAbandon(false) + , m_visibleRows(0) + , m_popupClient(client) + , m_repeatingChar(0) + , m_lastCharTime(0) + , m_setTextOnIndexChange(true) + , m_loopSelectionNavigation(false) + { + setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff); + } + + ~PopupListBox() + { + clear(); + } + + void disconnectClient() { m_popupClient = 0; } + + // Closes the popup + void abandon(); + // Select an index in the list, scrolling if necessary. + void selectIndex(int index); + // Accepts the selected index as the value to be displayed in the <select> widget on + // the web page, and closes the popup. + void acceptIndex(int index); + + // Returns true if the selection can be changed to index. + // Disabled items, or labels cannot be selected. + bool isSelectableItem(int index); + + // Clears the selection (so no row appears selected). + void clearSelection(); + + // Scrolls to reveal the given index. + void scrollToRevealRow(int index); + void scrollToRevealSelection() { scrollToRevealRow(m_selectedIndex); } + + // Invalidates the row at the given index. + void invalidateRow(int index); + + // Gets the height of a row. + int getRowHeight(int index); + // Get the bounds of a row. + IntRect getRowBounds(int index); + + // Converts a point to an index of the row the point is over + int pointToRowIndex(const IntPoint&); + + // Paint an individual row + void paintRow(GraphicsContext*, const IntRect&, int rowIndex); + + // Test if the given point is within the bounds of the popup window. + bool isPointInBounds(const IntPoint&); + + // Called when the user presses a text key. Does a prefix-search of the items. + void typeAheadFind(const PlatformKeyboardEvent&); + + // Returns the font to use for the given row + Font getRowFont(int index); + + // Moves the selection down/up one item, taking care of looping back to the + // first/last element if m_loopSelectionNavigation is true. + void selectPreviousRow(); + void selectNextRow(); + + // This is the index of the item marked as "selected" - i.e. displayed in the widget on the + // page. + int m_originalIndex; + + // This is the index of the item that the user is hovered over or has selected using the + // keyboard in the list. They have not confirmed this selection by clicking or pressing + // enter yet however. + int m_selectedIndex; + + // Whether we should accept the selectedIndex as chosen when the popup is + // "abandoned". This value is set through its setter and is useful as + // select popup menu and form autofill popup menu have different behaviors. + bool m_shouldAcceptOnAbandon; + + // True if we should accept the selectedIndex as chosen, even if the popup + // is "abandoned". This is used for keyboard navigation, where we want the + // selection to change immediately, and is only used if + // m_shouldAcceptOnAbandon is true. + bool m_willAcceptOnAbandon; + + // This is the number of rows visible in the popup. The maximum number visible at a time is + // defined as being kMaxVisibleRows. For a scrolled popup, this can be thought of as the + // page size in data units. + int m_visibleRows; + + // Our suggested width, not including scrollbar. + int m_baseWidth; + + // A list of the options contained within the <select> + Vector<ListItem*> m_items; + + // The <select> PopupMenuClient that opened us. + PopupMenuClient* m_popupClient; + + // The scrollbar which has mouse capture. Mouse events go straight to this + // if non-NULL. + RefPtr<Scrollbar> m_capturingScrollbar; + + // The last scrollbar that the mouse was over. Used for mouseover highlights. + RefPtr<Scrollbar> m_lastScrollbarUnderMouse; + + // The string the user has typed so far into the popup. Used for typeAheadFind. + String m_typedString; + + // The char the user has hit repeatedly. Used for typeAheadFind. + UChar m_repeatingChar; + + // The last time the user hit a key. Used for typeAheadFind. + TimeStamp m_lastCharTime; + + bool m_setTextOnIndexChange; + + bool m_loopSelectionNavigation; +}; + +static PlatformMouseEvent constructRelativeMouseEvent(const PlatformMouseEvent& e, + FramelessScrollView* parent, + FramelessScrollView* child) +{ + IntPoint pos = parent->convertSelfToChild(child, e.pos()); + + // FIXME: This is a horrible hack since PlatformMouseEvent has no setters for x/y. + PlatformMouseEvent relativeEvent = e; + IntPoint& relativePos = const_cast<IntPoint&>(relativeEvent.pos()); + relativePos.setX(pos.x()); + relativePos.setY(pos.y()); + return relativeEvent; +} + +static PlatformWheelEvent constructRelativeWheelEvent(const PlatformWheelEvent& e, + FramelessScrollView* parent, + FramelessScrollView* child) +{ + IntPoint pos = parent->convertSelfToChild(child, e.pos()); + + // FIXME: This is a horrible hack since PlatformWheelEvent has no setters for x/y. + PlatformWheelEvent relativeEvent = e; + IntPoint& relativePos = const_cast<IntPoint&>(relativeEvent.pos()); + relativePos.setX(pos.x()); + relativePos.setY(pos.y()); + return relativeEvent; +} + +/////////////////////////////////////////////////////////////////////////////// +// PopupContainer implementation + +// static +PassRefPtr<PopupContainer> PopupContainer::create(PopupMenuClient* client, + bool focusOnShow) +{ + return adoptRef(new PopupContainer(client, focusOnShow)); +} + +PopupContainer::PopupContainer(PopupMenuClient* client, bool focusOnShow) + : m_listBox(new PopupListBox(client)), + m_focusOnShow(focusOnShow) +{ + // FrameViews are created with a refcount of 1 so it needs releasing after we + // assign it to a RefPtr. + m_listBox->deref(); + + setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff); +} + +PopupContainer::~PopupContainer() +{ + if (m_listBox) + removeChild(m_listBox.get()); +} + +void PopupContainer::showPopup(FrameView* view) +{ + // Pre-layout, our size matches the <select> dropdown control. + int selectHeight = frameRect().height(); + + // Lay everything out to figure out our preferred size, then tell the view's + // WidgetClient about it. It should assign us a client. + layout(); + + ChromeClientChromium* chromeClient = static_cast<ChromeClientChromium*>( + view->frame()->page()->chrome()->client()); + if (chromeClient) { + // If the popup would extend past the bottom of the screen, open upwards + // instead. + FloatRect screen = screenRect(view); + IntRect widgetRect = chromeClient->windowToScreen(frameRect()); + if (widgetRect.bottom() > static_cast<int>(screen.bottom())) + widgetRect.move(0, -(widgetRect.height() + selectHeight)); + + chromeClient->popupOpened(this, widgetRect, m_focusOnShow); + } + + // Must get called after we have a client and containingWindow. + addChild(m_listBox.get()); + + // Enable scrollbars after the listbox is inserted into the hierarchy, so + // it has a proper WidgetClient. + m_listBox->setVerticalScrollbarMode(ScrollbarAuto); + + m_listBox->scrollToRevealSelection(); + + invalidate(); +} + +void PopupContainer::hidePopup() +{ + invalidate(); + + m_listBox->disconnectClient(); + removeChild(m_listBox.get()); + m_listBox = 0; + + if (client()) + client()->popupClosed(this); +} + +void PopupContainer::layout() +{ + m_listBox->layout(); + + // Place the listbox within our border. + m_listBox->move(kBorderSize, kBorderSize); + + // Size ourselves to contain listbox + border. + resize(m_listBox->width() + kBorderSize * 2, m_listBox->height() + kBorderSize * 2); + + invalidate(); +} + +bool PopupContainer::handleMouseDownEvent(const PlatformMouseEvent& event) +{ + return m_listBox->handleMouseDownEvent( + constructRelativeMouseEvent(event, this, m_listBox.get())); +} + +bool PopupContainer::handleMouseMoveEvent(const PlatformMouseEvent& event) +{ + return m_listBox->handleMouseMoveEvent( + constructRelativeMouseEvent(event, this, m_listBox.get())); +} + +bool PopupContainer::handleMouseReleaseEvent(const PlatformMouseEvent& event) +{ + return m_listBox->handleMouseReleaseEvent( + constructRelativeMouseEvent(event, this, m_listBox.get())); +} + +bool PopupContainer::handleWheelEvent(const PlatformWheelEvent& event) +{ + return m_listBox->handleWheelEvent( + constructRelativeWheelEvent(event, this, m_listBox.get())); +} + +bool PopupContainer::handleKeyEvent(const PlatformKeyboardEvent& event) +{ + return m_listBox->handleKeyEvent(event); +} + +void PopupContainer::hide() +{ + m_listBox->abandon(); +} + +void PopupContainer::paint(GraphicsContext* gc, const IntRect& rect) +{ + // adjust coords for scrolled frame + IntRect r = intersection(rect, frameRect()); + int tx = x(); + int ty = y(); + + r.move(-tx, -ty); + + gc->translate(static_cast<float>(tx), static_cast<float>(ty)); + m_listBox->paint(gc, r); + gc->translate(-static_cast<float>(tx), -static_cast<float>(ty)); + + paintBorder(gc, rect); +} + +void PopupContainer::paintBorder(GraphicsContext* gc, const IntRect& rect) +{ + // FIXME: Where do we get the border color from? + Color borderColor(127, 157, 185); + + gc->setStrokeStyle(NoStroke); + gc->setFillColor(borderColor); + + int tx = x(); + int ty = y(); + + // top, left, bottom, right + gc->drawRect(IntRect(tx, ty, width(), kBorderSize)); + gc->drawRect(IntRect(tx, ty, kBorderSize, height())); + gc->drawRect(IntRect(tx, ty + height() - kBorderSize, width(), kBorderSize)); + gc->drawRect(IntRect(tx + width() - kBorderSize, ty, kBorderSize, height())); +} + +bool PopupContainer::isInterestedInEventForKey(int keyCode) +{ + return m_listBox->isInterestedInEventForKey(keyCode); +} + +void PopupContainer::show(const IntRect& r, FrameView* v, int index) +{ + // The rect is the size of the select box. It's usually larger than we need. + // subtract border size so that usually the container will be displayed + // exactly the same width as the select box. + listBox()->setBaseWidth(max(r.width() - kBorderSize * 2, 0)); + + listBox()->updateFromElement(); + + // We set the selected item in updateFromElement(), and disregard the + // index passed into this function (same as Webkit's PopupMenuWin.cpp) + // FIXME: make sure this is correct, and add an assertion. + // ASSERT(popupWindow(popup)->listBox()->selectedIndex() == index); + + // Convert point to main window coords. + IntPoint location = v->contentsToWindow(r.location()); + + // Move it below the select widget. + location.move(0, r.height()); + + IntRect popupRect(location, r.size()); + setFrameRect(popupRect); + showPopup(v); +} + +void PopupContainer::setTextOnIndexChange(bool value) +{ + listBox()->setTextOnIndexChange(value); +} + +void PopupContainer::setAcceptOnAbandon(bool value) +{ + listBox()->setAcceptOnAbandon(value); +} + +void PopupContainer::setLoopSelectionNavigation(bool value) +{ + listBox()->setLoopSelectionNavigation(value); +} + +void PopupContainer::refresh() +{ + listBox()->updateFromElement(); + layout(); +} + +/////////////////////////////////////////////////////////////////////////////// +// PopupListBox implementation + +bool PopupListBox::handleMouseDownEvent(const PlatformMouseEvent& event) +{ + Scrollbar* scrollbar = scrollbarUnderMouse(event); + if (scrollbar) { + m_capturingScrollbar = scrollbar; + m_capturingScrollbar->mouseDown(event); + return true; + } + + if (!isPointInBounds(event.pos())) + abandon(); + + return true; +} + +bool PopupListBox::handleMouseMoveEvent(const PlatformMouseEvent& event) +{ + if (m_capturingScrollbar) { + m_capturingScrollbar->mouseMoved(event); + return true; + } + + Scrollbar* scrollbar = scrollbarUnderMouse(event); + if (m_lastScrollbarUnderMouse != scrollbar) { + // Send mouse exited to the old scrollbar. + if (m_lastScrollbarUnderMouse) + m_lastScrollbarUnderMouse->mouseExited(); + m_lastScrollbarUnderMouse = scrollbar; + } + + if (scrollbar) { + scrollbar->mouseMoved(event); + return true; + } + + if (!isPointInBounds(event.pos())) + return false; + + selectIndex(pointToRowIndex(event.pos())); + return true; +} + +bool PopupListBox::handleMouseReleaseEvent(const PlatformMouseEvent& event) +{ + if (m_capturingScrollbar) { + m_capturingScrollbar->mouseUp(); + m_capturingScrollbar = 0; + return true; + } + + if (!isPointInBounds(event.pos())) + return true; + + acceptIndex(pointToRowIndex(event.pos())); + return true; +} + +bool PopupListBox::handleWheelEvent(const PlatformWheelEvent& event) +{ + if (!isPointInBounds(event.pos())) { + abandon(); + return true; + } + + // Pass it off to the scroll view. + // Sadly, WebCore devs don't understand the whole "const" thing. + wheelEvent(const_cast<PlatformWheelEvent&>(event)); + return true; +} + +// Should be kept in sync with handleKeyEvent(). +bool PopupListBox::isInterestedInEventForKey(int keyCode) +{ + switch (keyCode) { + case VKEY_ESCAPE: + case VKEY_RETURN: + case VKEY_UP: + case VKEY_DOWN: + case VKEY_PRIOR: + case VKEY_NEXT: + case VKEY_HOME: + case VKEY_END: + case VKEY_TAB: + return true; + default: + return false; + } +} + +bool PopupListBox::handleKeyEvent(const PlatformKeyboardEvent& event) +{ + if (event.type() == PlatformKeyboardEvent::KeyUp) + return true; + + if (numItems() == 0 && event.windowsVirtualKeyCode() != VKEY_ESCAPE) + return true; + + switch (event.windowsVirtualKeyCode()) { + case VKEY_ESCAPE: + abandon(); // may delete this + return true; + case VKEY_RETURN: + if (m_selectedIndex == -1) { + m_popupClient->hidePopup(); + // Don't eat the enter if nothing is selected. + return false; + } + acceptIndex(m_selectedIndex); // may delete this + return true; + case VKEY_UP: + selectPreviousRow(); + break; + case VKEY_DOWN: + selectNextRow(); + break; + case VKEY_PRIOR: + adjustSelectedIndex(-m_visibleRows); + break; + case VKEY_NEXT: + adjustSelectedIndex(m_visibleRows); + break; + case VKEY_HOME: + adjustSelectedIndex(-m_selectedIndex); + break; + case VKEY_END: + adjustSelectedIndex(m_items.size()); + break; + default: + if (!event.ctrlKey() && !event.altKey() && !event.metaKey() + && isPrintableChar(event.windowsVirtualKeyCode())) + typeAheadFind(event); + break; + } + + if (m_originalIndex != m_selectedIndex) { + // Keyboard events should update the selection immediately (but we don't + // want to fire the onchange event until the popup is closed, to match + // IE). We change the original index so we revert to that when the + // popup is closed. + if (m_shouldAcceptOnAbandon) + m_willAcceptOnAbandon = true; + + setOriginalIndex(m_selectedIndex); + if (m_setTextOnIndexChange) + m_popupClient->setTextFromItem(m_selectedIndex); + } else if (!m_setTextOnIndexChange && event.windowsVirtualKeyCode() == VKEY_TAB) { + // TAB is a special case as it should select the current item if any and + // advance focus. + if (m_selectedIndex >= 0) + m_popupClient->setTextFromItem(m_selectedIndex); + // Return false so the TAB key event is propagated to the page. + return false; + } + + return true; +} + +HostWindow* PopupListBox::hostWindow() const +{ + // Our parent is the root ScrollView, so it is the one that has a + // HostWindow. FrameView::hostWindow() works similarly. + return parent() ? parent()->hostWindow() : 0; +} + +void PopupListBox::invalidateRect(const IntRect& rect) +{ + // Since we are returning the HostWindow of our parent as our own in + // hostWindow(), we need to invalidate in our parent's coordinates. + IntRect newRect(rect); + newRect.move(kBorderSize, kBorderSize); + FramelessScrollView::invalidateRect(newRect); +} + +// From HTMLSelectElement.cpp +static String stripLeadingWhiteSpace(const String& string) +{ + int length = string.length(); + int i; + for (i = 0; i < length; ++i) + if (string[i] != noBreakSpace + && (string[i] <= 0x7F ? !isspace(string[i]) : (direction(string[i]) != WhiteSpaceNeutral))) + break; + + return string.substring(i, length - i); +} + +// From HTMLSelectElement.cpp, with modifications +void PopupListBox::typeAheadFind(const PlatformKeyboardEvent& event) +{ + TimeStamp now = static_cast<TimeStamp>(currentTime() * 1000.0f); + TimeStamp delta = now - m_lastCharTime; + + m_lastCharTime = now; + + UChar c = event.windowsVirtualKeyCode(); + + String prefix; + int searchStartOffset = 1; + if (delta > kTypeAheadTimeoutMs) { + m_typedString = prefix = String(&c, 1); + m_repeatingChar = c; + } else { + m_typedString.append(c); + + if (c == m_repeatingChar) + // The user is likely trying to cycle through all the items starting with this character, so just search on the character + prefix = String(&c, 1); + else { + m_repeatingChar = 0; + prefix = m_typedString; + searchStartOffset = 0; + } + } + + int itemCount = numItems(); + int index = (max(0, m_selectedIndex) + searchStartOffset) % itemCount; + for (int i = 0; i < itemCount; i++, index = (index + 1) % itemCount) { + if (!isSelectableItem(index)) + continue; + + if (stripLeadingWhiteSpace(m_items[index]->label).startsWith(prefix, false)) { + selectIndex(index); + return; + } + } +} + +void PopupListBox::paint(GraphicsContext* gc, const IntRect& rect) +{ + // adjust coords for scrolled frame + IntRect r = intersection(rect, frameRect()); + int tx = x() - scrollX(); + int ty = y() - scrollY(); + + r.move(-tx, -ty); + + // set clip rect to match revised damage rect + gc->save(); + gc->translate(static_cast<float>(tx), static_cast<float>(ty)); + gc->clip(r); + + // FIXME: Can we optimize scrolling to not require repainting the entire + // window? Should we? + for (int i = 0; i < numItems(); ++i) + paintRow(gc, r, i); + + // Special case for an empty popup. + if (numItems() == 0) + gc->fillRect(r, Color::white); + + gc->restore(); + + ScrollView::paint(gc, rect); +} + +static const int separatorPadding = 4; +static const int separatorHeight = 1; + +void PopupListBox::paintRow(GraphicsContext* gc, const IntRect& rect, int rowIndex) +{ + // This code is based largely on RenderListBox::paint* methods. + + IntRect rowRect = getRowBounds(rowIndex); + if (!rowRect.intersects(rect)) + return; + + PopupMenuStyle style = m_popupClient->itemStyle(rowIndex); + + // Paint background + Color backColor, textColor; + if (rowIndex == m_selectedIndex) { + backColor = theme()->activeListBoxSelectionBackgroundColor(); + textColor = theme()->activeListBoxSelectionForegroundColor(); + } else { + backColor = style.backgroundColor(); + textColor = style.foregroundColor(); + } + + // 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, backColor); + + 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); + return; + } + + gc->setFillColor(textColor); + + // Bunch of shit to deal with RTL text... + String itemText = m_popupClient->itemText(rowIndex); + 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)); + } +} + +Font PopupListBox::getRowFont(int rowIndex) +{ + Font itemFont = m_popupClient->itemStyle(rowIndex).font(); + if (m_popupClient->itemIsLabel(rowIndex)) { + // Bold-ify labels (ie, an <optgroup> heading). + FontDescription d = itemFont.fontDescription(); + d.setWeight(FontWeightBold); + Font font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); + font.update(0); + return font; + } + + return itemFont; +} + +void PopupListBox::abandon() +{ + RefPtr<PopupListBox> keepAlive(this); + + m_selectedIndex = m_originalIndex; + + if (m_willAcceptOnAbandon) + m_popupClient->valueChanged(m_selectedIndex); + + // valueChanged may have torn down the popup! + if (m_popupClient) + m_popupClient->hidePopup(); +} + +int PopupListBox::pointToRowIndex(const IntPoint& point) +{ + int y = scrollY() + point.y(); + + // FIXME: binary search if perf matters. + for (int i = 0; i < numItems(); ++i) { + if (y < m_items[i]->y) + return i-1; + } + + // Last item? + if (y < contentsHeight()) + return m_items.size()-1; + + return -1; +} + +void PopupListBox::acceptIndex(int index) +{ + ASSERT(index >= -1 && index < numItems()); + if (index == -1 && m_popupClient) { + // Enter pressed with no selection, just close the popup. + m_popupClient->hidePopup(); + return; + } + + if (isSelectableItem(index)) { + RefPtr<PopupListBox> keepAlive(this); + + // Tell the <select> PopupMenuClient what index was selected, and hide ourself. + m_popupClient->valueChanged(index); + + // valueChanged may have torn down the popup! + if (m_popupClient) + m_popupClient->hidePopup(); + } +} + +void PopupListBox::selectIndex(int index) +{ + ASSERT(index >= 0 && index < numItems()); + + if (index != m_selectedIndex && isSelectableItem(index)) { + invalidateRow(m_selectedIndex); + m_selectedIndex = index; + invalidateRow(m_selectedIndex); + + scrollToRevealSelection(); + } +} + +void PopupListBox::setOriginalIndex(int index) +{ + m_originalIndex = m_selectedIndex = index; +} + +int PopupListBox::getRowHeight(int index) +{ + if (index < 0) + return 0; + + return m_popupClient->itemStyle(index).font().height(); +} + +IntRect PopupListBox::getRowBounds(int index) +{ + if (index < 0) + return IntRect(0, 0, visibleWidth(), getRowHeight(index)); + + return IntRect(0, m_items[index]->y, visibleWidth(), getRowHeight(index)); +} + +void PopupListBox::invalidateRow(int index) +{ + if (index < 0) + return; + + invalidateRect(getRowBounds(index)); +} + +void PopupListBox::scrollToRevealRow(int index) +{ + if (index < 0) + return; + + IntRect rowRect = getRowBounds(index); + + if (rowRect.y() < scrollY()) { + // Row is above current scroll position, scroll up. + ScrollView::setScrollPosition(IntPoint(0, rowRect.y())); + } else if (rowRect.bottom() > scrollY() + visibleHeight()) { + // Row is below current scroll position, scroll down. + ScrollView::setScrollPosition(IntPoint(0, rowRect.bottom() - visibleHeight())); + } +} + +bool PopupListBox::isSelectableItem(int index) { + return m_items[index]->type == TypeOption && m_popupClient->itemIsEnabled(index); +} + +void PopupListBox::clearSelection() +{ + if (m_selectedIndex != -1) { + invalidateRow(m_selectedIndex); + m_selectedIndex = -1; + } +} + +void PopupListBox::selectNextRow() +{ + if (!m_loopSelectionNavigation || m_selectedIndex != numItems() - 1) { + adjustSelectedIndex(1); + return; + } + + // We are moving past the last item, no row should be selected. + clearSelection(); +} + +void PopupListBox::selectPreviousRow() +{ + if (!m_loopSelectionNavigation || m_selectedIndex > 0) { + adjustSelectedIndex(-1); + return; + } + + if (m_selectedIndex == 0) { + // We are moving past the first item, clear the selection. + clearSelection(); + return; + } + + // No row are selected, jump to the last item. + selectIndex(numItems() - 1); + scrollToRevealSelection(); +} + +void PopupListBox::adjustSelectedIndex(int delta) +{ + int targetIndex = m_selectedIndex + delta; + targetIndex = min(max(targetIndex, 0), numItems() - 1); + if (!isSelectableItem(targetIndex)) { + // We didn't land on an option. Try to find one. + // We try to select the closest index to target, prioritizing any in + // the range [current, target]. + + int dir = delta > 0 ? 1 : -1; + int testIndex = m_selectedIndex; + int bestIndex = m_selectedIndex; + bool passedTarget = false; + while (testIndex >= 0 && testIndex < numItems()) { + if (isSelectableItem(testIndex)) + bestIndex = testIndex; + if (testIndex == targetIndex) + passedTarget = true; + if (passedTarget && bestIndex != m_selectedIndex) + break; + + testIndex += dir; + } + + // Pick the best index, which may mean we don't change. + targetIndex = bestIndex; + } + + // Select the new index, and ensure its visible. We do this regardless of + // whether the selection changed to ensure keyboard events always bring the + // selection into view. + selectIndex(targetIndex); + scrollToRevealSelection(); +} + +void PopupListBox::updateFromElement() +{ + // It happens when pressing a key to jump to an item, then use tab or + // mouse to get away from the select box. In that case, updateFromElement + // is called before abandon, which causes discarding of the select result. + if (m_willAcceptOnAbandon) { + m_popupClient->valueChanged(m_selectedIndex); + m_willAcceptOnAbandon = false; + } + + clear(); + + int size = m_popupClient->listSize(); + for (int i = 0; i < size; ++i) { + ListItemType type; + if (m_popupClient->itemIsSeparator(i)) + type = PopupListBox::TypeSeparator; + else if (m_popupClient->itemIsLabel(i)) + type = PopupListBox::TypeGroup; + else + type = PopupListBox::TypeOption; + m_items.append(new ListItem(m_popupClient->itemText(i), type)); + } + + m_selectedIndex = m_popupClient->selectedIndex(); + setOriginalIndex(m_selectedIndex); + + layout(); +} + +void PopupListBox::layout() +{ + // Size our child items. + int baseWidth = 0; + int paddingWidth = 0; + int y = 0; + for (int i = 0; i < numItems(); ++i) { + Font itemFont = getRowFont(i); + + // Place the item vertically. + m_items[i]->y = y; + y += itemFont.height(); + + // Ensure the popup is wide enough to fit this item. + String text = m_popupClient->itemText(i); + if (!text.isEmpty()) { + int width = itemFont.width(TextRun(text)); + baseWidth = max(baseWidth, width); + } + // FIXME: http://b/1210481 We should get the padding of individual option elements. + paddingWidth = max(paddingWidth, + m_popupClient->clientPaddingLeft() + m_popupClient->clientPaddingRight()); + } + + int windowHeight = 0; + m_visibleRows = min(numItems(), kMaxVisibleRows); + for (int i = 0; i < m_visibleRows; ++i) { + int rowHeight = getRowHeight(i); + if (windowHeight + rowHeight > kMaxHeight) { + m_visibleRows = i; + break; + } + + windowHeight += rowHeight; + } + + // Set our widget and scrollable contents sizes. + int scrollbarWidth = 0; + if (m_visibleRows < numItems()) + scrollbarWidth = ScrollbarTheme::nativeTheme()->scrollbarThickness(); + + int windowWidth = baseWidth + scrollbarWidth + paddingWidth; + int contentWidth = baseWidth; + + if (windowWidth < m_baseWidth) { + windowWidth = m_baseWidth; + contentWidth = m_baseWidth - scrollbarWidth - paddingWidth; + } else { + m_baseWidth = baseWidth; + } + + resize(windowWidth, windowHeight); + setContentsSize(IntSize(contentWidth, getRowBounds(numItems() - 1).bottom())); + + if (hostWindow()) + scrollToRevealSelection(); + + invalidate(); +} + +void PopupListBox::clear() +{ + for (Vector<ListItem*>::iterator it = m_items.begin(); it != m_items.end(); ++it) + delete *it; + m_items.clear(); +} + +bool PopupListBox::isPointInBounds(const IntPoint& point) +{ + return numItems() != 0 && IntRect(0, 0, width(), height()).contains(point); +} + +/////////////////////////////////////////////////////////////////////////////// +// PopupMenu implementation +// +// Note: you cannot add methods to this class, since it is defined above the +// portability layer. To access methods and properties on the +// popup widgets, use |popupWindow| above. + +PopupMenu::PopupMenu(PopupMenuClient* client) + : m_popupClient(client) +{ +} + +PopupMenu::~PopupMenu() +{ + hide(); +} + +void PopupMenu::show(const IntRect& r, FrameView* v, int index) +{ + p.popup = PopupContainer::create(client(), true); + p.popup->show(r, v, index); +} + +void PopupMenu::hide() +{ + if (p.popup) { + p.popup->hidePopup(); + p.popup = 0; + } +} + +void PopupMenu::updateFromElement() +{ + p.popup->listBox()->updateFromElement(); +} + +bool PopupMenu::itemWritingDirectionIsNatural() +{ + return false; +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/PopupMenuChromium.h b/WebCore/platform/chromium/PopupMenuChromium.h new file mode 100644 index 0000000..a57383d --- /dev/null +++ b/WebCore/platform/chromium/PopupMenuChromium.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2008, 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 PopupMenuChromium_h +#define PopupMenuChromium_h + +#include "config.h" +#include "PopupMenuClient.h" + +#include "FramelessScrollView.h" +#include "IntRect.h" + +namespace WebCore { + + class FrameView; + class PopupListBox; + + // FIXME: Our FramelessScrollView classes should probably implement HostWindow! + + // This class holds a PopupListBox (see cpp file). Its sole purpose is to be + // able to draw a border around its child. All its paint/event handling is + // just forwarded to the child listBox (with the appropriate transforms). + // NOTE: this class is exposed so it can be instantiated direcly for the + // autofill popup. We cannot use the Popup class directly in that case as the + // autofill popup should not be focused when shown and we want to forward the + // key events to it (through handleKeyEvent). + + class PopupContainer : public FramelessScrollView, public RefCounted<PopupContainer> { + public: + static PassRefPtr<PopupContainer> create(PopupMenuClient*, bool focusOnShow); + + // Whether a key event should be sent to this popup. + virtual bool isInterestedInEventForKey(int keyCode); + + // FramelessScrollView + virtual void paint(GraphicsContext*, const IntRect&); + virtual void hide(); + virtual bool handleMouseDownEvent(const PlatformMouseEvent&); + virtual bool handleMouseMoveEvent(const PlatformMouseEvent&); + virtual bool handleMouseReleaseEvent(const PlatformMouseEvent&); + virtual bool handleWheelEvent(const PlatformWheelEvent&); + virtual bool handleKeyEvent(const PlatformKeyboardEvent&); + + // PopupContainer methods + + // Show the popup + void showPopup(FrameView*); + + // Show the popup in the specified rect for the specified frame. + // Note: this code was somehow arbitrarily factored-out of the Popup class + // so WebViewImpl can create a PopupContainer. + void show(const IntRect&, FrameView*, int index); + + // Hide the popup. Do not call this directly: use client->hidePopup(). + void hidePopup(); + + // Compute size of widget and children. + void layout(); + + // Sets whether the PopupMenuClient should be told to change its text when a + // new item is selected (by using the arrow keys). Default is true. + void setTextOnIndexChange(bool); + + // Sets whether the selection should be accepted when the popup menu is + // closed (through ESC being pressed or the focus going away). Default + // is true. Note that when TAB is pressed, the selection is always + // accepted regardless of this setting. + void setAcceptOnAbandon(bool); + + // Sets 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. Default is false, causing the first/last item to stay + // selected. + void setLoopSelectionNavigation(bool); + + PopupListBox* listBox() const { return m_listBox.get(); } + + // Refresh the popup values from the PopupMenuClient. + void refresh(); + + private: + friend class WTF::RefCounted<PopupContainer>; + + PopupContainer(PopupMenuClient*, bool focusOnShow); + ~PopupContainer(); + + // Paint the border. + void paintBorder(GraphicsContext*, const IntRect&); + + RefPtr<PopupListBox> m_listBox; + + // Whether the window showing this popup should be focused when shown. + bool m_focusOnShow; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/chromium/PopupMenuPrivate.h b/WebCore/platform/chromium/PopupMenuPrivate.h new file mode 100644 index 0000000..fb8f850 --- /dev/null +++ b/WebCore/platform/chromium/PopupMenuPrivate.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2008, 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 PopupMenuPrivate_h +#define PopupMenuPrivate_h + +#include "RefPtr.h" + +namespace WebCore { + + class PopupContainer; + + struct PopupMenuPrivate { + RefPtr<PopupContainer> popup; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/chromium/SSLKeyGeneratorChromium.cpp b/WebCore/platform/chromium/SSLKeyGeneratorChromium.cpp new file mode 100644 index 0000000..fdedf2b --- /dev/null +++ b/WebCore/platform/chromium/SSLKeyGeneratorChromium.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008, 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 "SSLKeyGenerator.h" + +namespace WebCore { + +// These are defined in webkit/glue/localized_strings.cpp. +String keygenMenuHighGradeKeySize(); +String keygenMenuMediumGradeKeySize(); + +// Returns the key sizes supported by the HTML keygen tag. The first string +// is displayed as the default key size in the keygen menu. +Vector<String> supportedKeySizes() +{ + Vector<String> sizes(2); + sizes[0] = keygenMenuHighGradeKeySize(); + sizes[1] = keygenMenuMediumGradeKeySize(); + return sizes; +} + +// FIXME: implement signedPublicKeyAndChallengeString here. + +} // namespace WebCore diff --git a/WebCore/platform/chromium/ScrollbarThemeChromium.cpp b/WebCore/platform/chromium/ScrollbarThemeChromium.cpp new file mode 100644 index 0000000..de40572 --- /dev/null +++ b/WebCore/platform/chromium/ScrollbarThemeChromium.cpp @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2009 Google 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 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 "ScrollbarThemeChromium.h" + +#include "ChromiumBridge.h" +#include "PlatformMouseEvent.h" +#include "Scrollbar.h" +#include "ScrollbarClient.h" +#include "ScrollbarThemeComposite.h" + +// ----------------------------------------------------------------------------- +// This file contains scrollbar theme code that is cross platform. Additional +// members of ScrollbarThemeChromium can be found in the platform specific files +// ----------------------------------------------------------------------------- + +namespace WebCore { + +ScrollbarTheme* ScrollbarTheme::nativeTheme() +{ + static ScrollbarThemeChromium theme; + return &theme; +} + +ScrollbarThemeChromium::ScrollbarThemeChromium() +{ +} + +ScrollbarThemeChromium::~ScrollbarThemeChromium() +{ +} + +void ScrollbarThemeChromium::themeChanged() +{ +} + +bool ScrollbarThemeChromium::hasThumb(Scrollbar* scrollbar) +{ + // This method is just called as a paint-time optimization to see if + // painting the thumb can be skipped. We don't have to be exact here. + return thumbLength(scrollbar) > 0; +} + +IntRect ScrollbarThemeChromium::backButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool) +{ + // Windows and Linux just have single arrows. + if (part == BackButtonEndPart) + return IntRect(); + + IntSize size = buttonSize(scrollbar); + return IntRect(scrollbar->x(), scrollbar->y(), size.width(), size.height()); +} + +IntRect ScrollbarThemeChromium::forwardButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool) +{ + // Windows and Linux just have single arrows. + 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 ScrollbarThemeChromium::trackRect(Scrollbar* scrollbar, bool) +{ + IntSize bs = buttonSize(scrollbar); + int thickness = scrollbarThickness(); + if (scrollbar->orientation() == HorizontalScrollbar) { + if (scrollbar->width() < 2 * thickness) + return IntRect(); + return IntRect(scrollbar->x() + bs.width(), scrollbar->y(), scrollbar->width() - 2 * bs.width(), thickness); + } + if (scrollbar->height() < 2 * thickness) + return IntRect(); + return IntRect(scrollbar->x(), scrollbar->y() + bs.height(), thickness, scrollbar->height() - 2 * bs.height()); +} + +void ScrollbarThemeChromium::paintTrackBackground(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect) +{ + // Just assume a forward track part. We only paint the track as a single piece when there is no thumb. + if (!hasThumb(scrollbar)) + paintTrackPiece(context, scrollbar, rect, ForwardTrackPart); +} + +void ScrollbarThemeChromium::paintTickmarks(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect) +{ + if (scrollbar->orientation() != VerticalScrollbar) + return; + + if (rect.height() <= 0 || rect.width() <= 0) + return; // nothing to draw on. + + // Get the tickmarks for the frameview. + Vector<IntRect> tickmarks; + scrollbar->client()->getTickmarks(tickmarks); + if (!tickmarks.size()) + return; + + // Get the image for the tickmarks. + static RefPtr<Image> dash = Image::loadPlatformResource("tickmarkDash"); + if (dash->isNull()) { + ASSERT_NOT_REACHED(); + return; + } + + context->save(); + + 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(); + + // Calculate how far down (in pixels) the tick-mark should appear. + const int yPos = rect.topLeft().y() + (rect.height() * percent); + + IntPoint tick(scrollbar->x(), yPos); + context->drawImage(dash.get(), tick); + } + + context->restore(); +} + +void ScrollbarThemeChromium::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 ScrollbarThemeChromium::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& evt) +{ + return evt.shiftKey() && evt.button() == LeftButton; +} + +IntSize ScrollbarThemeChromium::buttonSize(Scrollbar* scrollbar) +{ + // Our desired rect is essentially thickness by thickness. + + // Our actual rect will shrink to half the available space when we have < 2 + // times thickness pixels left. This allows the scrollbar to scale down + // and function even at tiny sizes. + + int thickness = scrollbarThickness(); + +#if !defined(__linux__) + // In layout test mode, we force the button "girth" (i.e., the length of + // the button along the axis of the scrollbar) to be a fixed size. + // FIXME: This is retarded! scrollbarThickness is already fixed in layout + // test mode so that should be enough to result in repeatable results, but + // preserving this hack avoids having to rebaseline pixel tests. + const int kLayoutTestModeGirth = 17; + + int girth = ChromiumBridge::layoutTestMode() ? kLayoutTestModeGirth : thickness; +#else + int girth = thickness; +#endif + + if (scrollbar->orientation() == HorizontalScrollbar) { + int width = scrollbar->width() < 2 * girth ? scrollbar->width() / 2 : girth; + return IntSize(width, thickness); + } + + int height = scrollbar->height() < 2 * girth ? scrollbar->height() / 2 : girth; + return IntSize(thickness, height); +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/ScrollbarThemeChromium.h b/WebCore/platform/chromium/ScrollbarThemeChromium.h new file mode 100644 index 0000000..87ffd44 --- /dev/null +++ b/WebCore/platform/chromium/ScrollbarThemeChromium.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2008, 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 ScrollbarThemeChromium_h +#define ScrollbarThemeChromium_h + +#include "ScrollbarThemeComposite.h" + +namespace WebCore { + + class PlatformMouseEvent; + + // This class contains the Chromium scrollbar implementations for Windows + // and Linux. All of the symbols here in must be defined somewhere in the + // code and we manage the platform specific parts by linking in different, + // platform specific, files. Methods that we shared across platforms are + // implemented in ScrollbarThemeChromium.cpp + class ScrollbarThemeChromium : public ScrollbarThemeComposite { + public: + ScrollbarThemeChromium(); + virtual ~ScrollbarThemeChromium(); + + virtual int scrollbarThickness(ScrollbarControlSize = RegularScrollbar); + + virtual void themeChanged(); + + virtual bool invalidateOnMouseEnterExit(); + + protected: + virtual bool hasButtons(Scrollbar*) { return true; } + 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 void paintScrollCorner(ScrollView*, GraphicsContext*, const IntRect&); + virtual bool shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent&); + + virtual void paintTrackBackground(GraphicsContext*, Scrollbar*, const IntRect&); + virtual void paintTrackPiece(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart); + virtual void paintButton(GraphicsContext*, Scrollbar*, const IntRect&, ScrollbarPart); + virtual void paintThumb(GraphicsContext*, Scrollbar*, const IntRect&); + virtual void paintTickmarks(GraphicsContext*, Scrollbar*, const IntRect&); + + private: + IntSize buttonSize(Scrollbar*); + + int getThemeState(Scrollbar*, ScrollbarPart) const; + int getThemeArrowState(Scrollbar*, ScrollbarPart) const; + int getClassicThemeState(Scrollbar*, ScrollbarPart) const; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp b/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp new file mode 100644 index 0000000..95d0f78 --- /dev/null +++ b/WebCore/platform/chromium/ScrollbarThemeChromiumLinux.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2008, 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 "ScrollbarThemeChromium.h" + +#include "NotImplemented.h" +#include "PlatformContextSkia.h" +#include "PlatformMouseEvent.h" +#include "Scrollbar.h" +#include "TransformationMatrix.h" + +#include "gtkdrawing.h" +#include <gtk/gtk.h> +#include "skia/ext/GdkSkia.h" + +namespace WebCore { + +int ScrollbarThemeChromium::scrollbarThickness(ScrollbarControlSize controlSize) +{ + static int size = 0; + if (!size) { + MozGtkScrollbarMetrics metrics; + moz_gtk_get_scrollbar_metrics(&metrics); + size = metrics.slider_width; + } + return size; +} + +bool ScrollbarThemeChromium::invalidateOnMouseEnterExit() +{ + notImplemented(); + return false; +} + +// Given an uninitialised widget state object, set the members such that it's +// sane for drawing scrollbars +static void initMozState(GtkWidgetState* mozState) +{ + mozState->active = true; + mozState->focused = false; + mozState->inHover = false; + mozState->disabled = false; + mozState->isDefault = false; + mozState->canDefault = false; + mozState->depressed = false; + mozState->curpos = 0; + mozState->maxpos = 0; +} + +// Paint a GTK widget +// gc: context to draw onto +// rect: the area of the widget +// widget_type: the type of widget to draw +// flags: widget dependent flags (e.g. direction of scrollbar arrows etc) +// +// See paintMozWiget in RenderThemeGtk.cpp for an explanation of the clipping. +static void paintScrollbarWidget(GraphicsContext* gc, const IntRect& rect, + GtkThemeWidgetType widget_type, gint flags) +{ + PlatformContextSkia* pcs = gc->platformContext(); + + GdkRectangle gdkRect = { rect.x(), rect.y(), rect.width(), rect.height() }; + + const SkIRect clip_region = pcs->canvas()->getTotalClip().getBounds(); + TransformationMatrix ctm = gc->getCTM().inverse(); + IntPoint pos = ctm.mapPoint( + IntPoint(SkScalarRound(clip_region.fLeft), SkScalarRound(clip_region.fTop))); + GdkRectangle gdkClipRect; + gdkClipRect.x = pos.x(); + gdkClipRect.y = pos.y(); + gdkClipRect.width = clip_region.width(); + gdkClipRect.height = clip_region.height(); + + gdk_rectangle_intersect(&gdkRect, &gdkClipRect, &gdkClipRect); + + GtkWidgetState mozState; + initMozState(&mozState); + + moz_gtk_widget_paint(widget_type, pcs->gdk_skia(), &gdkRect, &gdkClipRect, + &mozState, flags, GTK_TEXT_DIR_LTR); +} + +void ScrollbarThemeChromium::paintTrackPiece(GraphicsContext* gc, Scrollbar* scrollbar, + const IntRect& rect, ScrollbarPart partType) +{ + const bool horz = scrollbar->orientation() == HorizontalScrollbar; + const GtkThemeWidgetType track_type = + horz ? MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL : MOZ_GTK_SCROLLBAR_TRACK_VERTICAL; + paintScrollbarWidget(gc, rect, track_type, 0); +} + +void ScrollbarThemeChromium::paintButton(GraphicsContext* gc, Scrollbar* scrollbar, + const IntRect& rect, ScrollbarPart part) +{ + // FIXME: It appears the either we're upsetting GTK by forcing WebKit sizes + // on it, or the buttons expect the track to be drawn under them. Either + // way, we end up with unpainted pixels which are upsetting the pixel + // tests. Thus we paint green under the buttons to, at least, make the + // pixel output the same between debug and opt builds. + SkPaint paint; + paint.setARGB(255, 0, 255, 128); + SkRect skrect; + skrect.set(rect.x(), rect.y(), rect.x() + rect.width() - 1, rect.y() + rect.height() - 1); + gc->platformContext()->canvas()->drawRect(skrect, paint); + + const bool horz = scrollbar->orientation() == HorizontalScrollbar; + gint flags = horz ? 0 : MOZ_GTK_STEPPER_VERTICAL; + flags |= ForwardButtonEndPart == part ? MOZ_GTK_STEPPER_DOWN : 0; + paintScrollbarWidget(gc, rect, MOZ_GTK_SCROLLBAR_BUTTON, flags); +} + +void ScrollbarThemeChromium::paintThumb(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect) +{ + const bool horz = scrollbar->orientation() == HorizontalScrollbar; + const GtkThemeWidgetType thumb_type = + horz ? MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL : MOZ_GTK_SCROLLBAR_THUMB_VERTICAL; + paintScrollbarWidget(gc, rect, thumb_type, 0); +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/ScrollbarThemeChromiumWin.cpp b/WebCore/platform/chromium/ScrollbarThemeChromiumWin.cpp new file mode 100644 index 0000000..0337f63 --- /dev/null +++ b/WebCore/platform/chromium/ScrollbarThemeChromiumWin.cpp @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2009 Google 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 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 "ScrollbarThemeChromium.h" + +#include <windows.h> +#include <vsstyle.h> + +#include "ChromiumBridge.h" +#include "GraphicsContext.h" +#include "PlatformContextSkia.h" +#include "PlatformMouseEvent.h" +#include "Scrollbar.h" +#include "WindowsVersion.h" + +namespace WebCore { + +// The scrollbar size in DumpRenderTree on the Mac - so we can match their +// layout results. Entries are for regular, small, and mini scrollbars. +// Metrics obtained using [NSScroller scrollerWidthForControlSize:] +static const int kMacScrollbarSize[3] = { 15, 11, 15 }; + +int ScrollbarThemeChromium::scrollbarThickness(ScrollbarControlSize controlSize) +{ + static int thickness; + if (!thickness) { + if (ChromiumBridge::layoutTestMode()) + return kMacScrollbarSize[controlSize]; + thickness = GetSystemMetrics(SM_CXVSCROLL); + } + return thickness; +} + +bool ScrollbarThemeChromium::invalidateOnMouseEnterExit() +{ + return isVistaOrNewer(); +} + +void ScrollbarThemeChromium::paintTrackPiece(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart partType) +{ + bool horz = scrollbar->orientation() == HorizontalScrollbar; + + int partId; + if (partType == BackTrackPart) + partId = horz ? SBP_UPPERTRACKHORZ : SBP_UPPERTRACKVERT; + else + partId = horz ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT; + + IntRect alignRect = trackRect(scrollbar, false); + + // Draw the track area before/after the thumb on the scroll bar. + ChromiumBridge::paintScrollbarTrack( + gc, + partId, + getThemeState(scrollbar, partType), + getClassicThemeState(scrollbar, partType), + rect, + alignRect); +} + +void ScrollbarThemeChromium::paintButton(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part) +{ + bool horz = scrollbar->orientation() == HorizontalScrollbar; + + int partId; + if (part == BackButtonStartPart || part == ForwardButtonStartPart) + partId = horz ? DFCS_SCROLLLEFT : DFCS_SCROLLUP; + else + partId = horz ? DFCS_SCROLLRIGHT : DFCS_SCROLLDOWN; + + // Draw the thumb (the box you drag in the scroll bar to scroll). + ChromiumBridge::paintScrollbarArrow( + gc, + getThemeArrowState(scrollbar, part), + partId | getClassicThemeState(scrollbar, part), + rect); +} + +void ScrollbarThemeChromium::paintThumb(GraphicsContext* gc, Scrollbar* scrollbar, const IntRect& rect) +{ + bool horz = scrollbar->orientation() == HorizontalScrollbar; + + // Draw the thumb (the box you drag in the scroll bar to scroll). + ChromiumBridge::paintScrollbarThumb( + gc, + horz ? SBP_THUMBBTNHORZ : SBP_THUMBBTNVERT, + getThemeState(scrollbar, ThumbPart), + getClassicThemeState(scrollbar, ThumbPart), + rect); + + // Draw the gripper (the three little lines on the thumb). + ChromiumBridge::paintScrollbarThumb( + gc, + horz ? SBP_GRIPPERHORZ : SBP_GRIPPERVERT, + getThemeState(scrollbar, ThumbPart), + getClassicThemeState(scrollbar, ThumbPart), + rect); +} + +int ScrollbarThemeChromium::getThemeState(Scrollbar* scrollbar, ScrollbarPart part) const +{ + // When dragging the thumb, draw thumb pressed and other segments normal + // regardless of where the cursor actually is. See also four places in + // getThemeArrowState(). + if (scrollbar->pressedPart() == ThumbPart) { + if (part == ThumbPart) + return SCRBS_PRESSED; + return isVistaOrNewer() ? SCRBS_HOVER : SCRBS_NORMAL; + } + if (!scrollbar->enabled()) + return SCRBS_DISABLED; + if (scrollbar->hoveredPart() != part || part == BackTrackPart || part == ForwardTrackPart) + return (scrollbar->hoveredPart() == NoPart || !isVistaOrNewer()) ? SCRBS_NORMAL : SCRBS_HOVER; + if (scrollbar->pressedPart() == NoPart) + return SCRBS_HOT; + return (scrollbar->pressedPart() == part) ? SCRBS_PRESSED : SCRBS_NORMAL; +} + +int ScrollbarThemeChromium::getThemeArrowState(Scrollbar* scrollbar, ScrollbarPart part) const +{ + // We could take advantage of knowing the values in the state enum to write + // some simpler code, but treating the state enum as a black box seems + // clearer and more future-proof. + if (part == BackButtonStartPart || part == ForwardButtonStartPart) { + if (scrollbar->orientation() == HorizontalScrollbar) { + if (scrollbar->pressedPart() == ThumbPart) + return !isVistaOrNewer() ? ABS_LEFTNORMAL : ABS_LEFTHOVER; + if (!scrollbar->enabled()) + return ABS_LEFTDISABLED; + if (scrollbar->hoveredPart() != part) + return ((scrollbar->hoveredPart() == NoPart) || !isVistaOrNewer()) ? ABS_LEFTNORMAL : ABS_LEFTHOVER; + if (scrollbar->pressedPart() == NoPart) + return ABS_LEFTHOT; + return (scrollbar->pressedPart() == part) ? + ABS_LEFTPRESSED : ABS_LEFTNORMAL; + } + if (scrollbar->pressedPart() == ThumbPart) + return !isVistaOrNewer() ? ABS_UPNORMAL : ABS_UPHOVER; + if (!scrollbar->enabled()) + return ABS_UPDISABLED; + if (scrollbar->hoveredPart() != part) + return ((scrollbar->hoveredPart() == NoPart) || !isVistaOrNewer()) ? ABS_UPNORMAL : ABS_UPHOVER; + if (scrollbar->pressedPart() == NoPart) + return ABS_UPHOT; + return (scrollbar->pressedPart() == part) ? ABS_UPPRESSED : ABS_UPNORMAL; + } + if (scrollbar->orientation() == HorizontalScrollbar) { + if (scrollbar->pressedPart() == ThumbPart) + return !isVistaOrNewer() ? ABS_RIGHTNORMAL : ABS_RIGHTHOVER; + if (!scrollbar->enabled()) + return ABS_RIGHTDISABLED; + if (scrollbar->hoveredPart() != part) + return ((scrollbar->hoveredPart() == NoPart) || !isVistaOrNewer()) ? ABS_RIGHTNORMAL : ABS_RIGHTHOVER; + if (scrollbar->pressedPart() == NoPart) + return ABS_RIGHTHOT; + return (scrollbar->pressedPart() == part) ? ABS_RIGHTPRESSED : ABS_RIGHTNORMAL; + } + if (scrollbar->pressedPart() == ThumbPart) + return !isVistaOrNewer() ? ABS_DOWNNORMAL : ABS_DOWNHOVER; + if (!scrollbar->enabled()) + return ABS_DOWNDISABLED; + if (scrollbar->hoveredPart() != part) + return ((scrollbar->hoveredPart() == NoPart) || !isVistaOrNewer()) ? ABS_DOWNNORMAL : ABS_DOWNHOVER; + if (scrollbar->pressedPart() == NoPart) + return ABS_DOWNHOT; + return (scrollbar->pressedPart() == part) ? ABS_DOWNPRESSED : ABS_DOWNNORMAL; +} + +int ScrollbarThemeChromium::getClassicThemeState(Scrollbar* scrollbar, ScrollbarPart part) const +{ + // When dragging the thumb, draw the buttons normal even when hovered. + if (scrollbar->pressedPart() == ThumbPart) + return 0; + if (!scrollbar->enabled()) + return DFCS_INACTIVE; + if (scrollbar->hoveredPart() != part || part == BackTrackPart || part == ForwardTrackPart) + return 0; + if (scrollbar->pressedPart() == NoPart) + return DFCS_HOT; + return (scrollbar->pressedPart() == part) ? (DFCS_PUSHED | DFCS_FLAT) : 0; +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/SearchPopupMenuChromium.cpp b/WebCore/platform/chromium/SearchPopupMenuChromium.cpp new file mode 100644 index 0000000..89bfddd --- /dev/null +++ b/WebCore/platform/chromium/SearchPopupMenuChromium.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2008, 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 "SearchPopupMenu.h" + +#include "AtomicString.h" +#include "NotImplemented.h" + +namespace WebCore { + +SearchPopupMenu::SearchPopupMenu(PopupMenuClient* client) + : PopupMenu(client) +{ +} + +bool SearchPopupMenu::enabled() +{ + return false; +} + +void SearchPopupMenu::saveRecentSearches(const AtomicString& name, const Vector<String>& searchItems) +{ + notImplemented(); +} + +void SearchPopupMenu::loadRecentSearches(const AtomicString& name, Vector<String>& searchItems) +{ + notImplemented(); +} + +} // namespace WebCore diff --git a/WebCore/platform/gtk/SystemTimeLinux.cpp b/WebCore/platform/chromium/SharedTimerChromium.cpp index 45caddd..5a6a000 100644 --- a/WebCore/platform/gtk/SystemTimeLinux.cpp +++ b/WebCore/platform/chromium/SharedTimerChromium.cpp @@ -1,7 +1,5 @@ /* * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. - * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -22,23 +20,29 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" -#include "SystemTime.h" +#include "SharedTimer.h" -#include <sys/time.h> +#include "ChromiumBridge.h" namespace WebCore { -double currentTime() -{ - struct timeval aTimeval; - struct timezone aTimezone; +void setSharedTimerFiredFunction(void (*f)()) +{ + ChromiumBridge::setSharedTimerFiredFunction(f); +} - gettimeofday( &aTimeval, &aTimezone ); - return (double)aTimeval.tv_sec + (double)(aTimeval.tv_usec / 1000000.0 ); +void setSharedTimerFireTime(double fireTime) +{ + ChromiumBridge::setSharedTimerFireTime(fireTime); } +void stopSharedTimer() +{ + ChromiumBridge::stopSharedTimer(); } + +} // namespace WebCore diff --git a/WebCore/platform/chromium/SoundChromiumPosix.cpp b/WebCore/platform/chromium/SoundChromiumPosix.cpp new file mode 100644 index 0000000..2767d76 --- /dev/null +++ b/WebCore/platform/chromium/SoundChromiumPosix.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2008, 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 "Sound.h" + +#include "NotImplemented.h" + +namespace WebCore { + +void systemBeep() +{ + notImplemented(); +} + +} // namespace WebCore diff --git a/WebCore/platform/wx/SystemTimeWx.cpp b/WebCore/platform/chromium/SoundChromiumWin.cpp index 41e6ad7..e145477 100644 --- a/WebCore/platform/wx/SystemTimeWx.cpp +++ b/WebCore/platform/chromium/SoundChromiumWin.cpp @@ -1,5 +1,6 @@ /* - * Copyright (C) 2007 Robin Dunn. All rights reserved. + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,16 +25,15 @@ */ #include "config.h" -#include "SystemTime.h" +#include "Sound.h" -#include <wx/datetime.h> +#include <windows.h> namespace WebCore { -double currentTime() +void systemBeep() { - wxDateTime now = wxDateTime::UNow(); - return (double)now.GetTicks() + (double)(now.GetMillisecond() / 1000.0); + MessageBeep(static_cast<UINT>(-1)); } -} +} // namespace WebCore diff --git a/WebCore/platform/chromium/SystemTimeChromium.cpp b/WebCore/platform/chromium/SystemTimeChromium.cpp new file mode 100644 index 0000000..52ac262 --- /dev/null +++ b/WebCore/platform/chromium/SystemTimeChromium.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008, 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 "SystemTime.h" + +#include "ChromiumBridge.h" +#include "NotImplemented.h" + +namespace WebCore { + +// Get the current time in seconds since epoch. +double currentTime() +{ + return ChromiumBridge::currentTime(); +} + +float userIdleTime() +{ + // Needed for back/forward cache, which we currently have disabled. + notImplemented(); + return 0.0F; +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/TemporaryLinkStubs.cpp b/WebCore/platform/chromium/TemporaryLinkStubs.cpp new file mode 100644 index 0000000..4a028da --- /dev/null +++ b/WebCore/platform/chromium/TemporaryLinkStubs.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2008, 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 "KURL.h" +#include "NotImplemented.h" +#include "SharedBuffer.h" + +namespace WebCore { + +String signedPublicKeyAndChallengeString(unsigned, const String&, const KURL&) { notImplemented(); return String(); } +void getSupportedKeySizes(Vector<String>&) { notImplemented(); } + +String KURL::fileSystemPath() const { notImplemented(); return String(); } + +PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String&) { notImplemented(); return 0; } + +} // namespace WebCore + +namespace WTF { + +#if !defined(__linux__) +void scheduleDispatchFunctionsOnMainThread() { notImplemented(); } +#endif + +} // namespace WTF diff --git a/WebCore/platform/chromium/WidgetChromium.cpp b/WebCore/platform/chromium/WidgetChromium.cpp new file mode 100644 index 0000000..4e16e68 --- /dev/null +++ b/WebCore/platform/chromium/WidgetChromium.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2008, 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 "Widget.h" + +#include "Assertions.h" +#include "ChromiumBridge.h" + +namespace WebCore { + +Widget::Widget(PlatformWidget widget) +{ + init(widget); +} + +Widget::~Widget() +{ + ASSERT(!parent()); +} + +void Widget::show() +{ +} + +void Widget::hide() +{ +} + +void Widget::setCursor(const Cursor& cursor) +{ + ChromiumBridge::widgetSetCursor(this, cursor); +} + +void Widget::paint(GraphicsContext*, const IntRect&) +{ +} + +void Widget::setFocus() +{ + ChromiumBridge::widgetSetFocus(this); +} + +void Widget::setIsSelected(bool) +{ +} + +IntRect Widget::frameRect() const +{ + return m_frame; +} + +void Widget::setFrameRect(const IntRect& rect) +{ + m_frame = rect; +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/WindowsVersion.cpp b/WebCore/platform/chromium/WindowsVersion.cpp new file mode 100644 index 0000000..a9632cb --- /dev/null +++ b/WebCore/platform/chromium/WindowsVersion.cpp @@ -0,0 +1,52 @@ +// 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 "WindowsVersion.h" + +#include <windows.h> + +namespace WebCore { + +bool isVistaOrNewer() +{ + // Cache the result to avoid asking every time. + static bool haveResult = false; + static bool result = false; + if (!haveResult) { + OSVERSIONINFO versionInfo; + versionInfo.dwOSVersionInfoSize = sizeof(versionInfo); + GetVersionEx(&versionInfo); + + haveResult = true; + result = versionInfo.dwMajorVersion >= 6; + } + return result; +} + +} // namespace WebCore diff --git a/WebCore/platform/chromium/WindowsVersion.h b/WebCore/platform/chromium/WindowsVersion.h new file mode 100644 index 0000000..3b2010a --- /dev/null +++ b/WebCore/platform/chromium/WindowsVersion.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008, 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 WindowsVersion_h +#define WindowsVersion_h + +namespace WebCore { + + bool isVistaOrNewer(); + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/graphics/BitmapImage.cpp b/WebCore/platform/graphics/BitmapImage.cpp index 4b21de0..45b32ab 100644 --- a/WebCore/platform/graphics/BitmapImage.cpp +++ b/WebCore/platform/graphics/BitmapImage.cpp @@ -30,22 +30,18 @@ #include "FloatRect.h" #include "ImageObserver.h" #include "IntRect.h" +#include "MIMETypeRegistry.h" #include "PlatformString.h" -#include "SystemTime.h" #include "Timer.h" +#include <wtf/CurrentTime.h> #include <wtf/Vector.h> -#include "MIMETypeRegistry.h" namespace WebCore { -// Animated images >5MB are considered large enough that we'll only hang on to -// one frame at a time. -const unsigned cLargeAnimationCutoff = 5242880; - -// When an animated image is more than five minutes out of date, don't try to -// resync on repaint, so we don't waste CPU cycles on an edge case the user -// doesn't care about. -const double cAnimationResyncCutoff = 5 * 60; +static int frameBytes(const IntSize& frameSize) +{ + return frameSize.width() * frameSize.height() * 4; +} BitmapImage::BitmapImage(ImageObserver* observer) : Image(observer) @@ -75,40 +71,42 @@ BitmapImage::~BitmapImage() stopAnimation(); } -void BitmapImage::destroyDecodedData(bool incremental, bool preserveNearbyFrames) +void BitmapImage::destroyDecodedData(bool destroyAll) { - // Destroy the cached images and release them. - if (m_frames.size()) { - int sizeChange = 0; - int frameSize = m_size.width() * m_size.height() * 4; - const size_t nextFrame = (preserveNearbyFrames && frameCount()) ? ((m_currentFrame + 1) % frameCount()) : 0; - for (unsigned i = incremental ? m_frames.size() - 1 : 0; i < m_frames.size(); i++) { - if (m_frames[i].m_frame && (!preserveNearbyFrames || (i != m_currentFrame && i != nextFrame))) { - sizeChange -= frameSize; - m_frames[i].clear(); - } - } - - // We just always invalidate our platform data, even in the incremental case. - // This could be better, but it's not a big deal. - m_isSolidColor = false; - invalidatePlatformData(); - - if (sizeChange) { - m_decodedSize += sizeChange; - if (imageObserver()) - imageObserver()->decodedSizeChanged(this, sizeChange); - } - - if (!incremental) { - // Reset the image source, since Image I/O has an underlying cache that it uses - // while animating that it seems to never clear. -#if !PLATFORM(SGL) - m_source.clear(); - m_source.setData(m_data.get(), m_allDataReceived); -#endif - } + int framesCleared = 0; + const size_t clearBeforeFrame = destroyAll ? m_frames.size() : m_currentFrame; + for (size_t i = 0; i < clearBeforeFrame; ++i) { + // The underlying frame isn't actually changing (we're just trying to + // save the memory for the framebuffer data), so we don't need to clear + // the metadata. + if (m_frames[i].clear(false)) + ++framesCleared; } + + destroyMetadataAndNotify(framesCleared); + + m_source.clear(destroyAll, clearBeforeFrame, m_data.get(), m_allDataReceived); + return; +} + +void BitmapImage::destroyDecodedDataIfNecessary(bool destroyAll) +{ + // Animated images >5MB are considered large enough that we'll only hang on + // to one frame at a time. + static const unsigned cLargeAnimationCutoff = 5242880; + if (frameCount() * frameBytes(m_size) > cLargeAnimationCutoff) + destroyDecodedData(destroyAll); +} + +void BitmapImage::destroyMetadataAndNotify(int framesCleared) +{ + m_isSolidColor = false; + invalidatePlatformData(); + + const int deltaBytes = framesCleared * -frameBytes(m_size); + m_decodedSize += deltaBytes; + if (deltaBytes && imageObserver()) + imageObserver()->decodedSizeChanged(this, deltaBytes); } void BitmapImage::cacheFrame(size_t index) @@ -129,19 +127,14 @@ void BitmapImage::cacheFrame(size_t index) m_frames[index].m_duration = m_source.frameDurationAtIndex(index); m_frames[index].m_hasAlpha = m_source.frameHasAlphaAtIndex(index); - int sizeChange; - if (index) { - IntSize frameSize = m_source.frameSizeAtIndex(index); - if (frameSize != m_size) - m_hasUniformFrameSize = false; - sizeChange = m_frames[index].m_frame ? frameSize.width() * frameSize.height() * 4 : 0; - } else - sizeChange = m_frames[index].m_frame ? m_size.width() * m_size.height() * 4 : 0; - - if (sizeChange) { - m_decodedSize += sizeChange; + const IntSize frameSize(index ? m_source.frameSizeAtIndex(index) : m_size); + if (frameSize != m_size) + m_hasUniformFrameSize = false; + if (m_frames[index].m_frame) { + const int deltaBytes = frameBytes(frameSize); + m_decodedSize += deltaBytes; if (imageObserver()) - imageObserver()->decodedSizeChanged(this, sizeChange); + imageObserver()->decodedSizeChanged(this, deltaBytes); } } @@ -163,7 +156,9 @@ IntSize BitmapImage::currentFrameSize() const bool BitmapImage::dataChanged(bool allDataReceived) { - destroyDecodedData(true); + // Because we're modifying the current frame, clear its (now possibly + // inaccurate) metadata as well. + destroyMetadataAndNotify((!m_frames.isEmpty() && m_frames[m_frames.size() - 1].clear(true)) ? 1 : 0); // Feed all the data we've seen so far to the image decoder. m_allDataReceived = allDataReceived; @@ -179,6 +174,11 @@ bool BitmapImage::dataChanged(bool allDataReceived) return isSizeAvailable(); } +String BitmapImage::filenameExtension() const +{ + return m_source.filenameExtension(); +} + size_t BitmapImage::frameCount() { if (!m_haveFrameCount) { @@ -274,16 +274,18 @@ void BitmapImage::startAnimation(bool catchUpIfNecessary) m_desiredFrameStartTime = time + currentDuration; } else { m_desiredFrameStartTime += currentDuration; - // If we're too far behind, the user probably doesn't care about - // resyncing and we could burn a lot of time looping through frames - // below. Just reset the timings. + + // When an animated image is more than five minutes out of date, the + // user probably doesn't care about resyncing and we could burn a lot of + // time looping through frames below. Just reset the timings. + const double cAnimationResyncCutoff = 5 * 60; if ((time - m_desiredFrameStartTime) > cAnimationResyncCutoff) m_desiredFrameStartTime = time + currentDuration; } // Don't advance the animation to an incomplete frame. size_t nextFrame = (m_currentFrame + 1) % frameCount(); - if (!frameIsCompleteAtIndex(nextFrame)) + if (!m_allDataReceived && !frameIsCompleteAtIndex(nextFrame)) return; // Don't advance past the last frame if we haven't decoded the whole image @@ -369,14 +371,12 @@ void BitmapImage::resetAnimation() m_repetitionsComplete = 0; m_desiredFrameStartTime = 0; m_animationFinished = false; - int frameSize = m_size.width() * m_size.height() * 4; - + // For extremely large animations, when the animation is reset, we just throw everything away. - if (frameCount() * frameSize > cLargeAnimationCutoff) - destroyDecodedData(); + destroyDecodedDataIfNecessary(true); } -void BitmapImage::advanceAnimation(Timer<BitmapImage>* timer) +void BitmapImage::advanceAnimation(Timer<BitmapImage>*) { internalAdvanceAnimation(false); // At this point the image region has been marked dirty, and if it's @@ -394,45 +394,32 @@ bool BitmapImage::internalAdvanceAnimation(bool skippingFrames) if (!skippingFrames && imageObserver()->shouldPauseAnimation(this)) return false; - m_currentFrame++; + ++m_currentFrame; + bool advancedAnimation = true; + bool destroyAll = false; if (m_currentFrame >= frameCount()) { ++m_repetitionsComplete; + // Get the repetition count again. If we weren't able to get a // repetition count before, we should have decoded the whole image by // now, so it should now be available. if (repetitionCount(true) && m_repetitionsComplete >= m_repetitionCount) { m_animationFinished = true; m_desiredFrameStartTime = 0; - m_currentFrame--; - if (skippingFrames) { - // Uh oh. We tried to skip past the end of the animation. We'd - // better draw this last frame. - notifyObserverAndTrimDecodedData(); - } - return false; + --m_currentFrame; + advancedAnimation = false; + } else { + m_currentFrame = 0; + destroyAll = true; } - m_currentFrame = 0; } + destroyDecodedDataIfNecessary(destroyAll); - if (!skippingFrames) - notifyObserverAndTrimDecodedData(); - - return true; -} - -void BitmapImage::notifyObserverAndTrimDecodedData() -{ - // Notify our observer that the animation has advanced. - imageObserver()->animationAdvanced(this); - - // For large animated images, go ahead and throw away frames as we go to - // save footprint. - int frameSize = m_size.width() * m_size.height() * 4; - if (frameCount() * frameSize > cLargeAnimationCutoff) { - // Destroy all of our frames and just redecode every time. We save the - // current frame since we'll need it in draw() anyway. - destroyDecodedData(false, true); - } + // We need to draw this frame if we advanced to it while not skipping, or if + // while trying to skip frames we hit the last frame and thus had to stop. + if (skippingFrames != advancedAnimation) + imageObserver()->animationAdvanced(this); + return advancedAnimation; } } diff --git a/WebCore/platform/graphics/BitmapImage.h b/WebCore/platform/graphics/BitmapImage.h index c5f2a72..110aec4 100644 --- a/WebCore/platform/graphics/BitmapImage.h +++ b/WebCore/platform/graphics/BitmapImage.h @@ -80,10 +80,12 @@ struct FrameData : Noncopyable { ~FrameData() { - clear(); + clear(true); } - void clear(); + // Clear the cached image data on the frame, and (optionally) the metadata. + // Returns whether there was cached image data to clear. + bool clear(bool clearMetadata); NativeImagePtr m_frame; bool m_haveMetadata; @@ -118,6 +120,7 @@ public: IntSize currentFrameSize() const; virtual bool dataChanged(bool allDataReceived); + virtual String filenameExtension() const; // It may look unusual that there is no start animation call as public API. This is because // we start and stop animating lazily. Animation begins whenever someone draws the image. It will @@ -164,7 +167,7 @@ protected: #endif virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); #if PLATFORM(QT) || PLATFORM(WX) - virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform, + virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator, const FloatRect& destRect); #endif size_t currentFrame() const { return m_currentFrame; } @@ -177,18 +180,22 @@ protected: // Decodes and caches a frame. Never accessed except internally. void cacheFrame(size_t index); - // Called to invalidate all our cached data. If an image is loading - // incrementally, we only invalidate the last cached frame. For large - // animated images, where we throw away the decoded data after every frame, - // |preserveNearbyFrames| can be set to preserve the current frame's data - // and eliminate some unnecessary duplicated decoding work. This also - // preserves the next frame's data, if available. In most cases this has no - // effect; either that frame isn't decoded yet, or it's already been - // destroyed by a previous call. But when we fall behind on the very first - // animation loop and startAnimation() needs to "catch up" one or more - // frames, this briefly preserves some of that decoding work, to ease CPU - // load and make it less likely that we'll keep falling behind. - virtual void destroyDecodedData(bool incremental = false, bool preserveNearbyFrames = false); + // Called to invalidate cached data. When |destroyAll| is true, we wipe out + // the entire frame buffer cache and tell the image source to destroy + // everything; this is used when e.g. we want to free some room in the image + // cache. If |destroyAll| is false, we only delete frames up to the current + // one; this is used while animating large images to keep memory footprint + // low without redecoding the whole image on every frame. + virtual void destroyDecodedData(bool destroyAll = true); + + // If the image is large enough, calls destroyDecodedData() and passes + // |destroyAll| along. + void destroyDecodedDataIfNecessary(bool destroyAll); + + // Generally called by destroyDecodedData(), destroys whole-image metadata + // and notifies observers that the memory footprint has (hopefully) + // decreased by |framesCleared| times the size (in bytes) of a frame. + void destroyMetadataAndNotify(int framesCleared); // Whether or not size is available yet. bool isSizeAvailable(); @@ -206,9 +213,6 @@ protected: // Returns whether the animation was advanced. bool internalAdvanceAnimation(bool skippingFrames); - // Helper for internalAdvanceAnimation(). - void notifyObserverAndTrimDecodedData(); - // Handle platform-specific data void initPlatformData(); void invalidatePlatformData(); diff --git a/WebCore/platform/graphics/Color.cpp b/WebCore/platform/graphics/Color.cpp index 3ff589d..c7e11ee 100644 --- a/WebCore/platform/graphics/Color.cpp +++ b/WebCore/platform/graphics/Color.cpp @@ -38,8 +38,17 @@ using namespace WTF; namespace WebCore { -const RGBA32 lightenedBlack = 0xFF545454; -const RGBA32 darkenedWhite = 0xFFABABAB; +#if !COMPILER(MSVC) +const RGBA32 Color::black; +const RGBA32 Color::white; +const RGBA32 Color::darkGray; +const RGBA32 Color::gray; +const RGBA32 Color::lightGray; +const RGBA32 Color::transparent; +#endif + +static const RGBA32 lightenedBlack = 0xFF545454; +static const RGBA32 darkenedWhite = 0xFFABABAB; RGBA32 makeRGB(int r, int g, int b) { @@ -51,7 +60,7 @@ RGBA32 makeRGBA(int r, int g, int b, int a) return max(0, min(a, 255)) << 24 | max(0, min(r, 255)) << 16 | max(0, min(g, 255)) << 8 | max(0, min(b, 255)); } -int colorFloatToRGBAByte(float f) +static int colorFloatToRGBAByte(float f) { // We use lroundf and 255 instead of nextafterf(256, 0) to match CG's rounding return max(0, min(static_cast<int>(lroundf(255.0f * f)), 255)); diff --git a/WebCore/platform/graphics/FloatPoint.cpp b/WebCore/platform/graphics/FloatPoint.cpp index 3ca0361..564ea86 100644 --- a/WebCore/platform/graphics/FloatPoint.cpp +++ b/WebCore/platform/graphics/FloatPoint.cpp @@ -27,7 +27,7 @@ #include "config.h" #include "FloatPoint.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "FloatConversion.h" #include "IntPoint.h" @@ -37,7 +37,7 @@ FloatPoint::FloatPoint(const IntPoint& p) : m_x(p.x()), m_y(p.y()) { } -FloatPoint FloatPoint::matrixTransform(const AffineTransform& transform) const +FloatPoint FloatPoint::matrixTransform(const TransformationMatrix& transform) const { double newX, newY; transform.map(static_cast<double>(m_x), static_cast<double>(m_y), &newX, &newY); diff --git a/WebCore/platform/graphics/FloatPoint.h b/WebCore/platform/graphics/FloatPoint.h index 6b3c769..35b3036 100644 --- a/WebCore/platform/graphics/FloatPoint.h +++ b/WebCore/platform/graphics/FloatPoint.h @@ -28,6 +28,8 @@ #define FloatPoint_h #include "FloatSize.h" +#include "IntPoint.h" +#include <wtf/MathExtras.h> #include <wtf/Platform.h> #if PLATFORM(CG) @@ -59,7 +61,7 @@ struct SkPoint; namespace WebCore { -class AffineTransform; +class TransformationMatrix; class IntPoint; class FloatPoint { @@ -102,7 +104,7 @@ public: FloatPoint(const SkPoint&); #endif - FloatPoint matrixTransform(const AffineTransform&) const; + FloatPoint matrixTransform(const TransformationMatrix&) const; private: float m_x, m_y; @@ -146,6 +148,11 @@ inline bool operator!=(const FloatPoint& a, const FloatPoint& b) return a.x() != b.x() || a.y() != b.y(); } +inline IntPoint roundedIntPoint(const FloatPoint& p) +{ + return IntPoint(static_cast<int>(roundf(p.x())), static_cast<int>(roundf(p.y()))); +} + } #endif diff --git a/WebCore/platform/graphics/FloatPoint3D.cpp b/WebCore/platform/graphics/FloatPoint3D.cpp index ec52d40..e3ba422 100644 --- a/WebCore/platform/graphics/FloatPoint3D.cpp +++ b/WebCore/platform/graphics/FloatPoint3D.cpp @@ -23,14 +23,15 @@ #if ENABLE(SVG) #include <math.h> +#include "FloatPoint.h" #include "FloatPoint3D.h" namespace WebCore { FloatPoint3D::FloatPoint3D() - : m_x(0.f) - , m_y(0.f) - , m_z(0.f) + : m_x(0) + , m_y(0) + , m_z(0) { } @@ -41,43 +42,22 @@ FloatPoint3D::FloatPoint3D(float x, float y, float z) { } -float FloatPoint3D::x() const +FloatPoint3D::FloatPoint3D(const FloatPoint& p) + : m_x(p.x()) + , m_y(p.y()) + , m_z(0) { - return m_x; -} - -void FloatPoint3D::setX(float x) -{ - m_x = x; -} - -float FloatPoint3D::y() const -{ - return m_y; -} - -void FloatPoint3D::setY(float y) -{ - m_y = y; -} - -float FloatPoint3D::z() const -{ - return m_z; -} - -void FloatPoint3D::setZ(float z) -{ - m_z = z; } void FloatPoint3D::normalize() { float length = sqrtf(m_x * m_x + m_y * m_y + m_z * m_z); - m_x /= length; - m_y /= length; - m_z /= length; + if (length != 0) { + m_x /= length; + m_y /= length; + m_z /= length; + } } } // namespace WebCore diff --git a/WebCore/platform/graphics/FloatPoint3D.h b/WebCore/platform/graphics/FloatPoint3D.h index 55f70e7..184e914 100644 --- a/WebCore/platform/graphics/FloatPoint3D.h +++ b/WebCore/platform/graphics/FloatPoint3D.h @@ -26,19 +26,22 @@ namespace WebCore { +class FloatPoint; + class FloatPoint3D { public: FloatPoint3D(); FloatPoint3D(float x, float y, float z); + FloatPoint3D(const FloatPoint&); - float x() const; - void setX(float x); + float x() const { return m_x; } + void setX(float x) { m_x = x; } - float y() const; - void setY(float y); + float y() const { return m_y; } + void setY(float y) { m_y = y; } - float z() const; - void setZ(float z); + float z() const { return m_z; } + void setZ(float z) { m_z = z; } void normalize(); diff --git a/WebCore/platform/graphics/FloatQuad.cpp b/WebCore/platform/graphics/FloatQuad.cpp new file mode 100644 index 0000000..a32d8ab --- /dev/null +++ b/WebCore/platform/graphics/FloatQuad.cpp @@ -0,0 +1,60 @@ +/* + * 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. + * 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 "FloatQuad.h" + +#include <algorithm> + +using std::max; +using std::min; + +namespace WebCore { + +static inline float min4(float a, float b, float c, float d) +{ + return min(min(a, b), min(c, d)); +} + +static inline float max4(float a, float b, float c, float d) +{ + return max(max(a, b), max(c, d)); +} + +FloatRect FloatQuad::boundingBox() const +{ + float left = min4(m_p1.x(), m_p2.x(), m_p3.x(), m_p4.x()); + float top = min4(m_p1.y(), m_p2.y(), m_p3.y(), m_p4.y()); + + float right = max4(m_p1.x(), m_p2.x(), m_p3.x(), m_p4.x()); + float bottom = max4(m_p1.y(), m_p2.y(), m_p3.y(), m_p4.y()); + + return FloatRect(left, top, right - left, bottom - top); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/FloatQuad.h b/WebCore/platform/graphics/FloatQuad.h new file mode 100644 index 0000000..e05b27d --- /dev/null +++ b/WebCore/platform/graphics/FloatQuad.h @@ -0,0 +1,138 @@ +/* + * 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FloatQuad_h +#define FloatQuad_h + +#include "FloatPoint.h" +#include "FloatRect.h" +#include "IntRect.h" + +namespace WebCore { + +// A FloatQuad is a collection of 4 points, often representing the result of +// mapping a rectangle through transforms. When initialized from a rect, the +// points are in clockwise order from top left. +class FloatQuad { +public: + FloatQuad() + { + } + + FloatQuad(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& p3, const FloatPoint& p4) + : m_p1(p1) + , m_p2(p2) + , m_p3(p3) + , m_p4(p4) + { + } + + FloatQuad(const FloatRect& inRect) + : m_p1(inRect.location()) + , m_p2(inRect.right(), inRect.y()) + , m_p3(inRect.right(), inRect.bottom()) + , m_p4(inRect.x(), inRect.bottom()) + { + } + + FloatPoint p1() const { return m_p1; } + FloatPoint p2() const { return m_p2; } + FloatPoint p3() const { return m_p3; } + FloatPoint p4() const { return m_p4; } + + void setP1(const FloatPoint& p) { m_p1 = p; } + void setP2(const FloatPoint& p) { m_p2 = p; } + void setP3(const FloatPoint& p) { m_p3 = p; } + void setP4(const FloatPoint& p) { m_p4 = p; } + + // isEmpty tests that the bounding box is empty. This will not identify + // "slanted" empty quads. + bool isEmpty() const { return boundingBox().isEmpty(); } + + FloatRect boundingBox() const; + IntRect enclosingBoundingBox() const + { + return enclosingIntRect(boundingBox()); + } + + void move(const FloatSize& offset) + { + m_p1 += offset; + m_p2 += offset; + m_p3 += offset; + m_p4 += offset; + } + + void move(float dx, float dy) + { + m_p1.move(dx, dy); + m_p2.move(dx, dy); + m_p3.move(dx, dy); + m_p4.move(dx, dy); + } + +private: + FloatPoint m_p1; + FloatPoint m_p2; + FloatPoint m_p3; + FloatPoint m_p4; +}; + +inline FloatQuad& operator+=(FloatQuad& a, const FloatSize& b) +{ + a.move(b); + return a; +} + +inline FloatQuad& operator-=(FloatQuad& a, const FloatSize& b) +{ + a.move(-b.width(), -b.height()); + return a; +} + +inline bool operator==(const FloatQuad& a, const FloatQuad& b) +{ + return a.p1() == b.p1() && + a.p2() == b.p2() && + a.p3() == b.p3() && + a.p4() == b.p4(); +} + +inline bool operator!=(const FloatQuad& a, const FloatQuad& b) +{ + return a.p1() != b.p1() || + a.p2() != b.p2() || + a.p3() != b.p3() || + a.p4() != b.p4(); +} + +} // namespace WebCore + + +#endif // FloatQuad_h + diff --git a/WebCore/platform/graphics/FloatRect.cpp b/WebCore/platform/graphics/FloatRect.cpp index ec7b3fa..532f719 100644 --- a/WebCore/platform/graphics/FloatRect.cpp +++ b/WebCore/platform/graphics/FloatRect.cpp @@ -119,4 +119,16 @@ IntRect enclosingIntRect(const FloatRect& rect) return IntRect(l, t, r - l, b - t); } +FloatRect mapRect(const FloatRect& r, const FloatRect& srcRect, const FloatRect& destRect) +{ + if (srcRect.width() == 0 || srcRect.height() == 0) + return FloatRect(); + + float widthScale = destRect.width() / srcRect.width(); + float heightScale = destRect.height() / srcRect.height(); + return FloatRect(destRect.x() + (r.x() - srcRect.x()) * widthScale, + destRect.y() + (r.y() - srcRect.y()) * heightScale, + r.width() * widthScale, r.height() * heightScale); +} + } diff --git a/WebCore/platform/graphics/FloatRect.h b/WebCore/platform/graphics/FloatRect.h index 11e3791..a87c949 100644 --- a/WebCore/platform/graphics/FloatRect.h +++ b/WebCore/platform/graphics/FloatRect.h @@ -167,6 +167,7 @@ inline FloatRect unionRect(const FloatRect& a, const FloatRect& b) return c; } + inline bool operator==(const FloatRect& a, const FloatRect& b) { return a.location() == b.location() && a.size() == b.size(); @@ -179,6 +180,9 @@ inline bool operator!=(const FloatRect& a, const FloatRect& b) IntRect enclosingIntRect(const FloatRect&); +// Map rect r from srcRect to an equivalent rect in destRect. +FloatRect mapRect(const FloatRect& r, const FloatRect& srcRect, const FloatRect& destRect); + } #endif diff --git a/WebCore/platform/graphics/FloatSize.h b/WebCore/platform/graphics/FloatSize.h index cf1e1c5..6e792b6 100644 --- a/WebCore/platform/graphics/FloatSize.h +++ b/WebCore/platform/graphics/FloatSize.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. * Copyright (C) 2005 Nokia. All rights reserved. + * 2008 Eric Seidel <eric@webkit.org> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -67,6 +68,12 @@ public: m_height > other.m_height ? m_height : other.m_height); } + FloatSize shrunkTo(const FloatSize& other) const + { + return FloatSize(m_width < other.m_width ? m_width : other.m_width, + m_height < other.m_height ? m_height : other.m_height); + } + #if PLATFORM(CG) explicit FloatSize(const CGSize&); // don't do this implicitly since it's lossy operator CGSize() const; diff --git a/WebCore/platform/graphics/Font.cpp b/WebCore/platform/graphics/Font.cpp index 138e322..f8bec82 100644 --- a/WebCore/platform/graphics/Font.cpp +++ b/WebCore/platform/graphics/Font.cpp @@ -38,6 +38,7 @@ using namespace Unicode; namespace WebCore { +#if USE(FONT_FAST_PATH) const uint8_t Font::gRoundingHackCharacterTable[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*\t*/, 1 /*\n*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*-*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*?*/, @@ -50,6 +51,7 @@ const uint8_t Font::gRoundingHackCharacterTable[256] = { }; Font::CodePath Font::s_codePath = Auto; +#endif // ============================================================================================ // Font Implementation (Cross-Platform Portion) @@ -133,132 +135,6 @@ bool Font::operator==(const Font& other) const && (m_fontList ? m_fontList->generation() : 0) == (other.m_fontList ? other.m_fontList->generation() : 0); } -const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCaps) const -{ - bool useSmallCapsFont = forceSmallCaps; - if (m_fontDescription.smallCaps()) { - UChar32 upperC = Unicode::toUpper(c); - if (upperC != c) { - c = upperC; - useSmallCapsFont = true; - } - } - - if (mirror) - c = mirroredChar(c); - - unsigned pageNumber = (c / GlyphPage::size); - - GlyphPageTreeNode* node = pageNumber ? m_pages.get(pageNumber) : m_pageZero; - if (!node) { - node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber); - if (pageNumber) - m_pages.set(pageNumber, node); - else - m_pageZero = node; - } - - GlyphPage* page; - if (!useSmallCapsFont) { - // Fastest loop, for the common case (not small caps). - while (true) { - page = node->page(); - if (page) { - const GlyphData& data = page->glyphDataForCharacter(c); - if (data.fontData) - return data; - if (node->isSystemFallback()) - break; - } - - // Proceed with the fallback list. - node = node->getChild(fontDataAt(node->level()), pageNumber); - if (pageNumber) - m_pages.set(pageNumber, node); - else - m_pageZero = node; - } - } else { - while (true) { - page = node->page(); - if (page) { - const GlyphData& data = page->glyphDataForCharacter(c); - if (data.fontData) { - // The smallCapsFontData function should not normally return 0. - // But if it does, we will just render the capital letter big. - const SimpleFontData* smallCapsFontData = data.fontData->smallCapsFontData(m_fontDescription); - if (!smallCapsFontData) - return data; - - GlyphPageTreeNode* smallCapsNode = GlyphPageTreeNode::getRootChild(smallCapsFontData, pageNumber); - const GlyphPage* smallCapsPage = smallCapsNode->page(); - if (smallCapsPage) { - const GlyphData& data = smallCapsPage->glyphDataForCharacter(c); - if (data.fontData) - return data; - } - - // Do not attempt system fallback off the smallCapsFontData. This is the very unlikely case that - // a font has the lowercase character but the small caps font does not have its uppercase version. - return smallCapsFontData->missingGlyphData(); - } - - if (node->isSystemFallback()) - break; - } - - // Proceed with the fallback list. - node = node->getChild(fontDataAt(node->level()), pageNumber); - if (pageNumber) - m_pages.set(pageNumber, node); - else - m_pageZero = node; - } - } - - ASSERT(page); - ASSERT(node->isSystemFallback()); - - // System fallback is character-dependent. When we get here, we - // know that the character in question isn't in the system fallback - // font's glyph page. Try to lazily create it here. - UChar codeUnits[2]; - int codeUnitsLength; - if (c <= 0xFFFF) { - UChar c16 = c; - if (Font::treatAsSpace(c16)) - codeUnits[0] = ' '; - else if (Font::treatAsZeroWidthSpace(c16)) - codeUnits[0] = zeroWidthSpace; - else - codeUnits[0] = c16; - codeUnitsLength = 1; - } else { - codeUnits[0] = U16_LEAD(c); - codeUnits[1] = U16_TRAIL(c); - codeUnitsLength = 2; - } - const SimpleFontData* characterFontData = FontCache::getFontDataForCharacters(*this, codeUnits, codeUnitsLength); - if (useSmallCapsFont) - characterFontData = characterFontData->smallCapsFontData(m_fontDescription); - if (characterFontData) { - // Got the fallback glyph and font. - GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page(); - const GlyphData& data = fallbackPage && fallbackPage->glyphDataForCharacter(c).fontData ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData(); - // Cache it so we don't have to do system fallback again next time. - if (!useSmallCapsFont) - page->setGlyphDataForCharacter(c, data.glyph, data.fontData); - return data; - } - - // Even system fallback can fail; use the missing glyph in that case. - // FIXME: It would be nicer to use the missing glyph from the last resort font instead. - const GlyphData& data = primaryFont()->missingGlyphData(); - if (!useSmallCapsFont) - page->setGlyphDataForCharacter(c, data.glyph, data.fontData); - return data; -} - void Font::cachePrimaryFont() const { ASSERT(m_fontList); @@ -293,184 +169,12 @@ void Font::update(PassRefPtr<FontSelector> fontSelector) const m_pages.clear(); } -int Font::width(const TextRun& run) const -{ - return lroundf(floatWidth(run)); -} - -int Font::ascent() const -{ - return primaryFont()->ascent(); -} - -int Font::descent() const -{ - return primaryFont()->descent(); -} - -int Font::lineSpacing() const -{ - return primaryFont()->lineSpacing(); -} - -int Font::lineGap() const -{ - return primaryFont()->lineGap(); -} - -float Font::xHeight() const -{ - return primaryFont()->xHeight(); -} - -unsigned Font::unitsPerEm() const -{ - return primaryFont()->unitsPerEm(); -} - -int Font::spaceWidth() const -{ - return (int)ceilf(primaryFont()->m_adjustedSpaceWidth + m_letterSpacing); -} - bool Font::isFixedPitch() const { ASSERT(m_fontList); return m_fontList->isFixedPitch(this); } -void Font::setCodePath(CodePath p) -{ - s_codePath = p; -} - -Font::CodePath Font::codePath() -{ - return s_codePath; -} - -bool Font::canUseGlyphCache(const TextRun& run) const -{ - switch (s_codePath) { - case Auto: - break; - case Simple: - return true; - case Complex: - return false; - } - - // Start from 0 since drawing and highlighting also measure the characters before run->from - for (int i = 0; i < run.length(); i++) { - const UChar c = run[i]; - if (c < 0x300) // U+0300 through U+036F Combining diacritical marks - continue; - if (c <= 0x36F) - return false; - - if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha - continue; - if (c <= 0x05CF) - return false; - - if (c < 0x0600) // U+0600 through U+1059 Arabic, Syriac, Thaana, Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar - continue; - if (c <= 0x1059) - return false; - - if (c < 0x1100) // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose; Modern Korean will be precomposed as a result of step A) - continue; - if (c <= 0x11FF) - return false; - - if (c < 0x1780) // U+1780 through U+18AF Khmer, Mongolian - continue; - if (c <= 0x18AF) - return false; - - if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0) - continue; - if (c <= 0x194F) - return false; - - if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols - continue; - if (c <= 0x20FF) - return false; - - if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks - continue; - if (c <= 0xFE2F) - return false; - } - - return true; - -} - -void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const -{ - // This glyph buffer holds our glyphs+advances+font data for each glyph. - GlyphBuffer glyphBuffer; - - float startX = point.x(); - WidthIterator it(this, run); - it.advance(from); - float beforeWidth = it.m_runWidthSoFar; - it.advance(to, &glyphBuffer); - - // We couldn't generate any glyphs for the run. Give up. - if (glyphBuffer.isEmpty()) - return; - - float afterWidth = it.m_runWidthSoFar; - - if (run.rtl()) { - float finalRoundingWidth = it.m_finalRoundingWidth; - it.advance(run.length()); - startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth; - } else - startX += beforeWidth; - - // Swap the order of the glyphs if right-to-left. - if (run.rtl()) - for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end) - glyphBuffer.swap(i, end); - - // Calculate the starting point of the glyphs to be displayed by adding - // all the advances up to the first glyph. - FloatPoint startPoint(startX, point.y()); - drawGlyphBuffer(context, glyphBuffer, run, startPoint); -} - -void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, - const TextRun& run, const FloatPoint& point) const -{ - // Draw each contiguous run of glyphs that use the same font data. - const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); - FloatSize offset = glyphBuffer.offsetAt(0); - FloatPoint startPoint(point); - float nextX = startPoint.x(); - int lastFrom = 0; - int nextGlyph = 0; - while (nextGlyph < glyphBuffer.size()) { - const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); - FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph); - if (nextFontData != fontData || nextOffset != offset) { - drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); - - lastFrom = nextGlyph; - fontData = nextFontData; - offset = nextOffset; - startPoint.setX(nextX); - } - nextX += glyphBuffer.advanceAt(nextGlyph); - nextGlyph++; - } - - drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); -} - void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const { // Don't draw anything while we are using custom fonts that are in the process of loading. @@ -486,10 +190,12 @@ void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoi } #endif +#if USE(FONT_FAST_PATH) if (canUseGlyphCache(run)) - drawSimpleText(context, run, point, from, to); - else - drawComplexText(context, run, point, from, to); + return drawSimpleText(context, run, point, from, to); +#endif + + return drawComplexText(context, run, point, from, to); } float Font::floatWidth(const TextRun& run) const @@ -499,8 +205,11 @@ float Font::floatWidth(const TextRun& run) const return floatWidthUsingSVGFont(run); #endif +#if USE(FONT_FAST_PATH) if (canUseGlyphCache(run)) return floatWidthForSimpleText(run, 0); +#endif + return floatWidthForComplexText(run); } @@ -513,16 +222,13 @@ float Font::floatWidth(const TextRun& run, int extraCharsAvailable, int& charsCo charsConsumed = run.length(); glyphName = ""; + +#if USE(FONT_FAST_PATH) if (canUseGlyphCache(run)) return floatWidthForSimpleText(run, 0); - return floatWidthForComplexText(run); -} +#endif -float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer) const -{ - WidthIterator it(this, run); - it.advance(run.length(), glyphBuffer); - return it.m_runWidthSoFar; + return floatWidthForComplexText(run); } FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& point, int h, int from, int to) const @@ -533,27 +239,13 @@ FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& point, #endif to = (to == -1 ? run.length() : to); + +#if USE(FONT_FAST_PATH) if (canUseGlyphCache(run)) return selectionRectForSimpleText(run, point, h, from, to); - return selectionRectForComplexText(run, point, h, from, to); -} +#endif -FloatRect Font::selectionRectForSimpleText(const TextRun& run, const IntPoint& point, int h, int from, int to) const -{ - WidthIterator it(this, run); - it.advance(from); - float beforeWidth = it.m_runWidthSoFar; - it.advance(to); - float afterWidth = it.m_runWidthSoFar; - - // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning - if (run.rtl()) { - it.advance(run.length()); - float totalWidth = it.m_runWidthSoFar; - return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h); - } else { - return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h); - } + return selectionRectForComplexText(run, point, h, from, to); } int Font::offsetForPosition(const TextRun& run, int x, bool includePartialGlyphs) const @@ -563,52 +255,12 @@ int Font::offsetForPosition(const TextRun& run, int x, bool includePartialGlyphs return offsetForPositionForTextUsingSVGFont(run, x, includePartialGlyphs); #endif +#if USE(FONT_FAST_PATH) if (canUseGlyphCache(run)) return offsetForPositionForSimpleText(run, x, includePartialGlyphs); - return offsetForPositionForComplexText(run, x, includePartialGlyphs); -} - -int Font::offsetForPositionForSimpleText(const TextRun& run, int x, bool includePartialGlyphs) const -{ - float delta = (float)x; - - WidthIterator it(this, run); - GlyphBuffer localGlyphBuffer; - unsigned offset; - if (run.rtl()) { - delta -= floatWidthForSimpleText(run, 0); - while (1) { - offset = it.m_currentCharacter; - float w; - if (!it.advanceOneCharacter(w, &localGlyphBuffer)) - break; - delta += w; - if (includePartialGlyphs) { - if (delta - w / 2 >= 0) - break; - } else { - if (delta >= 0) - break; - } - } - } else { - while (1) { - offset = it.m_currentCharacter; - float w; - if (!it.advanceOneCharacter(w, &localGlyphBuffer)) - break; - delta -= w; - if (includePartialGlyphs) { - if (delta + w / 2 <= 0) - break; - } else { - if (delta <= 0) - break; - } - } - } +#endif - return offset; + return offsetForPositionForComplexText(run, x, includePartialGlyphs); } #if ENABLE(SVG_FONTS) diff --git a/WebCore/platform/graphics/Font.h b/WebCore/platform/graphics/Font.h index a99ce12..1bfee8f 100644 --- a/WebCore/platform/graphics/Font.h +++ b/WebCore/platform/graphics/Font.h @@ -3,6 +3,7 @@ * (C) 2000 Antti Koivisto (koivisto@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) * Copyright (C) 2003, 2006, 2007 Apple Computer, Inc. + * Copyright (C) 2008 Holger Hans Peter Freyther * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -26,11 +27,12 @@ #include "TextRun.h" #include "FontDescription.h" +#include "SimpleFontData.h" #include <wtf/HashMap.h> +#include <wtf/MathExtras.h> #if PLATFORM(QT) -#include <QtGui/qfont.h> -#include <QtGui/qfontmetrics.h> +#include <QFont> #endif namespace WebCore { @@ -45,18 +47,18 @@ class GlyphBuffer; class GlyphPageTreeNode; class GraphicsContext; class IntPoint; -class SimpleFontData; class SVGFontElement; struct GlyphData; +const unsigned defaultUnitsPerEm = 1000; + class Font { public: Font(); Font(const FontDescription&, short letterSpacing, short wordSpacing); -#if !PLATFORM(QT) - Font(const FontPlatformData&, bool isPrinting); // This constructor is only used if the platform wants to start with a native font. -#endif + // This constructor is only used if the platform wants to start with a native font. + Font(const FontPlatformData&, bool isPrinting); ~Font(); Font(const Font&); @@ -76,7 +78,7 @@ public: void drawText(GraphicsContext*, const TextRun&, const FloatPoint&, int from = 0, int to = -1) const; - int width(const TextRun&) const; + int width(const TextRun& run) const { return lroundf(floatWidth(run)); } float floatWidth(const TextRun&) const; float floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const; @@ -87,13 +89,8 @@ public: short wordSpacing() const { return m_wordSpacing; } short letterSpacing() const { return m_letterSpacing; } -#if !PLATFORM(QT) void setWordSpacing(short s) { m_wordSpacing = s; } void setLetterSpacing(short s) { m_letterSpacing = s; } -#else - void setWordSpacing(short s); - void setLetterSpacing(short s); -#endif bool isFixedPitch() const; bool isPrinterFont() const { return m_fontDescription.usePrinterFont(); } @@ -105,27 +102,19 @@ public: bool italic() const { return m_fontDescription.italic(); } FontWeight weight() const { return m_fontDescription.weight(); } -#if !PLATFORM(QT) bool isPlatformFont() const { return m_isPlatformFont; } -#endif - -#if PLATFORM(QT) - inline const QFont &font() const { return m_font; } - inline const QFont &scFont() const { return m_scFont; } -#endif // Metrics that we query the FontFallbackList for. - int ascent() const; - int descent() const; + int ascent() const { return primaryFont()->ascent(); } + int descent() const { return primaryFont()->descent(); } int height() const { return ascent() + descent(); } - int lineSpacing() const; - int lineGap() const; - float xHeight() const; - unsigned unitsPerEm() const; - int spaceWidth() const; + int lineSpacing() const { return primaryFont()->lineSpacing(); } + int lineGap() const { return primaryFont()->lineGap(); } + float xHeight() const { return primaryFont()->xHeight(); } + unsigned unitsPerEm() const { return primaryFont()->unitsPerEm(); } + int spaceWidth() const { return (int)ceilf(primaryFont()->m_adjustedSpaceWidth + m_letterSpacing); } int tabWidth() const { return 8 * spaceWidth(); } -#if !PLATFORM(QT) const SimpleFontData* primaryFont() const { if (!m_cachedPrimaryFont) cachePrimaryFont(); @@ -137,9 +126,11 @@ public: // Used for complex text, and does not utilize the glyph map cache. const FontData* fontDataForCharacters(const UChar*, int length) const; +#if PLATFORM(QT) + QFont font() const; +#endif + private: - bool canUseGlyphCache(const TextRun&) const; - void drawSimpleText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const; #if ENABLE(SVG_FONTS) void drawTextUsingSVGFont(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const; float floatWidthUsingSVGFont(const TextRun&) const; @@ -147,24 +138,28 @@ private: FloatRect selectionRectForTextUsingSVGFont(const TextRun&, const IntPoint&, int h, int from, int to) const; int offsetForPositionForTextUsingSVGFont(const TextRun&, int position, bool includePartialGlyphs) const; #endif + +#if USE(FONT_FAST_PATH) + bool canUseGlyphCache(const TextRun&) const; + void drawSimpleText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const; void drawGlyphs(GraphicsContext*, const SimpleFontData*, const GlyphBuffer&, int from, int to, const FloatPoint&) const; void drawGlyphBuffer(GraphicsContext*, const GlyphBuffer&, const TextRun&, const FloatPoint&) const; - void drawComplexText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const; float floatWidthForSimpleText(const TextRun&, GlyphBuffer*) const; - float floatWidthForComplexText(const TextRun&) const; int offsetForPositionForSimpleText(const TextRun&, int position, bool includePartialGlyphs) const; - int offsetForPositionForComplexText(const TextRun&, int position, bool includePartialGlyphs) const; FloatRect selectionRectForSimpleText(const TextRun&, const IntPoint&, int h, int from, int to) const; +#endif + + void drawComplexText(GraphicsContext*, const TextRun&, const FloatPoint&, int from, int to) const; + float floatWidthForComplexText(const TextRun&) const; + int offsetForPositionForComplexText(const TextRun&, int position, bool includePartialGlyphs) const; FloatRect selectionRectForComplexText(const TextRun&, const IntPoint&, int h, int from, int to) const; void cachePrimaryFont() const; -#endif + friend struct WidthIterator; public: -#if PLATFORM(QT) - FontSelector* fontSelector() const { return 0; } -#else // Useful for debugging the different font rendering code paths. +#if USE(FONT_FAST_PATH) enum CodePath { Auto, Simple, Complex }; static void setCodePath(CodePath); static CodePath codePath(); @@ -175,9 +170,9 @@ public: { return (((c & ~0xFF) == 0 && gRoundingHackCharacterTable[c])); } +#endif FontSelector* fontSelector() const; -#endif static bool treatAsSpace(UChar c) { return c == ' ' || c == '\t' || c == '\n' || c == 0x00A0; } static bool treatAsZeroWidthSpace(UChar c) { return c < 0x20 || (c >= 0x7F && c < 0xA0) || c == 0x200e || c == 0x200f || (c >= 0x202a && c <= 0x202e) || c == 0xFFFC; } @@ -188,21 +183,13 @@ public: private: FontDescription m_fontDescription; -#if !PLATFORM(QT) mutable RefPtr<FontFallbackList> m_fontList; mutable HashMap<int, GlyphPageTreeNode*> m_pages; mutable GlyphPageTreeNode* m_pageZero; mutable const SimpleFontData* m_cachedPrimaryFont; -#endif short m_letterSpacing; short m_wordSpacing; -#if !PLATFORM(QT) bool m_isPlatformFont; -#else - QFont m_font; - QFont m_scFont; - int m_spaceWidth; -#endif }; } diff --git a/WebCore/platform/graphics/FontCache.cpp b/WebCore/platform/graphics/FontCache.cpp index 1c5a987..2d219be 100644 --- a/WebCore/platform/graphics/FontCache.cpp +++ b/WebCore/platform/graphics/FontCache.cpp @@ -37,11 +37,22 @@ #include "StringHash.h" #include <wtf/HashMap.h> #include <wtf/ListHashSet.h> +#include <wtf/StdLibExtras.h> using namespace WTF; namespace WebCore { +FontCache* fontCache() +{ + DEFINE_STATIC_LOCAL(FontCache, globalFontCache, ()); + return &globalFontCache; +} + +FontCache::FontCache() +{ +} + struct FontPlatformDataCacheKey { FontPlatformDataCacheKey(const AtomicString& family = AtomicString(), unsigned size = 0, unsigned weight = 0, bool italic = false, bool isPrinterFont = false, FontRenderingMode renderingMode = NormalRenderingMode) @@ -104,7 +115,7 @@ struct FontPlatformDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformDataC static const bool emptyValueIsZero = true; static const FontPlatformDataCacheKey& emptyValue() { - static FontPlatformDataCacheKey key(nullAtom); + DEFINE_STATIC_LOCAL(FontPlatformDataCacheKey, key, (nullAtom)); return key; } static void constructDeletedValue(FontPlatformDataCacheKey& slot) @@ -124,21 +135,24 @@ static FontPlatformDataCache* gFontPlatformDataCache = 0; static const AtomicString& alternateFamilyName(const AtomicString& familyName) { // Alias Courier <-> Courier New - static AtomicString courier("Courier"), courierNew("Courier New"); + DEFINE_STATIC_LOCAL(AtomicString, courier, ("Courier")); + DEFINE_STATIC_LOCAL(AtomicString, courierNew, ("Courier New")); if (equalIgnoringCase(familyName, courier)) return courierNew; if (equalIgnoringCase(familyName, courierNew)) return courier; // Alias Times and Times New Roman. - static AtomicString times("Times"), timesNewRoman("Times New Roman"); + DEFINE_STATIC_LOCAL(AtomicString, times, ("Times")); + DEFINE_STATIC_LOCAL(AtomicString, timesNewRoman, ("Times New Roman")); if (equalIgnoringCase(familyName, times)) return timesNewRoman; if (equalIgnoringCase(familyName, timesNewRoman)) return times; // Alias Arial and Helvetica - static AtomicString arial("Arial"), helvetica("Helvetica"); + DEFINE_STATIC_LOCAL(AtomicString, arial, ("Arial")); + DEFINE_STATIC_LOCAL(AtomicString, helvetica, ("Helvetica")); if (equalIgnoringCase(familyName, arial)) return helvetica; if (equalIgnoringCase(familyName, helvetica)) @@ -202,7 +216,7 @@ struct FontDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformData> { static const bool needsDestruction = true; static const FontPlatformData& emptyValue() { - static FontPlatformData key; + DEFINE_STATIC_LOCAL(FontPlatformData, key, ()); return key; } static void constructDeletedValue(FontPlatformData& slot) diff --git a/WebCore/platform/graphics/FontCache.h b/WebCore/platform/graphics/FontCache.h index 816fe64..8820045 100644 --- a/WebCore/platform/graphics/FontCache.h +++ b/WebCore/platform/graphics/FontCache.h @@ -51,45 +51,51 @@ class SimpleFontData; class FontCache { public: - static const FontData* getFontData(const Font&, int& familyIndex, FontSelector*); - static void releaseFontData(const SimpleFontData*); + friend FontCache* fontCache(); + + const FontData* getFontData(const Font&, int& familyIndex, FontSelector*); + void releaseFontData(const SimpleFontData*); // This method is implemented by the platform. // FIXME: Font data returned by this method never go inactive because callers don't track and release them. - static const SimpleFontData* getFontDataForCharacters(const Font&, const UChar* characters, int length); + const SimpleFontData* getFontDataForCharacters(const Font&, const UChar* characters, int length); // Also implemented by the platform. - static void platformInit(); + void platformInit(); #if PLATFORM(WIN) - static IMLangFontLink2* getFontLinkInterface(); + IMLangFontLink2* getFontLinkInterface(); #endif - static void getTraitsInFamily(const AtomicString&, Vector<unsigned>&); + void getTraitsInFamily(const AtomicString&, Vector<unsigned>&); - static FontPlatformData* getCachedFontPlatformData(const FontDescription&, const AtomicString& family, bool checkingAlternateName = false); - static SimpleFontData* getCachedFontData(const FontPlatformData*); - static FontPlatformData* getLastResortFallbackFont(const FontDescription&); + FontPlatformData* getCachedFontPlatformData(const FontDescription&, const AtomicString& family, bool checkingAlternateName = false); + SimpleFontData* getCachedFontData(const FontPlatformData*); + FontPlatformData* getLastResortFallbackFont(const FontDescription&); - static void addClient(FontSelector*); - static void removeClient(FontSelector*); + void addClient(FontSelector*); + void removeClient(FontSelector*); - static unsigned generation(); - static void invalidate(); + unsigned generation(); + void invalidate(); - static size_t fontDataCount(); - static size_t inactiveFontDataCount(); - static void purgeInactiveFontData(int count = INT_MAX); + size_t fontDataCount(); + size_t inactiveFontDataCount(); + void purgeInactiveFontData(int count = INT_MAX); private: + FontCache(); + // These methods are implemented by each platform. - static FontPlatformData* getSimilarFontPlatformData(const Font&); - static FontPlatformData* createFontPlatformData(const FontDescription&, const AtomicString& family); + FontPlatformData* getSimilarFontPlatformData(const Font&); + FontPlatformData* createFontPlatformData(const FontDescription&, const AtomicString& family); friend class SimpleFontData; friend class FontFallbackList; }; +// Get the global fontCache. +FontCache* fontCache(); } #endif diff --git a/WebCore/platform/graphics/FontFallbackList.cpp b/WebCore/platform/graphics/FontFallbackList.cpp index ef59c2f..06d52d7 100644 --- a/WebCore/platform/graphics/FontFallbackList.cpp +++ b/WebCore/platform/graphics/FontFallbackList.cpp @@ -40,7 +40,7 @@ FontFallbackList::FontFallbackList() , m_pitch(UnknownPitch) , m_loadingCustomFonts(false) , m_fontSelector(0) - , m_generation(FontCache::generation()) + , m_generation(fontCache()->generation()) { } @@ -52,7 +52,7 @@ void FontFallbackList::invalidate(PassRefPtr<FontSelector> fontSelector) m_pitch = UnknownPitch; m_loadingCustomFonts = false; m_fontSelector = fontSelector; - m_generation = FontCache::generation(); + m_generation = fontCache()->generation(); } void FontFallbackList::releaseFontData() @@ -61,7 +61,7 @@ void FontFallbackList::releaseFontData() for (unsigned i = 0; i < numFonts; ++i) { if (!m_fontList[i].second) { ASSERT(!m_fontList[i].first->isSegmented()); - FontCache::releaseFontData(static_cast<const SimpleFontData*>(m_fontList[i].first)); + fontCache()->releaseFontData(static_cast<const SimpleFontData*>(m_fontList[i].first)); } } } @@ -96,8 +96,8 @@ const FontData* FontFallbackList::fontDataAt(const Font* font, unsigned realized // We are obtaining this font for the first time. We keep track of the families we've looked at before // in |m_familyIndex|, so that we never scan the same spot in the list twice. getFontData will adjust our // |m_familyIndex| as it scans for the right font to make. - ASSERT(FontCache::generation() == m_generation); - const FontData* result = FontCache::getFontData(*font, m_familyIndex, m_fontSelector.get()); + ASSERT(fontCache()->generation() == m_generation); + const FontData* result = fontCache()->getFontData(*font, m_familyIndex, m_fontSelector.get()); if (result) { m_fontList.append(pair<const FontData*, bool>(result, result->isCustomFont())); if (result->isLoading()) @@ -116,8 +116,8 @@ const FontData* FontFallbackList::fontDataForCharacters(const Font* font, const fontData = fontDataAt(font, ++realizedFontIndex); if (!fontData) { - ASSERT(FontCache::generation() == m_generation); - fontData = FontCache::getFontDataForCharacters(*font, characters, length); + ASSERT(fontCache()->generation() == m_generation); + fontData = fontCache()->getFontDataForCharacters(*font, characters, length); } return fontData; @@ -126,8 +126,8 @@ const FontData* FontFallbackList::fontDataForCharacters(const Font* font, const void FontFallbackList::setPlatformFont(const FontPlatformData& platformData) { m_familyIndex = cAllFamiliesScanned; - ASSERT(FontCache::generation() == m_generation); - const FontData* fontData = FontCache::getCachedFontData(&platformData); + ASSERT(fontCache()->generation() == m_generation); + const FontData* fontData = fontCache()->getCachedFontData(&platformData); m_fontList.append(pair<const FontData*, bool>(fontData, fontData->isCustomFont())); } diff --git a/WebCore/platform/graphics/FontFastPath.cpp b/WebCore/platform/graphics/FontFastPath.cpp new file mode 100644 index 0000000..635aba9 --- /dev/null +++ b/WebCore/platform/graphics/FontFastPath.cpp @@ -0,0 +1,367 @@ +/** + * Copyright (C) 2003, 2006 Apple Computer, Inc. + * Copyright (C) 2008 Holger Hans Peter Freyther + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "Font.h" + +#include "CharacterNames.h" +#include "FontCache.h" +#include "FloatRect.h" +#include "GlyphBuffer.h" +#include "GlyphPageTreeNode.h" +#include "IntPoint.h" +#include "SimpleFontData.h" +#include "WidthIterator.h" + +#include <wtf/unicode/Unicode.h> +#include <wtf/MathExtras.h> + +using namespace WTF; +using namespace Unicode; + +namespace WebCore { + +const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCaps) const +{ + bool useSmallCapsFont = forceSmallCaps; + if (m_fontDescription.smallCaps()) { + UChar32 upperC = Unicode::toUpper(c); + if (upperC != c) { + c = upperC; + useSmallCapsFont = true; + } + } + + if (mirror) + c = mirroredChar(c); + + unsigned pageNumber = (c / GlyphPage::size); + + GlyphPageTreeNode* node = pageNumber ? m_pages.get(pageNumber) : m_pageZero; + if (!node) { + node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber); + if (pageNumber) + m_pages.set(pageNumber, node); + else + m_pageZero = node; + } + + GlyphPage* page; + if (!useSmallCapsFont) { + // Fastest loop, for the common case (not small caps). + while (true) { + page = node->page(); + if (page) { + const GlyphData& data = page->glyphDataForCharacter(c); + if (data.fontData) + return data; + if (node->isSystemFallback()) + break; + } + + // Proceed with the fallback list. + node = node->getChild(fontDataAt(node->level()), pageNumber); + if (pageNumber) + m_pages.set(pageNumber, node); + else + m_pageZero = node; + } + } else { + while (true) { + page = node->page(); + if (page) { + const GlyphData& data = page->glyphDataForCharacter(c); + if (data.fontData) { + // The smallCapsFontData function should not normally return 0. + // But if it does, we will just render the capital letter big. + const SimpleFontData* smallCapsFontData = data.fontData->smallCapsFontData(m_fontDescription); + if (!smallCapsFontData) + return data; + + GlyphPageTreeNode* smallCapsNode = GlyphPageTreeNode::getRootChild(smallCapsFontData, pageNumber); + const GlyphPage* smallCapsPage = smallCapsNode->page(); + if (smallCapsPage) { + const GlyphData& data = smallCapsPage->glyphDataForCharacter(c); + if (data.fontData) + return data; + } + + // Do not attempt system fallback off the smallCapsFontData. This is the very unlikely case that + // a font has the lowercase character but the small caps font does not have its uppercase version. + return smallCapsFontData->missingGlyphData(); + } + + if (node->isSystemFallback()) + break; + } + + // Proceed with the fallback list. + node = node->getChild(fontDataAt(node->level()), pageNumber); + if (pageNumber) + m_pages.set(pageNumber, node); + else + m_pageZero = node; + } + } + + ASSERT(page); + ASSERT(node->isSystemFallback()); + + // System fallback is character-dependent. When we get here, we + // know that the character in question isn't in the system fallback + // font's glyph page. Try to lazily create it here. + UChar codeUnits[2]; + int codeUnitsLength; + if (c <= 0xFFFF) { + UChar c16 = c; + if (Font::treatAsSpace(c16)) + codeUnits[0] = ' '; + else if (Font::treatAsZeroWidthSpace(c16)) + codeUnits[0] = zeroWidthSpace; + else + codeUnits[0] = c16; + codeUnitsLength = 1; + } else { + codeUnits[0] = U16_LEAD(c); + codeUnits[1] = U16_TRAIL(c); + codeUnitsLength = 2; + } + const SimpleFontData* characterFontData = fontCache()->getFontDataForCharacters(*this, codeUnits, codeUnitsLength); + if (useSmallCapsFont && characterFontData) + characterFontData = characterFontData->smallCapsFontData(m_fontDescription); + if (characterFontData) { + // Got the fallback glyph and font. + GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page(); + const GlyphData& data = fallbackPage && fallbackPage->glyphDataForCharacter(c).fontData ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData(); + // Cache it so we don't have to do system fallback again next time. + if (!useSmallCapsFont) + page->setGlyphDataForCharacter(c, data.glyph, data.fontData); + return data; + } + + // Even system fallback can fail; use the missing glyph in that case. + // FIXME: It would be nicer to use the missing glyph from the last resort font instead. + const GlyphData& data = primaryFont()->missingGlyphData(); + if (!useSmallCapsFont) + page->setGlyphDataForCharacter(c, data.glyph, data.fontData); + return data; +} + +void Font::setCodePath(CodePath p) +{ + s_codePath = p; +} + +Font::CodePath Font::codePath() +{ + return s_codePath; +} + +bool Font::canUseGlyphCache(const TextRun& run) const +{ + switch (s_codePath) { + case Auto: + break; + case Simple: + return true; + case Complex: + return false; + } + + // Start from 0 since drawing and highlighting also measure the characters before run->from + for (int i = 0; i < run.length(); i++) { + const UChar c = run[i]; + if (c < 0x300) // U+0300 through U+036F Combining diacritical marks + continue; + if (c <= 0x36F) + return false; + + if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha + continue; + if (c <= 0x05CF) + return false; + + if (c < 0x0600) // U+0600 through U+1059 Arabic, Syriac, Thaana, Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar + continue; + if (c <= 0x1059) + return false; + + if (c < 0x1100) // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose; Modern Korean will be precomposed as a result of step A) + continue; + if (c <= 0x11FF) + return false; + + if (c < 0x1780) // U+1780 through U+18AF Khmer, Mongolian + continue; + if (c <= 0x18AF) + return false; + + if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0) + continue; + if (c <= 0x194F) + return false; + + if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols + continue; + if (c <= 0x20FF) + return false; + + if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks + continue; + if (c <= 0xFE2F) + return false; + } + + return true; + +} + +void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const +{ + // This glyph buffer holds our glyphs+advances+font data for each glyph. + GlyphBuffer glyphBuffer; + + float startX = point.x(); + WidthIterator it(this, run); + it.advance(from); + float beforeWidth = it.m_runWidthSoFar; + it.advance(to, &glyphBuffer); + + // We couldn't generate any glyphs for the run. Give up. + if (glyphBuffer.isEmpty()) + return; + + float afterWidth = it.m_runWidthSoFar; + + if (run.rtl()) { + float finalRoundingWidth = it.m_finalRoundingWidth; + it.advance(run.length()); + startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth; + } else + startX += beforeWidth; + + // Swap the order of the glyphs if right-to-left. + if (run.rtl()) + for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end) + glyphBuffer.swap(i, end); + + // Calculate the starting point of the glyphs to be displayed by adding + // all the advances up to the first glyph. + FloatPoint startPoint(startX, point.y()); + drawGlyphBuffer(context, glyphBuffer, run, startPoint); +} + +void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const TextRun&, const FloatPoint& point) const +{ + // Draw each contiguous run of glyphs that use the same font data. + const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); + FloatSize offset = glyphBuffer.offsetAt(0); + FloatPoint startPoint(point); + float nextX = startPoint.x(); + int lastFrom = 0; + int nextGlyph = 0; + while (nextGlyph < glyphBuffer.size()) { + const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); + FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph); + if (nextFontData != fontData || nextOffset != offset) { + drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); + + lastFrom = nextGlyph; + fontData = nextFontData; + offset = nextOffset; + startPoint.setX(nextX); + } + nextX += glyphBuffer.advanceAt(nextGlyph); + nextGlyph++; + } + + drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); +} + +float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer) const +{ + WidthIterator it(this, run); + it.advance(run.length(), glyphBuffer); + return it.m_runWidthSoFar; +} + +FloatRect Font::selectionRectForSimpleText(const TextRun& run, const IntPoint& point, int h, int from, int to) const +{ + WidthIterator it(this, run); + it.advance(from); + float beforeWidth = it.m_runWidthSoFar; + it.advance(to); + float afterWidth = it.m_runWidthSoFar; + + // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning + if (run.rtl()) { + it.advance(run.length()); + float totalWidth = it.m_runWidthSoFar; + return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h); + } else { + return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h); + } +} + +int Font::offsetForPositionForSimpleText(const TextRun& run, int x, bool includePartialGlyphs) const +{ + float delta = (float)x; + + WidthIterator it(this, run); + GlyphBuffer localGlyphBuffer; + unsigned offset; + if (run.rtl()) { + delta -= floatWidthForSimpleText(run, 0); + while (1) { + offset = it.m_currentCharacter; + float w; + if (!it.advanceOneCharacter(w, &localGlyphBuffer)) + break; + delta += w; + if (includePartialGlyphs) { + if (delta - w / 2 >= 0) + break; + } else { + if (delta >= 0) + break; + } + } + } else { + while (1) { + offset = it.m_currentCharacter; + float w; + if (!it.advanceOneCharacter(w, &localGlyphBuffer)) + break; + delta -= w; + if (includePartialGlyphs) { + if (delta + w / 2 <= 0) + break; + } else { + if (delta <= 0) + break; + } + } + } + + return offset; +} + +} diff --git a/WebCore/platform/graphics/GeneratedImage.cpp b/WebCore/platform/graphics/GeneratedImage.cpp index 5e50959..15e27d7 100644 --- a/WebCore/platform/graphics/GeneratedImage.cpp +++ b/WebCore/platform/graphics/GeneratedImage.cpp @@ -47,7 +47,7 @@ void GeneratedImage::draw(GraphicsContext* context, const FloatRect& dstRect, co context->restore(); } -void GeneratedImage::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform, +void GeneratedImage::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator compositeOp, const FloatRect& destRect) { // Create a BitmapImage and call drawPattern on it. diff --git a/WebCore/platform/graphics/GeneratedImage.h b/WebCore/platform/graphics/GeneratedImage.h index fb0661b..dea0c54 100644 --- a/WebCore/platform/graphics/GeneratedImage.h +++ b/WebCore/platform/graphics/GeneratedImage.h @@ -53,15 +53,14 @@ public: virtual IntSize size() const { return m_size; } // Assume that generated content has no decoded data we need to worry about - virtual void destroyDecodedData(bool incremental = false, bool preserveNearbyFrames = false) { } + virtual void destroyDecodedData(bool /*destroyAll*/ = true) { } virtual unsigned decodedSize() const { return 0; } protected: virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); - virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform, + virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator, const FloatRect& destRect); -protected: GeneratedImage(PassRefPtr<Generator> generator, const IntSize& size) : m_generator(generator) , m_size(size) diff --git a/WebCore/platform/graphics/GlyphBuffer.h b/WebCore/platform/graphics/GlyphBuffer.h index 18957d5..fdb306f 100644 --- a/WebCore/platform/graphics/GlyphBuffer.h +++ b/WebCore/platform/graphics/GlyphBuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 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 @@ -30,14 +30,16 @@ #define GlyphBuffer_h #include "FloatSize.h" +#include <wtf/UnusedParam.h> +#include <wtf/Vector.h> #if PLATFORM(CG) #include <ApplicationServices/ApplicationServices.h> -#elif PLATFORM(CAIRO) -#include <cairo.h> #endif -#include <wtf/Vector.h> +#if PLATFORM(CAIRO) +#include <cairo.h> +#endif namespace WebCore { @@ -125,6 +127,7 @@ public: #if PLATFORM(WIN) return m_offsets[index]; #else + UNUSED_PARAM(index); return FloatSize(); #endif } @@ -132,6 +135,7 @@ public: void add(Glyph glyph, const SimpleFontData* font, float width, const FloatSize* offset = 0) { m_fontData.append(font); + #if PLATFORM(CAIRO) cairo_glyph_t cairoGlyph; cairoGlyph.index = glyph; @@ -152,6 +156,8 @@ public: m_offsets.append(*offset); else m_offsets.append(FloatSize()); +#else + UNUSED_PARAM(offset); #endif } diff --git a/WebCore/platform/graphics/GraphicsContext.cpp b/WebCore/platform/graphics/GraphicsContext.cpp index 9cd2969..8426011 100644 --- a/WebCore/platform/graphics/GraphicsContext.cpp +++ b/WebCore/platform/graphics/GraphicsContext.cpp @@ -109,17 +109,6 @@ void GraphicsContext::restore() restorePlatformState(); } -const Font& GraphicsContext::font() const -{ - return m_common->state.font; -} - -void GraphicsContext::setFont(const Font& aFont) -{ - m_common->state.font = aFont; - setPlatformFont(aFont); -} - void GraphicsContext::setStrokeThickness(float thickness) { m_common->state.strokeThickness = thickness; @@ -211,6 +200,17 @@ Color GraphicsContext::fillColor() const return m_common->state.fillColor; } +void GraphicsContext::setShouldAntialias(bool b) +{ + m_common->state.shouldAntialias = b; + setPlatformShouldAntialias(b); +} + +bool GraphicsContext::shouldAntialias() const +{ + return m_common->state.shouldAntialias; +} + void GraphicsContext::setStrokePattern(PassRefPtr<Pattern> pattern) { ASSERT(pattern); @@ -255,6 +255,11 @@ void GraphicsContext::setFillGradient(PassRefPtr<Gradient> gradient) m_common->state.fillGradient = gradient; } +void GraphicsContext::setShadowsIgnoreTransforms(bool ignoreTransforms) +{ + m_common->state.shadowsIgnoreTransforms = ignoreTransforms; +} + bool GraphicsContext::updatingControlTints() const { return m_common->m_updatingControlTints; @@ -296,15 +301,15 @@ void GraphicsContext::drawImage(Image* image, const IntRect& dest, const IntRect drawImage(image, FloatRect(dest), srcRect, op, useLowQualityScale); } -void GraphicsContext::drawText(const TextRun& run, const IntPoint& point, int from, int to) +void GraphicsContext::drawText(const Font& font, const TextRun& run, const IntPoint& point, int from, int to) { if (paintingDisabled()) return; - font().drawText(this, run, point, from, to); + font.drawText(this, run, point, from, to); } -void GraphicsContext::drawBidiText(const TextRun& run, const FloatPoint& point) +void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const FloatPoint& point) { if (paintingDisabled()) return; @@ -329,23 +334,23 @@ void GraphicsContext::drawBidiText(const TextRun& run, const FloatPoint& point) subrun.setRTL(bidiRun->level() % 2); subrun.setDirectionalOverride(bidiRun->dirOverride(false)); - font().drawText(this, subrun, currPoint); + font.drawText(this, subrun, currPoint); bidiRun = bidiRun->next(); // FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here. if (bidiRun) - currPoint.move(font().floatWidth(subrun), 0.f); + currPoint.move(font.floatWidth(subrun), 0.f); } bidiResolver.deleteRuns(); } -void GraphicsContext::drawHighlightForText(const TextRun& run, const IntPoint& point, int h, const Color& backgroundColor, int from, int to) +void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, const IntPoint& point, int h, const Color& backgroundColor, int from, int to) { if (paintingDisabled()) return; - fillRect(font().selectionRectForText(run, point, h, from, to), backgroundColor); + fillRect(font.selectionRectForText(run, point, h, from, to), backgroundColor); } void GraphicsContext::initFocusRing(int width, int offset) @@ -498,10 +503,4 @@ void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle&) } #endif -#if !PLATFORM(QT) -void GraphicsContext::setPlatformFont(const Font&) -{ -} -#endif - } diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h index 95bdc90..c27f38f 100644 --- a/WebCore/platform/graphics/GraphicsContext.h +++ b/WebCore/platform/graphics/GraphicsContext.h @@ -98,7 +98,7 @@ namespace WebCore { const int cMisspellingLinePatternWidth = 4; const int cMisspellingLinePatternGapWidth = 1; - class AffineTransform; + class TransformationMatrix; class Font; class Generator; class Gradient; @@ -145,9 +145,6 @@ namespace WebCore { ~GraphicsContext(); PlatformGraphicsContext* platformContext() const; - - const Font& font() const; - void setFont(const Font&); float strokeThickness() const; void setStrokeThickness(float); @@ -166,6 +163,15 @@ namespace WebCore { void setFillColor(const Color&); void setFillPattern(PassRefPtr<Pattern>); void setFillGradient(PassRefPtr<Gradient>); + void setShadowsIgnoreTransforms(bool); + + void setShouldAntialias(bool); + bool shouldAntialias() const; + +#if PLATFORM(CG) + void applyStrokePattern(); + void applyFillPattern(); +#endif #if PLATFORM(SGL) /* these should be pused to apple. needed for CanvasStyle.cpp */ @@ -183,6 +189,10 @@ namespace WebCore { bool willFill() const; // returns true if there is a valid (non-transparent) stroke color bool willStroke() const; + + // may return NULL, since we lazily allocate the path. This is the path + // that is drawn by drawPath() + const SkPath* getCurrPath() const; /** platform-specific factory method to return a bitmap graphicscontext, called by <canvas> when we need to draw offscreen. Caller is responsible for @@ -239,14 +249,15 @@ namespace WebCore { void clipOut(const IntRect&); void clipOutEllipseInRect(const IntRect&); void clipOutRoundedRect(const IntRect&, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight); + void clipPath(WindRule); void clipToImageBuffer(const FloatRect&, const ImageBuffer*); int textDrawingMode(); void setTextDrawingMode(int); - void drawText(const TextRun&, const IntPoint&, int from = 0, int to = -1); - void drawBidiText(const TextRun&, const FloatPoint&); - void drawHighlightForText(const TextRun&, const IntPoint&, int h, const Color& backgroundColor, int from = 0, int to = -1); + void drawText(const Font&, const TextRun&, const IntPoint&, int from = 0, int to = -1); + void drawBidiText(const Font&, const TextRun&, const FloatPoint&); + void drawHighlightForText(const Font&, const TextRun&, const IntPoint&, int h, const Color& backgroundColor, int from = 0, int to = -1); FloatRect roundToDevicePixels(const FloatRect&); @@ -297,10 +308,8 @@ namespace WebCore { void setURLForRect(const KURL&, const IntRect&); - void concatCTM(const AffineTransform&); - AffineTransform getCTM() const; - - void setUseAntialiasing(bool = true); + void concatCTM(const TransformationMatrix&); + TransformationMatrix getCTM() const; #if PLATFORM(WIN) GraphicsContext(HDC, bool hasAlpha = false); // FIXME: To be removed. @@ -308,6 +317,17 @@ namespace WebCore { HDC getWindowsContext(const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true); // The passed in rect is used to create a bitmap for compositing inside transparency layers. void releaseWindowsContext(HDC, const IntRect&, bool supportAlphaBlend = true, bool mayCreateBitmap = true); // The passed in HDC should be the one handed back by getWindowsContext. + // When set to true, child windows should be rendered into this context + // rather than allowing them just to render to the screen. Defaults to + // false. + // FIXME: This is a layering violation. GraphicsContext shouldn't know + // what a "window" is. It would be much more appropriate for this flag + // to be passed as a parameter alongside the GraphicsContext, but doing + // that would require lots of changes in cross-platform code that we + // aren't sure we want to make. + void setShouldIncludeChildWindows(bool); + bool shouldIncludeChildWindows() const; + class WindowsBitmap : public Noncopyable { public: WindowsBitmap(HDC, IntSize); @@ -341,6 +361,7 @@ namespace WebCore { #if PLATFORM(QT) bool inTransparencyLayer() const; PlatformPath* currentPath(); + QPen pen(); #endif #if PLATFORM(GTK) @@ -362,6 +383,8 @@ namespace WebCore { void setPlatformFillColor(const Color&); + void setPlatformShouldAntialias(bool b); + void setPlatformShadow(const IntSize&, int blur, const Color&); void clearPlatformShadow(); diff --git a/WebCore/platform/graphics/GraphicsContextPrivate.h b/WebCore/platform/graphics/GraphicsContextPrivate.h index de94527..87123eb 100644 --- a/WebCore/platform/graphics/GraphicsContextPrivate.h +++ b/WebCore/platform/graphics/GraphicsContextPrivate.h @@ -26,7 +26,7 @@ #ifndef GraphicsContextPrivate_h #define GraphicsContextPrivate_h -#include "Font.h" +#include "TransformationMatrix.h" #include "Gradient.h" #include "GraphicsContext.h" #include "Pattern.h" @@ -58,18 +58,21 @@ namespace WebCore { , fillRule(RULE_NONZERO) , fillColorSpace(SolidColorSpace) , fillColor(Color::black) + , shouldAntialias(true) , paintingDisabled(false) , shadowBlur(0) + , shadowsIgnoreTransforms(false) { } - Font font; int textDrawingMode; StrokeStyle strokeStyle; float strokeThickness; #if PLATFORM(CAIRO) float globalAlpha; +#elif PLATFORM(QT) + TransformationMatrix pathTransform; #endif ColorSpace strokeColorSpace; Color strokeColor; @@ -83,11 +86,15 @@ namespace WebCore { RefPtr<Gradient> fillGradient; RefPtr<Pattern> fillPattern; + bool shouldAntialias; + bool paintingDisabled; IntSize shadowSize; unsigned shadowBlur; Color shadowColor; + + bool shadowsIgnoreTransforms; }; class GraphicsContextPrivate { diff --git a/WebCore/platform/graphics/Image.cpp b/WebCore/platform/graphics/Image.cpp index ca6954e..49961e1 100644 --- a/WebCore/platform/graphics/Image.cpp +++ b/WebCore/platform/graphics/Image.cpp @@ -27,11 +27,12 @@ #include "config.h" #include "Image.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "BitmapImage.h" #include "GraphicsContext.h" #include "IntRect.h" #include "MIMETypeRegistry.h" +#include <wtf/StdLibExtras.h> #include <math.h> @@ -52,7 +53,7 @@ Image::~Image() Image* Image::nullImage() { - static RefPtr<Image> nullImage = BitmapImage::create(); + DEFINE_STATIC_LOCAL(RefPtr<Image>, nullImage, (BitmapImage::create()));; return nullImage.get(); } @@ -61,11 +62,6 @@ bool Image::supportsType(const String& type) return MIMETypeRegistry::isSupportedImageResourceMIMEType(type); } -bool Image::isNull() const -{ - return size().isEmpty(); -} - bool Image::setData(PassRefPtr<SharedBuffer> data, bool allDataReceived) { m_data = data; @@ -79,21 +75,6 @@ bool Image::setData(PassRefPtr<SharedBuffer> data, bool allDataReceived) return dataChanged(allDataReceived); } -IntRect Image::rect() const -{ - return IntRect(IntPoint(), size()); -} - -int Image::width() const -{ - return size().width(); -} - -int Image::height() const -{ - return size().height(); -} - void Image::fillWithSolidColor(GraphicsContext* ctxt, const FloatRect& dstRect, const Color& color, CompositeOperator op) { if (color.alpha() <= 0) @@ -138,7 +119,7 @@ void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& destRect, const Fl FloatSize scale(scaledTileSize.width() / intrinsicTileSize.width(), scaledTileSize.height() / intrinsicTileSize.height()); - AffineTransform patternTransform = AffineTransform().scale(scale.width(), scale.height()); + TransformationMatrix patternTransform = TransformationMatrix().scale(scale.width(), scale.height()); FloatRect oneTileRect; oneTileRect.setX(destRect.x() + fmodf(fmodf(-srcPoint.x(), scaledTileSize.width()) - scaledTileSize.width(), scaledTileSize.width())); @@ -177,7 +158,7 @@ void Image::drawTiled(GraphicsContext* ctxt, const FloatRect& dstRect, const Flo vRule = RepeatTile; FloatSize scale = calculatePatternScale(dstRect, srcRect, hRule, vRule); - AffineTransform patternTransform = AffineTransform().scale(scale.width(), scale.height()); + TransformationMatrix patternTransform = TransformationMatrix().scale(scale.width(), scale.height()); // We want to construct the phase such that the pattern is centered (when stretch is not // set for a particular rule). diff --git a/WebCore/platform/graphics/Image.h b/WebCore/platform/graphics/Image.h index 1419b2d..c3cf2e7 100644 --- a/WebCore/platform/graphics/Image.h +++ b/WebCore/platform/graphics/Image.h @@ -30,6 +30,7 @@ #include "Color.h" #include "GraphicsTypes.h" #include "ImageSource.h" +#include "IntRect.h" #include <wtf/RefPtr.h> #include <wtf/PassRefPtr.h> #include "SharedBuffer.h" @@ -66,13 +67,11 @@ class SkBitmapRef; namespace WebCore { -class AffineTransform; +class TransformationMatrix; class FloatPoint; class FloatRect; class FloatSize; class GraphicsContext; -class IntRect; -class IntSize; class SharedBuffer; class String; @@ -96,7 +95,7 @@ public: virtual bool hasSingleSecurityOrigin() const { return false; } static Image* nullImage(); - bool isNull() const; + bool isNull() const { return size().isEmpty(); } // These are only used for SVGImage right now virtual void setContainerSize(const IntSize&) { } @@ -105,14 +104,16 @@ public: virtual bool hasRelativeHeight() const { return false; } virtual IntSize size() const = 0; - IntRect rect() const; - int width() const; - int height() const; + IntRect rect() const { return IntRect(IntPoint(), size()); } + int width() const { return size().width(); } + int height() const { return size().height(); } bool setData(PassRefPtr<SharedBuffer> data, bool allDataReceived); - virtual bool dataChanged(bool allDataReceived) { return false; } + virtual bool dataChanged(bool /*allDataReceived*/) { return false; } + + virtual String filenameExtension() const { return String(); } // null string if unknown - virtual void destroyDecodedData(bool incremental = false, bool preserveNearbyFrames = false) = 0; + virtual void destroyDecodedData(bool destroyAll = true) = 0; virtual unsigned decodedSize() const = 0; SharedBuffer* data() { return m_data.get(); } @@ -166,9 +167,9 @@ protected: virtual bool mayFillWithSolidColor() const { return false; } virtual Color solidColor() const { return Color(); } - virtual void startAnimation() { } + virtual void startAnimation(bool /*catchUpIfNecessary*/ = true) { } - virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const AffineTransform& patternTransform, + virtual void drawPattern(GraphicsContext*, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator, const FloatRect& destRect); #if PLATFORM(CG) // These are private to CG. Ideally they would be only in the .cpp file, but the callback requires access diff --git a/WebCore/platform/graphics/ImageBuffer.h b/WebCore/platform/graphics/ImageBuffer.h index 7c68fc8..14f7461 100644 --- a/WebCore/platform/graphics/ImageBuffer.h +++ b/WebCore/platform/graphics/ImageBuffer.h @@ -27,6 +27,7 @@ #ifndef ImageBuffer_h #define ImageBuffer_h +#include "TransformationMatrix.h" #include "Image.h" #include "IntSize.h" #include "ImageBufferData.h" @@ -67,7 +68,11 @@ namespace WebCore { void putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint); String toDataURL(const String& mimeType) const; - +#if !PLATFORM(CG) + TransformationMatrix baseTransform() const { return TransformationMatrix(); } +#else + TransformationMatrix baseTransform() const { return TransformationMatrix(1, 0, 0, -1, 0, m_size.height()); } +#endif private: ImageBufferData m_data; diff --git a/WebCore/platform/graphics/ImageObserver.h b/WebCore/platform/graphics/ImageObserver.h index 4be83bd..8b693d9 100644 --- a/WebCore/platform/graphics/ImageObserver.h +++ b/WebCore/platform/graphics/ImageObserver.h @@ -29,6 +29,7 @@ namespace WebCore { class Image; +class IntRect; // Interface for notification about changes to an image, including decoding, // drawing, and animating. @@ -41,6 +42,8 @@ public: virtual bool shouldPauseAnimation(const Image*) = 0; virtual void animationAdvanced(const Image*) = 0; + + virtual void changedInRect(const Image*, const IntRect&) = 0; }; } diff --git a/WebCore/platform/graphics/ImageSource.h b/WebCore/platform/graphics/ImageSource.h index a9f346d..55e0c5a 100644 --- a/WebCore/platform/graphics/ImageSource.h +++ b/WebCore/platform/graphics/ImageSource.h @@ -55,6 +55,7 @@ namespace WebCore { class IntSize; class SharedBuffer; +class String; #if PLATFORM(WX) class ImageDecoder; @@ -94,22 +95,49 @@ public: ImageSource(); ~ImageSource(); - void clear(); + // Tells the ImageSource that the Image no longer cares about decoded frame + // data -- at all (if |destroyAll| is true), or before frame + // |clearBeforeFrame| (if |destroyAll| is false). The ImageSource should + // delete cached decoded data for these frames where possible to keep memory + // usage low. When |destroyAll| is true, the ImageSource should also reset + // any local state so that decoding can begin again. + // + // Implementations that delete less than what's specified above waste + // memory. Implementations that delete more may burn CPU re-decoding frames + // that could otherwise have been cached, or encounter errors if they're + // asked to decode frames they can't decode due to the loss of previous + // decoded frames. + // + // Callers should not call clear(false, n) and subsequently call + // createFrameAtIndex(m) with m < n, unless they first call clear(true). + // This ensures that stateful ImageSources/decoders will work properly. + // + // The |data| and |allDataReceived| parameters should be supplied by callers + // who set |destroyAll| to true if they wish to be able to continue using + // the ImageSource. This way implementations which choose to destroy their + // decoders in some cases can reconstruct them correctly. + void clear(bool destroyAll, + size_t clearBeforeFrame = 0, + SharedBuffer* data = NULL, + bool allDataReceived = false); bool initialized() const; - + void setData(SharedBuffer* data, bool allDataReceived); + String filenameExtension() const; bool isSizeAvailable(); IntSize size() const; IntSize frameSizeAtIndex(size_t) const; int repetitionCount(); - + size_t frameCount() const; - + + // Callers should not call this after calling clear() with a higher index; + // see comments on clear() above. NativeImagePtr createFrameAtIndex(size_t); - + float frameDurationAtIndex(size_t); bool frameHasAlphaAtIndex(size_t); // Whether or not the frame actually used any alpha. bool frameIsCompleteAtIndex(size_t); // Whether or not the frame is completely decoded. @@ -119,6 +147,9 @@ public: void setURL(const String& url); #endif private: + // FIXME: This is protected only to allow ImageSourceSkia to set ICO decoder + // with a preferred size. See ImageSourceSkia.h for discussion. +protected: NativeImageSourcePtr m_decoder; }; diff --git a/WebCore/platform/graphics/IntSize.h b/WebCore/platform/graphics/IntSize.h index 7245408..4d36545 100644 --- a/WebCore/platform/graphics/IntSize.h +++ b/WebCore/platform/graphics/IntSize.h @@ -67,6 +67,12 @@ public: bool isEmpty() const { return m_width <= 0 || m_height <= 0; } + void expand(int width, int height) + { + m_width += width; + m_height += height; + } + IntSize expandedTo(const IntSize& other) const { return IntSize(m_width > other.m_width ? m_width : other.m_width, diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h index 1beab95..203f299 100644 --- a/WebCore/platform/graphics/MediaPlayer.h +++ b/WebCore/platform/graphics/MediaPlayer.h @@ -67,6 +67,9 @@ public: void setFrameView(FrameView* frameView) { m_frameView = frameView; } bool inMediaDocument(); + // FIXME: it would be better to just have a getter and setter for size. + // This is currently an absolute rect, which is not appropriate for + // content with transforms IntRect rect() const { return m_rect; } void setRect(const IntRect& r); diff --git a/WebCore/platform/graphics/Path.h b/WebCore/platform/graphics/Path.h index 06e6ee4..2b0a7d1 100644 --- a/WebCore/platform/graphics/Path.h +++ b/WebCore/platform/graphics/Path.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. - * 2006 Rob Buis <buis@kde.org> + * Copyright (C) 2003, 2006, 2009 Apple Inc. All rights reserved. + * 2006 Rob Buis <buis@kde.org> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,6 +27,8 @@ #ifndef Path_h #define Path_h +#include <algorithm> + #if PLATFORM(CG) typedef struct CGPath PlatformPath; #elif PLATFORM(QT) @@ -55,11 +57,13 @@ typedef void PlatformPath; namespace WebCore { - class AffineTransform; class FloatPoint; - class FloatSize; class FloatRect; + class FloatSize; + class GraphicsContext; class String; + class StrokeStyleApplier; + class TransformationMatrix; enum WindRule { RULE_NONZERO = 0, @@ -79,7 +83,7 @@ namespace WebCore { FloatPoint* points; }; - typedef void (*PathApplierFunction) (void* info, const PathElement*); + typedef void (*PathApplierFunction)(void* info, const PathElement*); class Path { public: @@ -89,8 +93,12 @@ namespace WebCore { Path(const Path&); Path& operator=(const Path&); + void swap(Path& other) { std::swap(m_path, other.m_path); } + bool contains(const FloatPoint&, WindRule rule = RULE_NONZERO) const; + bool strokeContains(StrokeStyleApplier*, const FloatPoint&) const; FloatRect boundingRect() const; + FloatRect strokeBoundingRect(StrokeStyleApplier* = 0); float length(); FloatPoint pointAtLength(float length, bool& ok); @@ -124,7 +132,7 @@ namespace WebCore { static Path createLine(const FloatPoint&, const FloatPoint&); void apply(void* info, PathApplierFunction) const; - void transform(const AffineTransform&); + void transform(const TransformationMatrix&); private: PlatformPath* m_path; diff --git a/WebCore/platform/graphics/Pattern.h b/WebCore/platform/graphics/Pattern.h index 985c7c0..716a645 100644 --- a/WebCore/platform/graphics/Pattern.h +++ b/WebCore/platform/graphics/Pattern.h @@ -54,7 +54,7 @@ typedef wxBrush* PlatformPatternPtr; #endif namespace WebCore { - class AffineTransform; + class TransformationMatrix; class Image; class Pattern : public RefCounted<Pattern> { @@ -67,7 +67,7 @@ namespace WebCore { Image* tileImage() const { return m_tileImage.get(); } - PlatformPatternPtr createPlatformPattern(const AffineTransform& patternTransform) const; + PlatformPatternPtr createPlatformPattern(const TransformationMatrix& patternTransform) const; private: Pattern(Image*, bool repeatX, bool repeatY); diff --git a/WebCore/platform/graphics/SegmentedFontData.cpp b/WebCore/platform/graphics/SegmentedFontData.cpp index ceefe4f..1731d16 100644 --- a/WebCore/platform/graphics/SegmentedFontData.cpp +++ b/WebCore/platform/graphics/SegmentedFontData.cpp @@ -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 @@ -45,16 +45,27 @@ const SimpleFontData* SegmentedFontData::fontDataForCharacter(UChar32 c) const return m_ranges[0].fontData(); } -bool SegmentedFontData::containsCharacters(const UChar* characters, int length) const +bool SegmentedFontData::containsCharacter(UChar32 c) const { Vector<FontDataRange>::const_iterator end = m_ranges.end(); for (Vector<FontDataRange>::const_iterator it = m_ranges.begin(); it != end; ++it) { - if (it->from() <= characters[0] && it->to() >= characters[0]) + if (c >= it->from() && c <= it->to()) return true; } return false; } +bool SegmentedFontData::containsCharacters(const UChar* characters, int length) const +{ + UChar32 c; + for (int i = 0; i < length; ) { + U16_NEXT(characters, i, length, c) + if (!containsCharacter(c)) + return false; + } + return true; +} + bool SegmentedFontData::isCustomFont() const { // All segmented fonts are custom fonts. diff --git a/WebCore/platform/graphics/SegmentedFontData.h b/WebCore/platform/graphics/SegmentedFontData.h index 1adec15..0a78321 100644 --- a/WebCore/platform/graphics/SegmentedFontData.h +++ b/WebCore/platform/graphics/SegmentedFontData.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 @@ -55,6 +55,11 @@ class SegmentedFontData : public FontData { public: virtual ~SegmentedFontData(); + void appendRange(const FontDataRange& range) { m_ranges.append(range); } + unsigned numRanges() const { return m_ranges.size(); } + const FontDataRange& rangeAt(unsigned i) const { return m_ranges[i]; } + +private: virtual const SimpleFontData* fontDataForCharacter(UChar32) const; virtual bool containsCharacters(const UChar*, int length) const; @@ -62,11 +67,8 @@ public: virtual bool isLoading() const; virtual bool isSegmented() const; - void appendRange(const FontDataRange& range) { m_ranges.append(range); } - unsigned numRanges() const { return m_ranges.size(); } - const FontDataRange& rangeAt(unsigned i) const { return m_ranges[i]; } + bool containsCharacter(UChar32) const; -private: Vector<FontDataRange, 1> m_ranges; }; diff --git a/WebCore/platform/graphics/SimpleFontData.cpp b/WebCore/platform/graphics/SimpleFontData.cpp index 372fcc8..9670b55 100644 --- a/WebCore/platform/graphics/SimpleFontData.cpp +++ b/WebCore/platform/graphics/SimpleFontData.cpp @@ -30,6 +30,7 @@ #include "config.h" #include "SimpleFontData.h" +#include "Font.h" #include "FontCache.h" #if ENABLE(SVG_FONTS) #include "SVGFontData.h" @@ -41,7 +42,8 @@ namespace WebCore { SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool loading, SVGFontData* svgFontData) - : m_font(f) + : m_unitsPerEm(defaultUnitsPerEm) + , m_font(f) , m_treatAsFixedPitch(false) #if ENABLE(SVG_FONTS) , m_svgFontData(svgFontData) @@ -50,7 +52,7 @@ SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool , m_isLoading(loading) , m_smallCapsFontData(0) { -#if ENABLE(SVG_FONTS) && !PLATFORM(QT) +#if ENABLE(SVG_FONTS) if (SVGFontFaceElement* svgFontFaceElement = svgFontData ? svgFontData->svgFontFaceElement() : 0) { m_unitsPerEm = svgFontFaceElement->unitsPerEm(); @@ -75,7 +77,12 @@ SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool #endif platformInit(); + platformGlyphInit(); +} +#if !PLATFORM(QT) +void SimpleFontData::platformGlyphInit() +{ GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); if (!glyphPageZero) { LOG_ERROR("Failed to get glyph page zero."); @@ -113,21 +120,23 @@ SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool m_missingGlyphData.fontData = this; m_missingGlyphData.glyph = 0; } +#endif SimpleFontData::~SimpleFontData() { +#if ENABLE(SVG_FONTS) + if (!m_svgFontData || !m_svgFontData->svgFontFaceElement()) +#endif + platformDestroy(); + if (!isCustomFont()) { if (m_smallCapsFontData) - FontCache::releaseFontData(m_smallCapsFontData); + fontCache()->releaseFontData(m_smallCapsFontData); GlyphPageTreeNode::pruneTreeFontData(this); } - -#if ENABLE(SVG_FONTS) && !PLATFORM(QT) - if (!m_svgFontData || !m_svgFontData->svgFontFaceElement()) -#endif - platformDestroy(); } +#if !PLATFORM(QT) float SimpleFontData::widthForGlyph(Glyph glyph) const { float width = m_glyphToWidthMap.widthForGlyph(glyph); @@ -139,6 +148,7 @@ float SimpleFontData::widthForGlyph(Glyph glyph) const return width; } +#endif const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const { diff --git a/WebCore/platform/graphics/SimpleFontData.h b/WebCore/platform/graphics/SimpleFontData.h index 5f26cbf..e572e30 100644 --- a/WebCore/platform/graphics/SimpleFontData.h +++ b/WebCore/platform/graphics/SimpleFontData.h @@ -41,6 +41,10 @@ typedef struct OpaqueATSUStyle* ATSUStyle; #include <cairo.h> #endif +#if PLATFORM(QT) +#include <QFont> +#endif + namespace WebCore { class FontDescription; @@ -109,6 +113,10 @@ public: } #endif +#if PLATFORM(QT) + QFont getQtFont() const { return m_font.font(); } +#endif + #if PLATFORM(WIN) bool isSystemFont() const { return m_isSystemFont; } SCRIPT_FONTPROPERTIES* scriptFontProperties() const; @@ -128,6 +136,7 @@ public: private: void platformInit(); + void platformGlyphInit(); void platformDestroy(); void commonInit(); diff --git a/WebCore/platform/graphics/StrokeStyleApplier.h b/WebCore/platform/graphics/StrokeStyleApplier.h new file mode 100644 index 0000000..e40d3d1 --- /dev/null +++ b/WebCore/platform/graphics/StrokeStyleApplier.h @@ -0,0 +1,38 @@ +/* + Copyright (C) 2008 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 + 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 StrokeStyleApplier_h +#define StrokeStyleApplier_h + +namespace WebCore { + + class GraphicsContext; + + class StrokeStyleApplier { + public: + virtual void strokeStyle(GraphicsContext*) = 0; + + protected: + StrokeStyleApplier() {} + virtual ~StrokeStyleApplier() {} + }; +} + +#endif + diff --git a/WebCore/platform/graphics/android/FontCacheAndroid.cpp b/WebCore/platform/graphics/android/FontCacheAndroid.cpp index c257348..0b3655f 100644 --- a/WebCore/platform/graphics/android/FontCacheAndroid.cpp +++ b/WebCore/platform/graphics/android/FontCacheAndroid.cpp @@ -113,7 +113,7 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD if (fontDescription.italic()) style |= SkTypeface::kItalic; - SkTypeface* tf = SkTypeface::Create(name, (SkTypeface::Style)style); + SkTypeface* tf = SkTypeface::CreateFromName(name, (SkTypeface::Style)style); FontPlatformData* result = new FontPlatformData(tf, fontDescription.computedSize(), diff --git a/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp index c2e0f02..40d98ec 100644 --- a/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp +++ b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp @@ -40,7 +40,7 @@ #include "SkPaint.h" #include "SkPorterDuff.h" #include "PlatformGraphicsContext.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "android_graphics.h" #include "SkGradientShader.h" @@ -320,7 +320,7 @@ static void extactShader(SkPaint* paint, ColorSpace cs, Pattern* pat, case PatternColorSpace: // createPlatformPattern() returns a new inst paint->setShader(pat->createPlatformPattern( - AffineTransform()))->safeUnref(); + TransformationMatrix()))->safeUnref(); break; case GradientColorSpace: { // grad->getShader() returns a cached obj @@ -389,6 +389,10 @@ bool GraphicsContext::willStroke() const { return m_data->mState->mStrokeColor != 0; } +const SkPath* GraphicsContext::getCurrPath() const { + return m_data->mState->mPath; +} + // Draws a filled rectangle with a stroked border. void GraphicsContext::drawRect(const IntRect& rect) { @@ -771,19 +775,21 @@ KRenderingDeviceContext* GraphicsContext::createRenderingDeviceContext() } #endif +/* These are the flags we need when we call saveLayer for transparency. + Since it does not appear that webkit intends this to also save/restore + the matrix or clip, I do not give those flags (for performance) + */ +#define TRANSPARENCY_SAVEFLAGS \ + (SkCanvas::SaveFlags)(SkCanvas::kHasAlphaLayer_SaveFlag | \ + SkCanvas::kFullColorLayer_SaveFlag) + void GraphicsContext::beginTransparencyLayer(float opacity) { if (paintingDisabled()) return; SkCanvas* canvas = GC2Canvas(this); - - if (opacity < 1) - { - canvas->saveLayerAlpha(NULL, (int)(opacity * 255), SkCanvas::kHasAlphaLayer_SaveFlag); - } - else - canvas->save(); + canvas->saveLayerAlpha(NULL, (int)(opacity * 255), TRANSPARENCY_SAVEFLAGS); } void GraphicsContext::endTransparencyLayer() @@ -976,7 +982,7 @@ void GraphicsContext::translate(float x, float y) GC2Canvas(this)->translate(SkFloatToScalar(x), SkFloatToScalar(y)); } -void GraphicsContext::concatCTM(const AffineTransform& xform) +void GraphicsContext::concatCTM(const TransformationMatrix& xform) { if (paintingDisabled()) return; @@ -1026,32 +1032,38 @@ if (urlRef) { #endif } -void GraphicsContext::setUseAntialiasing(bool useAA) { +void GraphicsContext::setPlatformShouldAntialias(bool useAA) +{ if (paintingDisabled()) return; m_data->mState->mUseAA = useAA; } -AffineTransform GraphicsContext::getCTM() const { - return AffineTransform(GC2Canvas(this)->getTotalMatrix()); +TransformationMatrix GraphicsContext::getCTM() const +{ + return TransformationMatrix(GC2Canvas(this)->getTotalMatrix()); } /////////////////////////////////////////////////////////////////////////////// -void GraphicsContext::beginPath() { +void GraphicsContext::beginPath() +{ m_data->beginPath(); } -void GraphicsContext::addPath(const Path& p) { +void GraphicsContext::addPath(const Path& p) +{ m_data->addPath(*p.platformPath()); } -void GraphicsContext::drawPath() { +void GraphicsContext::drawPath() +{ this->fillPath(); this->strokePath(); } -void GraphicsContext::fillPath() { +void GraphicsContext::fillPath() +{ SkPath* path = m_data->getPath(); if (paintingDisabled() || !path) return; @@ -1075,7 +1087,8 @@ void GraphicsContext::fillPath() { GC2Canvas(this)->drawPath(*path, paint); } -void GraphicsContext::strokePath() { +void GraphicsContext::strokePath() +{ const SkPath* path = m_data->getPath(); if (paintingDisabled() || !path || strokeStyle() == NoStroke) return; @@ -1112,7 +1125,8 @@ void GraphicsContext::setImageInterpolationQuality(InterpolationQuality mode) /////////////////////////////////////////////////////////////////////////////// -SkCanvas* android_gc2canvas(WebCore::GraphicsContext* gc) { +SkCanvas* android_gc2canvas(WebCore::GraphicsContext* gc) +{ return gc->platformContext()->mCanvas; } diff --git a/WebCore/platform/graphics/android/ImageAndroid.cpp b/WebCore/platform/graphics/android/ImageAndroid.cpp index 04235d5..da52d67 100644 --- a/WebCore/platform/graphics/android/ImageAndroid.cpp +++ b/WebCore/platform/graphics/android/ImageAndroid.cpp @@ -25,7 +25,7 @@ */ #include "config.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "BitmapImage.h" #include "Image.h" #include "FloatRect.h" @@ -59,14 +59,19 @@ android::AssetManager* globalAssetManager() { namespace WebCore { -void FrameData::clear() +bool FrameData::clear(bool clearMetadata) { + if (clearMetadata) + m_haveMetadata = false; + if (m_frame) { m_frame->unref(); m_frame = 0; m_duration = 0.; m_hasAlpha = true; + return true; } + return false; } BitmapImage::BitmapImage(SkBitmapRef* ref, ImageObserver* observer) @@ -211,7 +216,7 @@ void BitmapImage::setURL(const String& str) /////////////////////////////////////////////////////////////////////////////// void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, - const AffineTransform& patternTransform, + const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator compositeOp, const FloatRect& destRect) { diff --git a/WebCore/platform/graphics/android/ImageBufferAndroid.cpp b/WebCore/platform/graphics/android/ImageBufferAndroid.cpp index de88b33..7b3e8e8 100644 --- a/WebCore/platform/graphics/android/ImageBufferAndroid.cpp +++ b/WebCore/platform/graphics/android/ImageBufferAndroid.cpp @@ -99,8 +99,9 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const return 0; } - PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height()); - unsigned char* data = result->data()->data().data(); + // ! Can't use PassRefPtr<>, otherwise the second access will cause crash. + 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()) memset(data, 0, result->data()->length()); @@ -190,7 +191,7 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, con unsigned srcBytesPerRow = 4 * source->width(); unsigned dstPixelsPerRow = dst.rowBytesAsPixels(); - unsigned char* srcRows = source->data()->data().data() + originy * srcBytesPerRow + originx * 4; + unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4; SkPMColor* dstRows = dst.getAddr32(destx, desty); for (int y = 0; y < numRows; ++y) { for (int x = 0; x < numColumns; x++) { diff --git a/WebCore/platform/graphics/android/ImageSourceAndroid.cpp b/WebCore/platform/graphics/android/ImageSourceAndroid.cpp index a6bf6c6..c8fe8dd 100644 --- a/WebCore/platform/graphics/android/ImageSourceAndroid.cpp +++ b/WebCore/platform/graphics/android/ImageSourceAndroid.cpp @@ -347,7 +347,7 @@ bool ImageSource::frameIsCompleteAtIndex(size_t index) return m_decoder.m_image && m_decoder.m_image->fAllDataReceived; } -void ImageSource::clear() +void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived) { // do nothing, since the cache is managed elsewhere } @@ -358,4 +358,10 @@ IntSize ImageSource::frameSizeAtIndex(size_t index) const return this->size(); } +String ImageSource::filenameExtension() const +{ + // FIXME: need to add virtual to our decoders to return "jpg/png/gif/..." + return String(); +} + } diff --git a/WebCore/platform/graphics/android/PathAndroid.cpp b/WebCore/platform/graphics/android/PathAndroid.cpp index 819173b..cfcd2bc 100644 --- a/WebCore/platform/graphics/android/PathAndroid.cpp +++ b/WebCore/platform/graphics/android/PathAndroid.cpp @@ -26,7 +26,10 @@ #include "config.h" #include "Path.h" #include "FloatRect.h" -#include "AffineTransform.h" +#include "GraphicsContext.h" +#include "ImageBuffer.h" +#include "StrokeStyleApplier.h" +#include "TransformationMatrix.h" #include "SkPath.h" #include "SkRegion.h" @@ -260,9 +263,54 @@ void Path::apply(void* info, PathApplierFunction function) const } } -void Path::transform(const AffineTransform& xform) +void Path::transform(const TransformationMatrix& xform) { m_path->transform(xform); } + +/////////////////////////////////////////////////////////////////////////////// + +// Computes the bounding box for the stroke and style currently selected into +// the given bounding box. This also takes into account the stroke width. +static FloatRect boundingBoxForCurrentStroke(GraphicsContext* context) +{ + const SkPath* path = context->getCurrPath(); + if (NULL == path) { + return FloatRect(); + } + + SkPaint paint; + context->setupStrokePaint(&paint); + SkPath fillPath; + paint.getFillPath(*path, &fillPath); + SkRect r; + fillPath.computeBounds(&r, SkPath::kExact_BoundsType); + return FloatRect(r.fLeft, r.fTop, r.width(), r.height()); +} + +static GraphicsContext* scratchContext() +{ + static ImageBuffer* scratch = 0; + if (!scratch) + scratch = ImageBuffer::create(IntSize(1, 1), false).release(); + // We don't bother checking for failure creating the ImageBuffer, since our + // ImageBuffer initializer won't fail. + return scratch->context(); +} + +FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) +{ + GraphicsContext* scratch = scratchContext(); + scratch->save(); + scratch->beginPath(); + scratch->addPath(*this); + + if (applier) + applier->strokeStyle(scratch); + + FloatRect r = boundingBoxForCurrentStroke(scratch); + scratch->restore(); + return r; +} } diff --git a/WebCore/platform/graphics/android/PatternAndroid.cpp b/WebCore/platform/graphics/android/PatternAndroid.cpp index 2840faa..ffdbbb1 100644 --- a/WebCore/platform/graphics/android/PatternAndroid.cpp +++ b/WebCore/platform/graphics/android/PatternAndroid.cpp @@ -40,7 +40,7 @@ static SkShader::TileMode toTileMode(bool doRepeat) { return doRepeat ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode; } -SkShader* Pattern::createPlatformPattern(const AffineTransform& transform) const +SkShader* Pattern::createPlatformPattern(const TransformationMatrix& transform) const { SkBitmapRef* ref = tileImage()->nativeImageForCurrentFrame(); SkShader* s = SkShader::CreateBitmapShader(ref->bitmap(), diff --git a/WebCore/platform/graphics/android/AffineTransformAndroid.cpp b/WebCore/platform/graphics/android/TransformationMatrixAndroid.cpp index c01d078..154d4f3 100644 --- a/WebCore/platform/graphics/android/AffineTransformAndroid.cpp +++ b/WebCore/platform/graphics/android/TransformationMatrixAndroid.cpp @@ -24,7 +24,7 @@ */ #include "config.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "FloatRect.h" #include "IntRect.h" @@ -35,14 +35,14 @@ namespace WebCore { static const double deg2rad = 0.017453292519943295769; // pi/180 -AffineTransform::AffineTransform() +TransformationMatrix::TransformationMatrix() { m_transform.reset(); } -AffineTransform::AffineTransform(const SkMatrix& mat) : m_transform(mat) {} +TransformationMatrix::TransformationMatrix(const SkMatrix& mat) : m_transform(mat) {} -AffineTransform::AffineTransform(double a, double b, double c, double d, double tx, double ty) +TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double tx, double ty) { m_transform.reset(); @@ -55,7 +55,7 @@ AffineTransform::AffineTransform(double a, double b, double c, double d, double m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(ty)); } -void AffineTransform::setMatrix(double a, double b, double c, double d, double tx, double ty) +void TransformationMatrix::setMatrix(double a, double b, double c, double d, double tx, double ty) { m_transform.set(SkMatrix::kMScaleX, SkDoubleToScalar(a)); m_transform.set(SkMatrix::kMSkewX, SkDoubleToScalar(b)); @@ -66,150 +66,164 @@ void AffineTransform::setMatrix(double a, double b, double c, double d, double t m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(ty)); } -void AffineTransform::map(double x, double y, double *x2, double *y2) const +void TransformationMatrix::map(double x, double y, double *x2, double *y2) const { - SkPoint src, dst; - src.set(SkDoubleToScalar(x), SkDoubleToScalar(y)); - m_transform.mapPoints(&dst, &src, 1); + SkPoint pt; - *x2 = SkScalarToDouble(dst.fX); - *y2 = SkScalarToDouble(dst.fY); + m_transform.mapXY(SkDoubleToScalar(x), SkDoubleToScalar(y), &pt); + *x2 = SkScalarToDouble(pt.fX); + *y2 = SkScalarToDouble(pt.fY); } -IntRect AffineTransform::mapRect(const IntRect &rect) const +IntRect TransformationMatrix::mapRect(const IntRect &rect) const { SkRect src, dst; SkIRect ir; android_setrect(&src, rect); m_transform.mapRect(&dst, src); - dst.round(&ir); + // we round out to mimic enclosingIntRect() + dst.roundOut(&ir); return IntRect(ir.fLeft, ir.fTop, ir.width(), ir.height()); } -FloatRect AffineTransform::mapRect(const FloatRect &rect) const +FloatRect TransformationMatrix::mapRect(const FloatRect &rect) const { - SkRect src, dst; - SkIRect ir; + SkRect r; - android_setrect(&src, rect); - m_transform.mapRect(&dst, src); - dst.round(&ir); + android_setrect(&r, rect); + m_transform.mapRect(&r); - return IntRect(ir.fLeft, ir.fTop, ir.width(), ir.height()); + return FloatRect(r.fLeft, r.fTop, r.width(), r.height()); } -bool AffineTransform::isIdentity() const +bool TransformationMatrix::isIdentity() const { return m_transform.isIdentity(); } -void AffineTransform::reset() +void TransformationMatrix::reset() { m_transform.reset(); } - double AffineTransform::a() const { - return SkScalarToDouble(m_transform[0]); - } - void AffineTransform::setA(double a) { - m_transform.set(0, SkDoubleToScalar(a)); - } +double TransformationMatrix::a() const +{ + return SkScalarToDouble(m_transform[0]); +} - double AffineTransform::b() const { - return SkScalarToDouble(m_transform[1]); - } - void AffineTransform::setB(double b) { - m_transform.set(1, SkDoubleToScalar(b)); - } - - double AffineTransform::c() const { - return SkScalarToDouble(m_transform[3]); - } - void AffineTransform::setC(double c) { - m_transform.set(3, SkDoubleToScalar(c)); - } - - double AffineTransform::d() const { - return SkScalarToDouble(m_transform[4]); - } - void AffineTransform::setD(double d) { - m_transform.set(4, SkDoubleToScalar(d)); - } - - double AffineTransform::e() const { - return SkScalarToDouble(m_transform[2]); - } - void AffineTransform::setE(double e) { - m_transform.set(2, SkDoubleToScalar(e)); - } - - double AffineTransform::f() const { - return SkScalarToDouble(m_transform[5]); - } - void AffineTransform::setF(double f) { - m_transform.set(5, SkDoubleToScalar(f)); - } +void TransformationMatrix::setA(double a) +{ + m_transform.set(0, SkDoubleToScalar(a)); +} + +double TransformationMatrix::b() const +{ + return SkScalarToDouble(m_transform[1]); +} + +void TransformationMatrix::setB(double b) +{ + m_transform.set(1, SkDoubleToScalar(b)); +} + +double TransformationMatrix::c() const +{ + return SkScalarToDouble(m_transform[3]); +} + +void TransformationMatrix::setC(double c) +{ + m_transform.set(3, SkDoubleToScalar(c)); +} + +double TransformationMatrix::d() const { + return SkScalarToDouble(m_transform[4]); +} + +void TransformationMatrix::setD(double d) +{ + m_transform.set(4, SkDoubleToScalar(d)); +} + +double TransformationMatrix::e() const +{ + return SkScalarToDouble(m_transform[2]); +} + +void TransformationMatrix::setE(double e) +{ + m_transform.set(2, SkDoubleToScalar(e)); +} + +double TransformationMatrix::f() const { + return SkScalarToDouble(m_transform[5]); +} +void TransformationMatrix::setF(double f) { + m_transform.set(5, SkDoubleToScalar(f)); +} -AffineTransform &AffineTransform::scale(double sx, double sy) +TransformationMatrix &TransformationMatrix::scale(double sx, double sy) { m_transform.preScale(SkDoubleToScalar(sx), SkDoubleToScalar(sy)); return *this; } -AffineTransform &AffineTransform::rotate(double d) +TransformationMatrix &TransformationMatrix::rotate(double d) { m_transform.preRotate(SkDoubleToScalar(d)); return *this; } -AffineTransform &AffineTransform::translate(double tx, double ty) +TransformationMatrix &TransformationMatrix::translate(double tx, double ty) { m_transform.preTranslate(SkDoubleToScalar(tx), SkDoubleToScalar(ty)); return *this; } -AffineTransform &AffineTransform::shear(double sx, double sy) +TransformationMatrix &TransformationMatrix::shear(double sx, double sy) { m_transform.preSkew(SkDoubleToScalar(sx), SkDoubleToScalar(sy)); return *this; } -double AffineTransform::det() const +double TransformationMatrix::det() const { return SkScalarToDouble(m_transform[SkMatrix::kMScaleX]) * SkScalarToDouble(m_transform[SkMatrix::kMScaleY]) - SkScalarToDouble(m_transform[SkMatrix::kMSkewX]) * SkScalarToDouble(m_transform[SkMatrix::kMSkewY]); } -AffineTransform AffineTransform::inverse() const +TransformationMatrix TransformationMatrix::inverse() const { - AffineTransform inverse; + // the constructor initializes inverse to the identity + TransformationMatrix inverse; + // if we are not invertible, inverse will stay identity m_transform.invert(&inverse.m_transform); return inverse; } -AffineTransform::operator SkMatrix() const +TransformationMatrix::operator SkMatrix() const { return m_transform; } -bool AffineTransform::operator==(const AffineTransform &m2) const +bool TransformationMatrix::operator==(const TransformationMatrix &m2) const { return m_transform == m2.m_transform; } -AffineTransform &AffineTransform::operator*= (const AffineTransform &m2) +TransformationMatrix &TransformationMatrix::operator*= (const TransformationMatrix &m2) { m_transform.setConcat(m2.m_transform, m_transform); return *this; } -AffineTransform AffineTransform::operator* (const AffineTransform &m2) +TransformationMatrix TransformationMatrix::operator* (const TransformationMatrix &m2) { - AffineTransform cat; + TransformationMatrix cat; cat.m_transform.setConcat(m2.m_transform, m_transform); return cat; diff --git a/WebCore/platform/graphics/android/android_graphics.cpp b/WebCore/platform/graphics/android/android_graphics.cpp index 2bc0c8f..1decfd8 100644 --- a/WebCore/platform/graphics/android/android_graphics.cpp +++ b/WebCore/platform/graphics/android/android_graphics.cpp @@ -98,7 +98,7 @@ static const struct CompositOpToPorterDuffMode { uint8_t mPorterDuffMode; } gMapCompositOpsToPorterDuffModes[] = { { WebCore::CompositeClear, SkPorterDuff::kClear_Mode }, - { WebCore::CompositeCopy, SkPorterDuff::kSrcOver_Mode }, // TODO + { WebCore::CompositeCopy, SkPorterDuff::kSrc_Mode }, { WebCore::CompositeSourceOver, SkPorterDuff::kSrcOver_Mode }, { WebCore::CompositeSourceIn, SkPorterDuff::kSrcIn_Mode }, { WebCore::CompositeSourceOut, SkPorterDuff::kSrcOut_Mode }, diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp index c403f44..ef748cf 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp +++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp @@ -31,7 +31,7 @@ #if PLATFORM(CAIRO) -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "CairoPath.h" #include "FloatRect.h" #include "Font.h" @@ -62,6 +62,15 @@ namespace WebCore { +static const unsigned aquaFocusRingColor = 0xFF7DADD9; + +Color focusRingColor() +{ + static Color focusRingColor = aquaFocusRingColor; + + return focusRingColor; +} + static inline void setColor(cairo_t* cr, const Color& col) { float red, green, blue, alpha; @@ -90,9 +99,6 @@ static inline cairo_pattern_t* applySpreadMethod(cairo_pattern_t* pattern, Gradi case SpreadMethodRepeat: cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); break; - default: - cairo_pattern_set_extend(pattern, CAIRO_EXTEND_NONE); - break; } return pattern; } @@ -111,7 +117,7 @@ GraphicsContext::~GraphicsContext() delete m_data; } -AffineTransform GraphicsContext::getCTM() const +TransformationMatrix GraphicsContext::getCTM() const { cairo_t* cr = platformContext(); cairo_matrix_t m; @@ -444,19 +450,19 @@ void GraphicsContext::fillPath() cairo_set_fill_rule(cr, fillRule() == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); switch (m_common->state.fillColorSpace) { case SolidColorSpace: - if (fillColor().alpha()) { - setColor(cr, fillColor()); - cairo_clip(cr); - cairo_paint_with_alpha(cr, m_common->state.globalAlpha); - } + setColor(cr, fillColor()); + cairo_clip(cr); + cairo_paint_with_alpha(cr, m_common->state.globalAlpha); break; - case PatternColorSpace: - cairo_set_source(cr, m_common->state.fillPattern.get()->createPlatformPattern(getCTM())); + case PatternColorSpace: { + TransformationMatrix affine; + cairo_set_source(cr, m_common->state.fillPattern->createPlatformPattern(affine)); cairo_clip(cr); cairo_paint_with_alpha(cr, m_common->state.globalAlpha); break; + } case GradientColorSpace: - cairo_pattern_t* pattern = m_common->state.fillGradient.get()->platformGradient(); + cairo_pattern_t* pattern = m_common->state.fillGradient->platformGradient(); pattern = applySpreadMethod(pattern, spreadMethod()); cairo_set_source(cr, pattern); cairo_clip(cr); @@ -475,18 +481,16 @@ void GraphicsContext::strokePath() cairo_save(cr); switch (m_common->state.strokeColorSpace) { case SolidColorSpace: - if (strokeColor().alpha()) { - setColor(cr, strokeColor()); - if (m_common->state.globalAlpha < 1.0f) { - cairo_push_group(cr); - cairo_paint_with_alpha(cr, m_common->state.globalAlpha); - cairo_pop_group_to_source(cr); - } - cairo_stroke(cr); - } + float red, green, blue, alpha; + strokeColor().getRGBA(red, green, blue, alpha); + if (m_common->state.globalAlpha < 1.0f) + alpha *= m_common->state.globalAlpha; + cairo_set_source_rgba(cr, red, green, blue, alpha); + cairo_stroke(cr); break; - case PatternColorSpace: - cairo_set_source(cr, m_common->state.strokePattern.get()->createPlatformPattern(getCTM())); + case PatternColorSpace: { + TransformationMatrix affine; + cairo_set_source(cr, m_common->state.strokePattern->createPlatformPattern(affine)); if (m_common->state.globalAlpha < 1.0f) { cairo_push_group(cr); cairo_paint_with_alpha(cr, m_common->state.globalAlpha); @@ -494,8 +498,9 @@ void GraphicsContext::strokePath() } cairo_stroke(cr); break; + } case GradientColorSpace: - cairo_pattern_t* pattern = m_common->state.strokeGradient.get()->platformGradient(); + cairo_pattern_t* pattern = m_common->state.strokeGradient->platformGradient(); pattern = applySpreadMethod(pattern, spreadMethod()); cairo_set_source(cr, pattern); if (m_common->state.globalAlpha < 1.0f) { @@ -548,6 +553,16 @@ void GraphicsContext::clip(const FloatRect& rect) m_data->clip(rect); } +void GraphicsContext::clipPath(WindRule clipRule) +{ + if (paintingDisabled()) + return; + + cairo_t* cr = m_data->cr; + cairo_set_fill_rule(cr, clipRule == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); + cairo_clip(cr); +} + void GraphicsContext::drawFocusRing(const Color& color) { if (paintingDisabled()) @@ -729,7 +744,7 @@ void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) notImplemented(); } -void GraphicsContext::concatCTM(const AffineTransform& transform) +void GraphicsContext::concatCTM(const TransformationMatrix& transform) { if (paintingDisabled()) return; @@ -1079,7 +1094,7 @@ GdkDrawable* GraphicsContext::gdkDrawable() const } #endif -void GraphicsContext::setUseAntialiasing(bool enable) +void GraphicsContext::setPlatformShouldAntialias(bool enable) { if (paintingDisabled()) return; diff --git a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h index 9a14555..535f70d 100644 --- a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h +++ b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h @@ -69,7 +69,7 @@ public: void scale(const FloatSize&); void rotate(float); void translate(float, float); - void concatCTM(const AffineTransform&); + void concatCTM(const TransformationMatrix&); void beginTransparencyLayer() { m_transparencyCount++; } void endTransparencyLayer() { m_transparencyCount--; } #else @@ -81,7 +81,7 @@ public: void scale(const FloatSize&) {} void rotate(float) {} void translate(float, float) {} - void concatCTM(const AffineTransform&) {} + void concatCTM(const TransformationMatrix&) {} void beginTransparencyLayer() {} void endTransparencyLayer() {} #endif diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp index 5f65ed2..3e06669 100644 --- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp @@ -94,7 +94,7 @@ PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height()); unsigned char* dataSrc = cairo_image_surface_get_data(m_data.m_surface); - unsigned char* dataDst = result->data()->data().data(); + 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()); @@ -179,7 +179,7 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, con unsigned srcBytesPerRow = 4 * source->width(); int stride = cairo_image_surface_get_stride(m_data.m_surface); - unsigned char* srcRows = source->data()->data().data() + originy * srcBytesPerRow + originx * 4; + unsigned char* srcRows = source->data()->data()->data() + originy * srcBytesPerRow + originx * 4; for (int y = 0; y < numRows; ++y) { unsigned char *row = dataDst + stride * (y + desty); for (int x = 0; x < numColumns; x++) { diff --git a/WebCore/platform/graphics/cairo/ImageCairo.cpp b/WebCore/platform/graphics/cairo/ImageCairo.cpp index 0a35cf2..2850488 100644 --- a/WebCore/platform/graphics/cairo/ImageCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageCairo.cpp @@ -29,7 +29,7 @@ #if PLATFORM(CAIRO) -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "FloatRect.h" #include "GraphicsContext.h" #include "ImageObserver.h" @@ -38,15 +38,17 @@ namespace WebCore { -void FrameData::clear() +bool FrameData::clear(bool clearMetadata) { + if (clearMetadata) + m_haveMetadata = false; + if (m_frame) { cairo_surface_destroy(m_frame); m_frame = 0; - // NOTE: We purposefully don't reset metadata here, so that even if we - // throw away previously-decoded data, animation loops can still access - // properties like frame durations without re-decoding. + return true; } + return false; } BitmapImage::BitmapImage(cairo_surface_t* surface, ImageObserver* observer) @@ -139,7 +141,7 @@ void BitmapImage::draw(GraphicsContext* context, const FloatRect& dst, const Flo imageObserver()->didDraw(this); } -void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const AffineTransform& patternTransform, +void Image::drawPattern(GraphicsContext* context, const FloatRect& tileRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) { cairo_surface_t* image = nativeImageForCurrentFrame(); diff --git a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp index b7a4cbb..6841599 100644 --- a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp +++ b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp @@ -97,13 +97,21 @@ ImageSource::ImageSource() ImageSource::~ImageSource() { - clear(); + clear(true); } -void ImageSource::clear() +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 @@ -126,6 +134,14 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived) m_decoder->setData(data, allDataReceived); } +String ImageSource::filenameExtension() const +{ + if (!m_decoder) + return String(); + + return m_decoder->filenameExtension(); +} + bool ImageSource::isSizeAvailable() { if (!m_decoder) diff --git a/WebCore/platform/graphics/cairo/PathCairo.cpp b/WebCore/platform/graphics/cairo/PathCairo.cpp index 3f8d588..24354d2 100644 --- a/WebCore/platform/graphics/cairo/PathCairo.cpp +++ b/WebCore/platform/graphics/cairo/PathCairo.cpp @@ -4,6 +4,7 @@ 2004, 2005, 2006 Rob Buis <buis@kde.org> 2005, 2007 Apple Inc. All Rights reserved. 2007 Alp Toker <alp@atoker.com> + 2008 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,11 +25,13 @@ #include "config.h" #include "Path.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "CairoPath.h" #include "FloatRect.h" +#include "GraphicsContext.h" #include "NotImplemented.h" #include "PlatformString.h" +#include "StrokeStyleApplier.h" #include <cairo.h> #include <math.h> @@ -153,9 +156,78 @@ void Path::addArc(const FloatPoint& p, float r, float sa, float ea, bool anticlo void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius) { - // FIXME: cairo_arc_to not yet in cairo see cairo.h - // cairo_arc_to(m_cr, p1.x(), p1.y(), p2.x(), p2.y()); - notImplemented(); + if (isEmpty()) + return; + + cairo_t* cr = platformPath()->m_cr; + + double x0, y0; + cairo_get_current_point(cr, &x0, &y0); + FloatPoint p0(x0, y0); + if ((p1.x() == p0.x() && p1.y() == p0.y()) || (p1.x() == p2.x() && p1.y() == p2.y()) || radius == 0.f) { + cairo_line_to(cr, p1.x(), p1.y()); + return; + } + + FloatPoint p1p0((p0.x() - p1.x()),(p0.y() - p1.y())); + FloatPoint p1p2((p2.x() - p1.x()),(p2.y() - p1.y())); + float p1p0_length = sqrtf(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y()); + float p1p2_length = sqrtf(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y()); + + double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length); + // all points on a line logic + if (cos_phi == -1) { + cairo_line_to(cr, p1.x(), p1.y()); + return; + } + if (cos_phi == 1) { + // add infinite far away point + unsigned int max_length = 65535; + double factor_max = max_length / p1p0_length; + FloatPoint ep((p0.x() + factor_max * p1p0.x()), (p0.y() + factor_max * p1p0.y())); + cairo_line_to(cr, ep.x(), ep.y()); + return; + } + + float tangent = radius / tan(acos(cos_phi) / 2); + float factor_p1p0 = tangent / p1p0_length; + FloatPoint t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y())); + + FloatPoint orth_p1p0(p1p0.y(), -p1p0.x()); + float orth_p1p0_length = sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y()); + float factor_ra = radius / orth_p1p0_length; + + // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0 + double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length); + if (cos_alpha < 0.f) + orth_p1p0 = FloatPoint(-orth_p1p0.x(), -orth_p1p0.y()); + + FloatPoint p((t_p1p0.x() + factor_ra * orth_p1p0.x()), (t_p1p0.y() + factor_ra * orth_p1p0.y())); + + // calculate angles for addArc + orth_p1p0 = FloatPoint(-orth_p1p0.x(), -orth_p1p0.y()); + float sa = acos(orth_p1p0.x() / orth_p1p0_length); + if (orth_p1p0.y() < 0.f) + sa = 2 * piDouble - sa; + + // anticlockwise logic + bool anticlockwise = false; + + float factor_p1p2 = tangent / p1p2_length; + FloatPoint t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y())); + FloatPoint orth_p1p2((t_p1p2.x() - p.x()),(t_p1p2.y() - p.y())); + float orth_p1p2_length = sqrtf(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y()); + float ea = acos(orth_p1p2.x() / orth_p1p2_length); + if (orth_p1p2.y() < 0) + ea = 2 * piDouble - ea; + if ((sa > ea) && ((sa - ea) < piDouble)) + anticlockwise = true; + if ((sa < ea) && ((ea - sa) > piDouble)) + anticlockwise = true; + + cairo_line_to(cr, t_p1p0.x(), t_p1p0.y()); + + addArc(p, radius, sa, ea, anticlockwise); } void Path::addEllipse(const FloatRect& rect) @@ -188,6 +260,19 @@ FloatRect Path::boundingRect() const return FloatRect(x0, y0, x1 - x0, y1 - y0); } +FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) +{ + cairo_t* cr = platformPath()->m_cr; + if (applier) { + GraphicsContext gc(cr); + applier->strokeStyle(&gc); + } + + double x0, x1, y0, y1; + cairo_stroke_extents(cr, &x0, &y0, &x1, &y1); + return FloatRect(x0, y0, x1 - x0, y1 - y0); +} + bool Path::contains(const FloatPoint& point, WindRule rule) const { if (!boundingRect().contains(point)) @@ -201,6 +286,16 @@ bool Path::contains(const FloatPoint& point, WindRule rule) const return contains; } +bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const +{ + ASSERT(applier); + cairo_t* cr = platformPath()->m_cr; + GraphicsContext gc(cr); + applier->strokeStyle(&gc); + + return cairo_in_stroke(cr, point.x(), point.y()); +} + void Path::apply(void* info, PathApplierFunction function) const { cairo_t* cr = platformPath()->m_cr; @@ -239,7 +334,7 @@ void Path::apply(void* info, PathApplierFunction function) const cairo_path_destroy(path); } -void Path::transform(const AffineTransform& trans) +void Path::transform(const TransformationMatrix& trans) { cairo_t* m_cr = platformPath()->m_cr; cairo_matrix_t c_matrix = cairo_matrix_t(trans); @@ -249,37 +344,39 @@ void Path::transform(const AffineTransform& trans) String Path::debugString() const { - String string = ""; + if (isEmpty()) + return String(); + + String pathString; cairo_path_t* path = cairo_copy_path(platformPath()->m_cr); cairo_path_data_t* data; - if (!path->num_data ) - string = "EMPTY"; - for (int i = 0; i < path->num_data; i += path->data[i].header.length) { data = &path->data[i]; switch (data->header.type) { case CAIRO_PATH_MOVE_TO: - string += String::format("M %.2f,%.2f", + if (i < (path->num_data - path->data[i].header.length)) + pathString += String::format("M%.2f,%.2f ", data[1].point.x, data[1].point.y); break; case CAIRO_PATH_LINE_TO: - string += String::format("L %.2f,%.2f", + pathString += String::format("L%.2f,%.2f ", data[1].point.x, data[1].point.y); break; case CAIRO_PATH_CURVE_TO: - string += String::format("C %.2f,%.2f,%.2f,%.2f,%.2f,%.2f", + pathString += String::format("C%.2f,%.2f,%.2f,%.2f,%.2f,%.2f ", data[1].point.x, data[1].point.y, data[2].point.x, data[2].point.y, data[3].point.x, data[3].point.y); break; case CAIRO_PATH_CLOSE_PATH: - string += "X"; + pathString += "Z "; break; } } + cairo_path_destroy(path); - return string; + return pathString.simplifyWhiteSpace(); } } // namespace WebCore diff --git a/WebCore/platform/graphics/cairo/PatternCairo.cpp b/WebCore/platform/graphics/cairo/PatternCairo.cpp index 16cebf8..7d75db3 100644 --- a/WebCore/platform/graphics/cairo/PatternCairo.cpp +++ b/WebCore/platform/graphics/cairo/PatternCairo.cpp @@ -26,21 +26,22 @@ #include "config.h" #include "Pattern.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "GraphicsContext.h" #include <cairo.h> namespace WebCore { -cairo_pattern_t* Pattern::createPlatformPattern(const AffineTransform& patternTransform) const +cairo_pattern_t* Pattern::createPlatformPattern(const TransformationMatrix& patternTransform) const { cairo_surface_t* surface = tileImage()->nativeImageForCurrentFrame(); if (!surface) return 0; cairo_pattern_t* pattern = cairo_pattern_create_for_surface(surface); - const cairo_matrix_t* pattern_matrix = reinterpret_cast<const cairo_matrix_t*>(&patternTransform); + const TransformationMatrix& inverse = patternTransform.inverse(); + const cairo_matrix_t* pattern_matrix = reinterpret_cast<const cairo_matrix_t*>(&inverse); cairo_pattern_set_matrix(pattern, pattern_matrix); if (m_repeatX || m_repeatY) cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); diff --git a/WebCore/platform/graphics/cairo/AffineTransformCairo.cpp b/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp index 0f2fccd..b78620f 100644 --- a/WebCore/platform/graphics/cairo/AffineTransformCairo.cpp +++ b/WebCore/platform/graphics/cairo/TransformationMatrixCairo.cpp @@ -23,7 +23,7 @@ */ #include "config.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "IntRect.h" #include "FloatRect.h" @@ -34,34 +34,34 @@ namespace WebCore { static const double deg2rad = 0.017453292519943295769; // pi/180 -AffineTransform::AffineTransform() +TransformationMatrix::TransformationMatrix() { cairo_matrix_init_identity(&m_transform); } -AffineTransform::AffineTransform(double a, double b, double c, double d, double tx, double ty) +TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double tx, double ty) { cairo_matrix_init(&m_transform, a, b, c, d, tx, ty); } -AffineTransform::AffineTransform(const PlatformAffineTransform& matrix) +TransformationMatrix::TransformationMatrix(const PlatformTransformationMatrix& matrix) { m_transform = matrix; } -void AffineTransform::setMatrix(double a, double b, double c, double d, double tx, double ty) +void TransformationMatrix::setMatrix(double a, double b, double c, double d, double tx, double ty) { cairo_matrix_init(&m_transform, a, b, c, d, tx, ty); } -void AffineTransform::map(double x, double y, double* x2, double* y2) const +void TransformationMatrix::map(double x, double y, double* x2, double* y2) const { *x2 = x; *y2 = y; cairo_matrix_transform_point(&m_transform, x2, y2); } -IntRect AffineTransform::mapRect(const IntRect &rect) const +IntRect TransformationMatrix::mapRect(const IntRect &rect) const { FloatRect floatRect(rect); FloatRect enclosingFloatRect = this->mapRect(floatRect); @@ -69,7 +69,7 @@ IntRect AffineTransform::mapRect(const IntRect &rect) const return enclosingIntRect(enclosingFloatRect); } -FloatRect AffineTransform::mapRect(const FloatRect &rect) const +FloatRect TransformationMatrix::mapRect(const FloatRect &rect) const { double rectMinX = rect.x(); double rectMaxX = rect.x() + rect.width(); @@ -128,97 +128,97 @@ FloatRect AffineTransform::mapRect(const FloatRect &rect) const return FloatRect(enclosingRectMinX, enclosingRectMinY, enclosingRectWidth, enclosingRectHeight); } -bool AffineTransform::isIdentity() const +bool TransformationMatrix::isIdentity() const { return ((m_transform.xx == 1) && (m_transform.yy == 1) && (m_transform.xy == 0) && (m_transform.yx == 0) && (m_transform.x0 == 0) && (m_transform.y0 == 0)); } -double AffineTransform::a() const +double TransformationMatrix::a() const { return m_transform.xx; } -void AffineTransform::setA(double a) +void TransformationMatrix::setA(double a) { m_transform.xx = a; } -double AffineTransform::b() const +double TransformationMatrix::b() const { return m_transform.yx; } -void AffineTransform::setB(double b) +void TransformationMatrix::setB(double b) { m_transform.yx = b; } -double AffineTransform::c() const +double TransformationMatrix::c() const { return m_transform.xy; } -void AffineTransform::setC(double c) +void TransformationMatrix::setC(double c) { m_transform.xy = c; } -double AffineTransform::d() const +double TransformationMatrix::d() const { return m_transform.yy; } -void AffineTransform::setD(double d) +void TransformationMatrix::setD(double d) { m_transform.yy = d; } -double AffineTransform::e() const +double TransformationMatrix::e() const { return m_transform.x0; } -void AffineTransform::setE(double e) +void TransformationMatrix::setE(double e) { m_transform.x0 = e; } -double AffineTransform::f() const +double TransformationMatrix::f() const { return m_transform.y0; } -void AffineTransform::setF(double f) +void TransformationMatrix::setF(double f) { m_transform.y0 = f; } -void AffineTransform::reset() +void TransformationMatrix::reset() { cairo_matrix_init_identity(&m_transform); } -AffineTransform &AffineTransform::scale(double sx, double sy) +TransformationMatrix &TransformationMatrix::scale(double sx, double sy) { cairo_matrix_scale(&m_transform, sx, sy); return *this; } -AffineTransform &AffineTransform::rotate(double d) +TransformationMatrix &TransformationMatrix::rotate(double d) { cairo_matrix_rotate(&m_transform, d * deg2rad); return *this; } -AffineTransform &AffineTransform::translate(double tx, double ty) +TransformationMatrix &TransformationMatrix::translate(double tx, double ty) { cairo_matrix_translate(&m_transform, tx, ty); return *this; } -AffineTransform &AffineTransform::shear(double sx, double sy) +TransformationMatrix &TransformationMatrix::shear(double sx, double sy) { cairo_matrix_t shear; cairo_matrix_init(&shear, 1, sy, sx, 1, 0, 0); @@ -230,26 +230,26 @@ AffineTransform &AffineTransform::shear(double sx, double sy) return *this; } -double AffineTransform::det() const +double TransformationMatrix::det() const { return m_transform.xx * m_transform.yy - m_transform.xy * m_transform.yx; } -AffineTransform AffineTransform::inverse() const +TransformationMatrix TransformationMatrix::inverse() const { - if (!isInvertible()) return AffineTransform(); + if (!isInvertible()) return TransformationMatrix(); cairo_matrix_t result = m_transform; cairo_matrix_invert(&result); - return AffineTransform(result); + return TransformationMatrix(result); } -AffineTransform::operator cairo_matrix_t() const +TransformationMatrix::operator cairo_matrix_t() const { return m_transform; } -bool AffineTransform::operator== (const AffineTransform &m2) const +bool TransformationMatrix::operator== (const TransformationMatrix &m2) const { return ((m_transform.xx == m2.m_transform.xx) && (m_transform.yy == m2.m_transform.yy) @@ -260,7 +260,7 @@ bool AffineTransform::operator== (const AffineTransform &m2) const } -AffineTransform &AffineTransform::operator*= (const AffineTransform &m2) +TransformationMatrix &TransformationMatrix::operator*= (const TransformationMatrix &m2) { cairo_matrix_t result; cairo_matrix_multiply(&result, &m_transform, &m2.m_transform); @@ -269,7 +269,7 @@ AffineTransform &AffineTransform::operator*= (const AffineTransform &m2) return *this; } -AffineTransform AffineTransform::operator* (const AffineTransform &m2) +TransformationMatrix TransformationMatrix::operator* (const TransformationMatrix &m2) { cairo_matrix_t result; cairo_matrix_multiply(&result, &m_transform, &m2.m_transform); diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp index 3f0e6e7..1cc55a4 100644 --- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp +++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp @@ -28,7 +28,7 @@ #include "config.h" #include "GraphicsContext.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "FloatConversion.h" #include "GraphicsContextPrivate.h" #include "GraphicsContextPlatformPrivateCG.h" @@ -191,11 +191,13 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) } CGContextRef context = platformContext(); - CGContextSaveGState(context); - - CGContextSetShouldAntialias(context, false); + + if (shouldAntialias()) + CGContextSetShouldAntialias(context, false); if (patWidth) { + CGContextSaveGState(context); + // 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. setCGFillColor(context, strokeColor()); // The save/restore make it safe to mutate the fill color here without setting it back to the old color. @@ -245,7 +247,11 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) CGContextStrokePath(context); - CGContextRestoreGState(context); + if (patWidth) + CGContextRestoreGState(context); + + if (shouldAntialias()) + CGContextSetShouldAntialias(context, true); } // This method is only used to draw the little circles used in lists. @@ -358,7 +364,7 @@ void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSp CGContextRestoreGState(context); } -void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias) +void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool antialiased) { if (paintingDisabled() || !fillColor().alpha() && (strokeThickness() <= 0 || strokeStyle() == NoStroke)) return; @@ -368,9 +374,8 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points CGContextRef context = platformContext(); - CGContextSaveGState(context); - - CGContextSetShouldAntialias(context, shouldAntialias); + if (antialiased != shouldAntialias()) + CGContextSetShouldAntialias(context, antialiased); CGContextBeginPath(context); CGContextMoveToPoint(context, points[0].x(), points[0].y()); @@ -379,15 +384,16 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points CGContextClosePath(context); drawPath(); - - CGContextRestoreGState(context); + + if (antialiased != shouldAntialias()) + CGContextSetShouldAntialias(context, shouldAntialias()); } -static void applyStrokePattern(GraphicsContext* context, Pattern* pattern) +void GraphicsContext::applyStrokePattern() { - CGContextRef cgContext = context->platformContext(); + CGContextRef cgContext = platformContext(); - CGPatternRef platformPattern = pattern->createPlatformPattern(context->getCTM()); + CGPatternRef platformPattern = m_common->state.strokePattern.get()->createPlatformPattern(getCTM()); if (!platformPattern) return; @@ -400,11 +406,11 @@ static void applyStrokePattern(GraphicsContext* context, Pattern* pattern) CGPatternRelease(platformPattern); } -static void applyFillPattern(GraphicsContext* context, Pattern* pattern) +void GraphicsContext::applyFillPattern() { - CGContextRef cgContext = context->platformContext(); + CGContextRef cgContext = platformContext(); - CGPatternRef platformPattern = pattern->createPlatformPattern(context->getCTM()); + CGPatternRef platformPattern = m_common->state.fillPattern.get()->createPlatformPattern(getCTM()); if (!platformPattern) return; @@ -460,9 +466,9 @@ void GraphicsContext::drawPath() } if (state.fillColorSpace == PatternColorSpace) - applyFillPattern(this, m_common->state.fillPattern.get()); + applyFillPattern(); if (state.strokeColorSpace == PatternColorSpace) - applyStrokePattern(this, m_common->state.strokePattern.get()); + applyStrokePattern(); CGPathDrawingMode drawingMode; if (calculateDrawingMode(state, drawingMode)) @@ -489,7 +495,7 @@ void GraphicsContext::fillPath() fillPathWithFillRule(context, fillRule()); break; case PatternColorSpace: - applyFillPattern(this, m_common->state.fillPattern.get()); + applyFillPattern(); fillPathWithFillRule(context, fillRule()); break; case GradientColorSpace: @@ -512,11 +518,11 @@ void GraphicsContext::strokePath() CGContextRef context = platformContext(); switch (m_common->state.strokeColorSpace) { case SolidColorSpace: - if (fillColor().alpha()) + if (strokeColor().alpha()) CGContextStrokePath(context); break; case PatternColorSpace: - applyStrokePattern(this, m_common->state.strokePattern.get()); + applyStrokePattern(); CGContextStrokePath(context); break; case GradientColorSpace: @@ -540,7 +546,7 @@ void GraphicsContext::fillRect(const FloatRect& rect) CGContextFillRect(context, rect); break; case PatternColorSpace: - applyFillPattern(this, m_common->state.fillPattern.get()); + applyFillPattern(); CGContextFillRect(context, rect); break; case GradientColorSpace: @@ -614,6 +620,21 @@ void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) CGContextEOClip(platformContext()); } +void GraphicsContext::clipPath(WindRule clipRule) +{ + if (paintingDisabled()) + return; + + CGContextRef context = platformContext(); + + if (!CGContextIsPathEmpty(context)) { + if (clipRule == RULE_EVENODD) + CGContextEOClip(context); + else + CGContextClip(context); + } +} + void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) { if (paintingDisabled()) @@ -670,23 +691,30 @@ void GraphicsContext::setPlatformShadow(const IntSize& size, int blur, const Col { if (paintingDisabled()) return; + CGFloat width = size.width(); + CGFloat height = size.height(); + CGFloat blurRadius = blur; CGContextRef context = platformContext(); - CGAffineTransform transform = CGContextGetCTM(context); - CGFloat A = transform.a * transform.a + transform.b * transform.b; - CGFloat B = transform.a * transform.c + transform.b * transform.d; - CGFloat C = B; - CGFloat D = transform.c * transform.c + transform.d * transform.d; + if (!m_common->state.shadowsIgnoreTransforms) { + CGAffineTransform transform = CGContextGetCTM(context); - CGFloat smallEigenvalue = narrowPrecisionToCGFloat(sqrt(0.5 * ((A + D) - sqrt(4 * B * C + (A - D) * (A - D))))); + CGFloat A = transform.a * transform.a + transform.b * transform.b; + CGFloat B = transform.a * transform.c + transform.b * transform.d; + CGFloat C = B; + CGFloat D = transform.c * transform.c + transform.d * transform.d; - // Extreme "blur" values can make text drawing crash or take crazy long times, so clamp - CGFloat blurRadius = min(blur * smallEigenvalue, narrowPrecisionToCGFloat(1000.0)); + CGFloat smallEigenvalue = narrowPrecisionToCGFloat(sqrt(0.5 * ((A + D) - sqrt(4 * B * C + (A - D) * (A - D))))); - CGSize sizeInDeviceSpace = CGSizeApplyAffineTransform(size, transform); + // Extreme "blur" values can make text drawing crash or take crazy long times, so clamp + blurRadius = min(blur * smallEigenvalue, narrowPrecisionToCGFloat(1000.0)); - CGFloat width = sizeInDeviceSpace.width; - CGFloat height = sizeInDeviceSpace.height; + CGSize sizeInDeviceSpace = CGSizeApplyAffineTransform(size, transform); + + width = sizeInDeviceSpace.width; + height = sizeInDeviceSpace.height; + + } // Work around <rdar://problem/5539388> by ensuring that the offsets will get truncated // to the desired integer. @@ -747,7 +775,27 @@ void GraphicsContext::strokeRect(const FloatRect& r, float lineWidth) { if (paintingDisabled()) return; - CGContextStrokeRectWithWidth(platformContext(), r, lineWidth); + + CGContextRef context = platformContext(); + switch (m_common->state.strokeColorSpace) { + case SolidColorSpace: + if (strokeColor().alpha()) + CGContextStrokeRectWithWidth(context, r, lineWidth); + break; + case PatternColorSpace: + applyStrokePattern(); + CGContextStrokeRectWithWidth(context, r, lineWidth); + break; + case GradientColorSpace: + CGContextSaveGState(context); + setStrokeThickness(lineWidth); + CGContextAddRect(context, r); + CGContextReplacePathWithStrokedPath(context); + CGContextClip(context); + CGContextDrawShading(context, m_common->state.strokeGradient->platformGradient()); + CGContextRestoreGState(context); + break; + } } void GraphicsContext::setLineCap(LineCap cap) @@ -848,7 +896,7 @@ void GraphicsContext::translate(float x, float y) m_data->m_userToDeviceTransformKnownToBeIdentity = false; } -void GraphicsContext::concatCTM(const AffineTransform& transform) +void GraphicsContext::concatCTM(const TransformationMatrix& transform) { if (paintingDisabled()) return; @@ -857,7 +905,7 @@ void GraphicsContext::concatCTM(const AffineTransform& transform) m_data->m_userToDeviceTransformKnownToBeIdentity = false; } -AffineTransform GraphicsContext::getCTM() const +TransformationMatrix GraphicsContext::getCTM() const { return CGContextGetCTM(platformContext()); } @@ -909,8 +957,6 @@ void GraphicsContext::drawLineForText(const IntPoint& point, int width, bool pri if (width <= 0) return; - CGContextSaveGState(platformContext()); - float x = point.x(); float y = point.y(); float lineLength = width; @@ -919,6 +965,8 @@ void GraphicsContext::drawLineForText(const IntPoint& point, int width, bool pri // See http://bugs.webkit.org/show_bug.cgi?id=4255 for details of why 0.5 is the right minimum thickness to use. float thickness = max(strokeThickness(), 0.5f); + bool restoreAntialiasMode = false; + if (!printing) { // On screen, use a minimum thickness of 1.0 in user space (later rounded to an integral number in device space). float adjustedThickness = max(thickness, 1.0f); @@ -933,15 +981,21 @@ void GraphicsContext::drawLineForText(const IntPoint& point, int width, bool pri y = lineRect.origin.y; lineLength = lineRect.size.width; thickness = lineRect.size.height; - CGContextSetShouldAntialias(platformContext(), false); + if (shouldAntialias()) { + CGContextSetShouldAntialias(platformContext(), false); + restoreAntialiasMode = true; + } } } if (fillColor() != strokeColor()) setCGFillColor(platformContext(), strokeColor()); CGContextFillRect(platformContext(), CGRectMake(x, y, lineLength, thickness)); - - CGContextRestoreGState(platformContext()); + if (fillColor() != strokeColor()) + setCGFillColor(platformContext(), fillColor()); + + if (restoreAntialiasMode) + CGContextSetShouldAntialias(platformContext(), true); } void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) @@ -1078,7 +1132,7 @@ void GraphicsContext::setPlatformFillColor(const Color& color) setCGFillColor(platformContext(), color); } -void GraphicsContext::setUseAntialiasing(bool enable) +void GraphicsContext::setPlatformShouldAntialias(bool enable) { if (paintingDisabled()) return; diff --git a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h index 8827ff7..beee660 100644 --- a/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h +++ b/WebCore/platform/graphics/cg/GraphicsContextPlatformPrivateCG.h @@ -34,6 +34,7 @@ public: #if PLATFORM(WIN) , m_hdc(0) , m_transparencyCount(0) + , m_shouldIncludeChildWindows(false) #endif , m_userToDeviceTransformKnownToBeIdentity(false) { @@ -54,7 +55,7 @@ public: void scale(const FloatSize&) {} void rotate(float) {} void translate(float, float) {} - void concatCTM(const AffineTransform&) {} + void concatCTM(const TransformationMatrix&) {} void beginTransparencyLayer() {} void endTransparencyLayer() {} #endif @@ -68,12 +69,13 @@ public: void scale(const FloatSize&); void rotate(float); void translate(float, float); - void concatCTM(const AffineTransform&); + void concatCTM(const TransformationMatrix&); void beginTransparencyLayer() { m_transparencyCount++; } void endTransparencyLayer() { m_transparencyCount--; } HDC m_hdc; unsigned m_transparencyCount; + bool m_shouldIncludeChildWindows; #endif CGContextRef m_cgContext; diff --git a/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/WebCore/platform/graphics/cg/ImageBufferCG.cpp index 502313b..96e5604 100644 --- a/WebCore/platform/graphics/cg/ImageBufferCG.cpp +++ b/WebCore/platform/graphics/cg/ImageBufferCG.cpp @@ -107,7 +107,7 @@ Image* ImageBuffer::image() const PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const { PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height()); - unsigned char* data = result->data()->data().data(); + 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()) memset(data, 0, result->data()->length()); @@ -188,7 +188,7 @@ void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, con unsigned srcBytesPerRow = 4 * source->width(); unsigned destBytesPerRow = 4 * m_size.width(); - unsigned char* srcRows = source->data()->data().data() + originy * srcBytesPerRow + originx * 4; + 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; for (int y = 0; y < numRows; ++y) { for (int x = 0; x < numColumns; x++) { diff --git a/WebCore/platform/graphics/cg/ImageCG.cpp b/WebCore/platform/graphics/cg/ImageCG.cpp index 8609c46..13c8c07 100644 --- a/WebCore/platform/graphics/cg/ImageCG.cpp +++ b/WebCore/platform/graphics/cg/ImageCG.cpp @@ -28,7 +28,7 @@ #if PLATFORM(CG) -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "FloatConversion.h" #include "FloatRect.h" #include "GraphicsContext.h" @@ -47,15 +47,17 @@ namespace WebCore { -void FrameData::clear() +bool FrameData::clear(bool clearMetadata) { + if (clearMetadata) + m_haveMetadata = false; + if (m_frame) { CGImageRelease(m_frame); m_frame = 0; - // NOTE: We purposefully don't reset metadata here, so that even if we - // throw away previously-decoded data, animation loops can still access - // properties like frame durations without re-decoding. + return true; } + return false; } // ================================================ @@ -207,7 +209,7 @@ void Image::drawPatternCallback(void* info, CGContextRef context) CGContextDrawImage(context, GraphicsContext(context).roundToDevicePixels(FloatRect(0, 0, CGImageGetWidth(image), CGImageGetHeight(image))), image); } -void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform, +void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) { if (!nativeImageForCurrentFrame()) @@ -251,9 +253,14 @@ void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const // its buffer is the same size as the overall image. Because a partially decoded CGImageRef with a smaller width or height than the // overall image buffer needs to tile with "gaps", we can't use the optimized tiling call in that case. // FIXME: Could create WebKitSystemInterface SPI for CGCreatePatternWithImage2 and probably make Tiger tile faster as well. + // FIXME: We cannot use CGContextDrawTiledImage with scaled tiles on Leopard, because it suffers from rounding errors. Snow Leopard is ok. float scaledTileWidth = tileRect.width() * narrowPrecisionToFloat(patternTransform.a()); float w = CGImageGetWidth(tileImage); +#ifdef BUILDING_ON_LEOPARD + if (w == size().width() && h == size().height() && scaledTileWidth == tileRect.width() && scaledTileHeight == tileRect.height()) +#else if (w == size().width() && h == size().height()) +#endif CGContextDrawTiledImage(context, FloatRect(adjustedX, adjustedY, scaledTileWidth, scaledTileHeight), subImage); else { #endif diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp index 73907c9..0b276cc 100644 --- a/WebCore/platform/graphics/cg/ImageSourceCG.cpp +++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp @@ -27,8 +27,10 @@ #include "ImageSource.h" #if PLATFORM(CG) +#include "ImageSourceCG.h" #include "IntSize.h" +#include "MIMETypeRegistry.h" #include "SharedBuffer.h" #include <ApplicationServices/ApplicationServices.h> @@ -43,18 +45,23 @@ ImageSource::ImageSource() ImageSource::~ImageSource() { - clear(); + clear(true); } -void ImageSource::clear() +void ImageSource::clear(bool, size_t, SharedBuffer* data, bool allDataReceived) { + // We always destroy the decoder, because there is no API to get it to + // selectively release some of the frames it's holding, and if we don't + // release any of them, we use too much memory on large images. if (m_decoder) { CFRelease(m_decoder); m_decoder = 0; } + if (data) + setData(data, allDataReceived); } -CFDictionaryRef imageSourceOptions() +static CFDictionaryRef imageSourceOptions() { static CFDictionaryRef options; @@ -89,6 +96,14 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived) CFRelease(cfData); } +String ImageSource::filenameExtension() const +{ + if (!m_decoder) + return String(); + CFStringRef imageSourceType = CGImageSourceGetType(m_decoder); + return WebCore::preferredExtensionForImageSourceType(imageSourceType); +} + bool ImageSource::isSizeAvailable() { bool result = false; @@ -210,7 +225,7 @@ float ImageSource::frameDurationAtIndex(size_t index) return duration; } -bool ImageSource::frameHasAlphaAtIndex(size_t index) +bool ImageSource::frameHasAlphaAtIndex(size_t) { // Might be interesting to do this optimization on Mac some day, but for now we're just using this // for the Cairo source, since it uses our decoders, and our decoders can answer this question. diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.h b/WebCore/platform/graphics/cg/ImageSourceCG.h new file mode 100644 index 0000000..d5b4b5a --- /dev/null +++ b/WebCore/platform/graphics/cg/ImageSourceCG.h @@ -0,0 +1,41 @@ +/* + * 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 ImageSourceCG_h +#define ImageSourceCG_h + +#include "ImageSource.h" + +namespace WebCore { + +class String; + +String preferredExtensionForImageSourceType(const String& type); + +String MIMETypeForImageSourceType(const String& type); + +} + +#endif // ImageSourceCG_h diff --git a/WebCore/platform/graphics/cg/ImageSourceCGMac.mm b/WebCore/platform/graphics/cg/ImageSourceCGMac.mm new file mode 100644 index 0000000..297e30a --- /dev/null +++ b/WebCore/platform/graphics/cg/ImageSourceCGMac.mm @@ -0,0 +1,48 @@ +/* + * 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 + * 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 "ImageSourceCG.h" + +#import "PlatformString.h" +#import "wtf/RetainPtr.h" + +namespace WebCore { + +String MIMETypeForImageSourceType(const String& uti) +{ + RetainPtr<CFStringRef> utiref(AdoptCF, uti.createCFString()); + RetainPtr<CFStringRef> mime(AdoptCF, UTTypeCopyPreferredTagWithClass(utiref.get(), kUTTagClassMIMEType)); + return mime.get(); +} + +String preferredExtensionForImageSourceType(const String& uti) +{ + RetainPtr<CFStringRef> type(AdoptCF, uti.createCFString()); + RetainPtr<CFStringRef> extension(AdoptCF, UTTypeCopyPreferredTagWithClass(type.get(), kUTTagClassFilenameExtension)); + return extension.get(); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/cg/ImageSourceCGWin.cpp b/WebCore/platform/graphics/cg/ImageSourceCGWin.cpp new file mode 100644 index 0000000..c7d9a0b --- /dev/null +++ b/WebCore/platform/graphics/cg/ImageSourceCGWin.cpp @@ -0,0 +1,84 @@ +/* + * 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 "ImageSourceCG.h" + +#include "StdLibExtras.h" +#include "StringHash.h" +#include <wtf/HashMap.h> + +namespace WebCore { + +String MIMETypeForImageSourceType(const String& type) +{ + String mimeType; + // FIXME: This approach of taking a UTI like public.type and giving back + // a MIME type like image/type will work for common image UTIs like jpeg, + // png, tiff, gif but won't work for UTIs like: public.jpeg-2000, + // public.xbitmap-image, com.apple.quicktime-image, and others. + if (int dotLocation = type.reverseFind('.')) + mimeType = "image/" + type.substring(dotLocation + 1); + return mimeType; +} + +String preferredExtensionForImageSourceType(const String& type) +{ + if (type.isEmpty()) + return String(); + + typedef HashMap<String, String> StringMap; + DEFINE_STATIC_LOCAL(StringMap, UTIMap, ()); + if (UTIMap.isEmpty()) { + UTIMap.add("public.html", "html"); + UTIMap.add("public.jpeg", "jpeg"); + UTIMap.add("public.jpeg-2000", "jp2"); + UTIMap.add("public.plain-text", "txt"); + UTIMap.add("public.png", "png"); + UTIMap.add("public.tiff", "tiff"); + UTIMap.add("public.xbitmap-image", "xbm"); + UTIMap.add("public.xml", "xml"); + UTIMap.add("com.adobe.illustrator.ai-image", "ai"); + UTIMap.add("com.adobe.pdf", "pdf"); + UTIMap.add("com.adobe.photoshop-image", "psd"); + UTIMap.add("com.adobe.postscript", "ps"); + UTIMap.add("com.apple.icns", "icns"); + UTIMap.add("com.apple.macpaint-image", "pntg"); + UTIMap.add("com.apple.pict", "pict"); + UTIMap.add("com.apple.quicktime-image", "qtif"); + UTIMap.add("com.apple.webarchive", "webarchive"); + UTIMap.add("com.compuserve.gif", "gif"); + UTIMap.add("com.ilm.openexr-image", "exr"); + UTIMap.add("com.kodak.flashpix-image", "fpx"); + UTIMap.add("com.microsoft.bmp", "bmp"); + UTIMap.add("com.microsoft.ico", "ico"); + UTIMap.add("com.netscape.javascript-source", "js"); + UTIMap.add("com.sgi.sgi-image", "sgi"); + UTIMap.add("com.truevision.tga-image", "tga"); + } + return UTIMap.get(type); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/cg/PDFDocumentImage.h b/WebCore/platform/graphics/cg/PDFDocumentImage.h index 5c9d4e1..130c12c 100644 --- a/WebCore/platform/graphics/cg/PDFDocumentImage.h +++ b/WebCore/platform/graphics/cg/PDFDocumentImage.h @@ -42,7 +42,9 @@ namespace WebCore { { return adoptRef(new PDFDocumentImage); } - ~PDFDocumentImage(); + + private: + virtual ~PDFDocumentImage(); virtual bool hasSingleSecurityOrigin() const { return true; } @@ -50,12 +52,11 @@ namespace WebCore { // FIXME: PDF Images are underreporting decoded sizes and will be unable // to prune because these functions are not implemented yet. - virtual void destroyDecodedData(bool incremental = false, bool preserveNearbyFrames = false) { } + virtual void destroyDecodedData(bool /*destroyAll*/ = true) { } virtual unsigned decodedSize() const { return 0; } virtual IntSize size() const; - private: PDFDocumentImage(); virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); diff --git a/WebCore/platform/graphics/cg/PathCG.cpp b/WebCore/platform/graphics/cg/PathCG.cpp index 1382589..ebd0359 100644 --- a/WebCore/platform/graphics/cg/PathCG.cpp +++ b/WebCore/platform/graphics/cg/PathCG.cpp @@ -29,16 +29,43 @@ #if PLATFORM(CG) -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include <ApplicationServices/ApplicationServices.h> #include "FloatRect.h" +#include "GraphicsContext.h" #include "IntRect.h" #include "PlatformString.h" +#include "StrokeStyleApplier.h" #include <wtf/MathExtras.h> namespace WebCore { +static size_t putBytesNowhere(void*, const void*, size_t count) +{ + return count; +} + +static CGContextRef createScratchContext() +{ + CGDataConsumerCallbacks callbacks = { putBytesNowhere, 0 }; + CGDataConsumerRef consumer = CGDataConsumerCreate(0, &callbacks); + CGContextRef context = CGPDFContextCreate(consumer, 0, 0); + CGDataConsumerRelease(consumer); + + CGFloat black[4] = { 0, 0, 0, 1 }; + CGContextSetFillColor(context, black); + CGContextSetStrokeColor(context, black); + + return context; +} + +static inline CGContextRef scratchContext() +{ + static CGContextRef context = createScratchContext(); + return context; +} + Path::Path() : m_path(CGPathCreateMutable()) { @@ -62,7 +89,6 @@ Path& Path::operator=(const Path& other) return *this; } - static void copyClosingSubpathsApplierFunction(void* info, const CGPathElement* element) { CGMutablePathRef path = static_cast<CGMutablePathRef>(info); @@ -109,6 +135,25 @@ bool Path::contains(const FloatPoint &point, WindRule rule) const return ret; } +bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const +{ + ASSERT(applier); + + CGContextRef context = scratchContext(); + + CGContextSaveGState(context); + CGContextBeginPath(context); + CGContextAddPath(context, platformPath()); + + GraphicsContext gc(context); + applier->strokeStyle(&gc); + + bool hitSuccess = CGContextPathContainsPoint(context, point, kCGPathStroke); + CGContextRestoreGState(context); + + return hitSuccess; +} + void Path::translate(const FloatSize& size) { CGAffineTransform translation = CGAffineTransformMake(1, 0, 0, 1, size.width(), size.height()); @@ -123,6 +168,26 @@ FloatRect Path::boundingRect() const return CGPathGetBoundingBox(m_path); } +FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) +{ + CGContextRef context = scratchContext(); + + CGContextSaveGState(context); + CGContextBeginPath(context); + CGContextAddPath(context, platformPath()); + + if (applier) { + GraphicsContext graphicsContext(context); + applier->strokeStyle(&graphicsContext); + } + + CGContextReplacePathWithStrokedPath(context); + CGRect box = CGContextIsPathEmpty(context) ? CGRectZero : CGContextGetPathBoundingBox(context); + CGContextRestoreGState(context); + + return box; +} + void Path::moveTo(const FloatPoint& point) { CGPathMoveToPoint(m_path, 0, point.x(), point.y()); @@ -184,8 +249,8 @@ bool Path::isEmpty() const static void CGPathToCFStringApplierFunction(void* info, const CGPathElement *element) { - CFMutableStringRef string = (CFMutableStringRef)info; - CFStringRef typeString = CFSTR(""); + CFMutableStringRef string = static_cast<CFMutableStringRef>(info); + CGPoint* points = element->points; switch (element->type) { case kCGPathElementMoveToPoint: @@ -204,7 +269,8 @@ static void CGPathToCFStringApplierFunction(void* info, const CGPathElement *ele points[2].x, points[2].y); break; case kCGPathElementCloseSubpath: - typeString = CFSTR("X"); break; + CFStringAppendFormat(string, 0, CFSTR("Z ")); + break; } } @@ -241,7 +307,7 @@ struct PathApplierInfo { PathApplierFunction function; }; -void CGPathApplierToPathApplier(void *info, const CGPathElement *element) +static void CGPathApplierToPathApplier(void *info, const CGPathElement *element) { PathApplierInfo* pinfo = (PathApplierInfo*)info; FloatPoint points[3]; @@ -277,7 +343,7 @@ void Path::apply(void* info, PathApplierFunction function) const CGPathApply(m_path, &pinfo, CGPathApplierToPathApplier); } -void Path::transform(const AffineTransform& transform) +void Path::transform(const TransformationMatrix& transform) { CGMutablePathRef path = CGPathCreateMutable(); CGAffineTransform transformCG = transform; diff --git a/WebCore/platform/graphics/cg/PatternCG.cpp b/WebCore/platform/graphics/cg/PatternCG.cpp index e1f7a69..2b9c12f 100644 --- a/WebCore/platform/graphics/cg/PatternCG.cpp +++ b/WebCore/platform/graphics/cg/PatternCG.cpp @@ -27,7 +27,7 @@ #include "config.h" #include "Pattern.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "GraphicsContext.h" #include <ApplicationServices/ApplicationServices.h> @@ -50,11 +50,11 @@ static void patternReleaseCallback(void* info) static_cast<Image*>(info)->deref(); } -CGPatternRef Pattern::createPlatformPattern(const AffineTransform& transform) const +CGPatternRef Pattern::createPlatformPattern(const TransformationMatrix& transform) const { IntRect tileRect = tileImage()->rect(); - AffineTransform patternTransform = transform; + TransformationMatrix patternTransform = transform; patternTransform.scale(1, -1); patternTransform.translate(0, -tileRect.height()); diff --git a/WebCore/platform/graphics/cg/AffineTransformCG.cpp b/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp index 4f0bca0..9b3181a 100644 --- a/WebCore/platform/graphics/cg/AffineTransformCG.cpp +++ b/WebCore/platform/graphics/cg/TransformationMatrixCG.cpp @@ -24,7 +24,7 @@ */ #include "config.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #if PLATFORM(CG) @@ -36,12 +36,12 @@ namespace WebCore { -AffineTransform::AffineTransform() +TransformationMatrix::TransformationMatrix() : m_transform(CGAffineTransformIdentity) { } -AffineTransform::AffineTransform(double a, double b, double c, double d, double tx, double ty) +TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double tx, double ty) { m_transform = CGAffineTransformMake(narrowPrecisionToCGFloat(a), narrowPrecisionToCGFloat(b), @@ -51,12 +51,12 @@ AffineTransform::AffineTransform(double a, double b, double c, double d, double narrowPrecisionToCGFloat(ty)); } -AffineTransform::AffineTransform(const PlatformAffineTransform& t) +TransformationMatrix::TransformationMatrix(const PlatformTransformationMatrix& t) : m_transform(t) { } -void AffineTransform::setMatrix(double a, double b, double c, double d, double tx, double ty) +void TransformationMatrix::setMatrix(double a, double b, double c, double d, double tx, double ty) { m_transform = CGAffineTransformMake(narrowPrecisionToCGFloat(a), narrowPrecisionToCGFloat(b), @@ -66,147 +66,147 @@ void AffineTransform::setMatrix(double a, double b, double c, double d, double t narrowPrecisionToCGFloat(ty)); } -void AffineTransform::map(double x, double y, double *x2, double *y2) const +void TransformationMatrix::map(double x, double y, double *x2, double *y2) const { CGPoint result = CGPointApplyAffineTransform(CGPointMake(narrowPrecisionToCGFloat(x), narrowPrecisionToCGFloat(y)), m_transform); *x2 = result.x; *y2 = result.y; } -IntRect AffineTransform::mapRect(const IntRect &rect) const +IntRect TransformationMatrix::mapRect(const IntRect &rect) const { return enclosingIntRect(CGRectApplyAffineTransform(CGRect(rect), m_transform)); } -FloatRect AffineTransform::mapRect(const FloatRect &rect) const +FloatRect TransformationMatrix::mapRect(const FloatRect &rect) const { return FloatRect(CGRectApplyAffineTransform(CGRect(rect), m_transform)); } -bool AffineTransform::isIdentity() const +bool TransformationMatrix::isIdentity() const { return CGAffineTransformIsIdentity(m_transform); } -double AffineTransform::a() const +double TransformationMatrix::a() const { return m_transform.a; } -void AffineTransform::setA(double a) +void TransformationMatrix::setA(double a) { m_transform.a = narrowPrecisionToCGFloat(a); } -double AffineTransform::b() const +double TransformationMatrix::b() const { return m_transform.b; } -void AffineTransform::setB(double b) +void TransformationMatrix::setB(double b) { m_transform.b = narrowPrecisionToCGFloat(b); } -double AffineTransform::c() const +double TransformationMatrix::c() const { return m_transform.c; } -void AffineTransform::setC(double c) +void TransformationMatrix::setC(double c) { m_transform.c = narrowPrecisionToCGFloat(c); } -double AffineTransform::d() const +double TransformationMatrix::d() const { return m_transform.d; } -void AffineTransform::setD(double d) +void TransformationMatrix::setD(double d) { m_transform.d = narrowPrecisionToCGFloat(d); } -double AffineTransform::e() const +double TransformationMatrix::e() const { return m_transform.tx; } -void AffineTransform::setE(double e) +void TransformationMatrix::setE(double e) { m_transform.tx = narrowPrecisionToCGFloat(e); } -double AffineTransform::f() const +double TransformationMatrix::f() const { return m_transform.ty; } -void AffineTransform::setF(double f) +void TransformationMatrix::setF(double f) { m_transform.ty = narrowPrecisionToCGFloat(f); } -void AffineTransform::reset() +void TransformationMatrix::reset() { m_transform = CGAffineTransformIdentity; } -AffineTransform &AffineTransform::scale(double sx, double sy) +TransformationMatrix &TransformationMatrix::scale(double sx, double sy) { m_transform = CGAffineTransformScale(m_transform, narrowPrecisionToCGFloat(sx), narrowPrecisionToCGFloat(sy)); return *this; } -AffineTransform &AffineTransform::rotate(double d) +TransformationMatrix &TransformationMatrix::rotate(double d) { m_transform = CGAffineTransformRotate(m_transform, narrowPrecisionToCGFloat(deg2rad(d))); return *this; } -AffineTransform &AffineTransform::translate(double tx, double ty) +TransformationMatrix &TransformationMatrix::translate(double tx, double ty) { m_transform = CGAffineTransformTranslate(m_transform, narrowPrecisionToCGFloat(tx), narrowPrecisionToCGFloat(ty)); return *this; } -AffineTransform &AffineTransform::shear(double sx, double sy) +TransformationMatrix &TransformationMatrix::shear(double sx, double sy) { CGAffineTransform shear = CGAffineTransformMake(1.0f, narrowPrecisionToCGFloat(sy), narrowPrecisionToCGFloat(sx), 1.0f, 0.0f, 0.0f); m_transform = CGAffineTransformConcat(shear, m_transform); return *this; } -double AffineTransform::det() const +double TransformationMatrix::det() const { return m_transform.a * m_transform.d - m_transform.b * m_transform.c; } -AffineTransform AffineTransform::inverse() const +TransformationMatrix TransformationMatrix::inverse() const { if (isInvertible()) - return AffineTransform(CGAffineTransformInvert(m_transform)); - return AffineTransform(); + return TransformationMatrix(CGAffineTransformInvert(m_transform)); + return TransformationMatrix(); } -AffineTransform::operator PlatformAffineTransform() const +TransformationMatrix::operator PlatformTransformationMatrix() const { return m_transform; } -bool AffineTransform::operator== (const AffineTransform &m2) const +bool TransformationMatrix::operator== (const TransformationMatrix &m2) const { return CGAffineTransformEqualToTransform(m_transform, CGAffineTransform(m2)); } -AffineTransform &AffineTransform::operator*= (const AffineTransform &m2) +TransformationMatrix &TransformationMatrix::operator*= (const TransformationMatrix &m2) { m_transform = CGAffineTransformConcat(m_transform, CGAffineTransform(m2)); return *this; } -AffineTransform AffineTransform::operator* (const AffineTransform &m2) +TransformationMatrix TransformationMatrix::operator* (const TransformationMatrix &m2) { return CGAffineTransformConcat(m_transform, CGAffineTransform(m2)); } diff --git a/WebCore/platform/graphics/chromium/ColorChromium.cpp b/WebCore/platform/graphics/chromium/ColorChromium.cpp new file mode 100644 index 0000000..16ca17d --- /dev/null +++ b/WebCore/platform/graphics/chromium/ColorChromium.cpp @@ -0,0 +1,62 @@ +/* + * 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: + * 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" + +namespace WebCore { + +Color focusRingColor() +{ +// FIXME: This should be split up to ColorChromiumWin and ColorChromiumMac. +#if PLATFORM(DARWIN) + // To avoid the Mac Chromium build having to rebasline 500+ layout tests and + // continue to do this w/ new tests that get landed in WebKit, we want to + // run the layout tests w/ the same color that stock WebKit uses. + // + // TODO: For now we've hard coded the color that WebKit uses for layout + // tests. We need to revisit this and do either of the following: + // A. Fully honor the color from the UI, which means collecting the color + // (and change notifications) in the browser process, and messaging the + // color to the render process. + // B. Adding a "layout tests" flag, to control the orage vs. blue colors + // depending if we're running layout tests. + // To see the WebKit implementation of using the UI color and/or a flag for + // layout tests see WebKit/WebCore/platform/graphics/mac/ColorMac.mm. + // (Reality is we just need an api to override the focus color and both + // of the above are covered for what this file needs to provide, the + // two options would be details that happen in other places.) + + // From WebKit: + // static RGBA32 oldAquaFocusRingColorRGBA = 0xFF7DADD9; + static Color oldAquaFocusRingColor(0x7D, 0xAD, 0xD9, 0xFF); + return oldAquaFocusRingColor; +#else + static Color focusRingColor(229, 151, 0, 255); + return focusRingColor; +#endif +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp new file mode 100644 index 0000000..03583a0 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontCacheChromiumWin.cpp @@ -0,0 +1,602 @@ +/* + * Copyright (C) 2006, 2007 Apple Computer, Inc. + * Copyright (c) 2006, 2007, 2008, 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 "FontCache.h" + +#include "ChromiumBridge.h" +#include "Font.h" +#include "FontUtilsChromiumWin.h" +#include "HashMap.h" +#include "HashSet.h" +#include "SimpleFontData.h" +#include "StringHash.h" +#include <unicode/uniset.h> + +#include <windows.h> +#include <objidl.h> +#include <mlang.h> + +using std::min; + +namespace WebCore +{ + +void FontCache::platformInit() +{ + // Not needed on Windows. +} + +// FIXME: consider adding to WebKit String class +static bool charactersAreAllASCII(const String& s) +{ + return charactersAreAllASCII(s.characters(), s.length()); +} + +// When asked for a CJK font with a native name under a non-CJK locale or +// asked for a CJK font with a Romanized name under a CJK locale, +// |GetTextFace| (after |CreateFont*|) returns a 'bogus' value (e.g. Arial). +// This is not consistent with what MSDN says !! +// Therefore, before we call |CreateFont*|, we have to map a Romanized name to +// the corresponding native name under a CJK locale and vice versa +// under a non-CJK locale. +// See the corresponding gecko bugs at +// https://bugzilla.mozilla.org/show_bug.cgi?id=373952 +// https://bugzilla.mozilla.org/show_bug.cgi?id=231426 +static bool LookupAltName(const String& name, String& altName) +{ + struct FontCodepage { + WCHAR* name; + int codePage; + }; + + struct NamePair { + WCHAR* name; + FontCodepage altNameCodepage; + }; + + const int japaneseCodepage = 932; + const int simplifiedChineseCodepage = 936; + const int koreanCodepage = 949; + const int traditionalChineseCodepage = 950; + + // FIXME(jungshik) : This list probably covers 99% of cases. + // To cover the remaining 1% and cut down the file size, + // consider accessing 'NAME' table of a truetype font + // using |GetFontData| and caching the mapping. + // In the table below, the ASCII keys are all lower-cased for + // case-insensitive matching. + static const NamePair namePairs[] = { + // MS Pゴシック, MS PGothic + {L"\xFF2D\xFF33 \xFF30\x30B4\x30B7\x30C3\x30AF", {L"MS PGothic", japaneseCodepage}}, + {L"ms pgothic", {L"\xFF2D\xFF33 \xFF30\x30B4\x30B7\x30C3\x30AF", japaneseCodepage}}, + // MS P明朝, MS PMincho + {L"\xFF2D\xFF33 \xFF30\x660E\x671D", {L"MS PMincho", japaneseCodepage}}, + {L"ms pmincho", {L"\xFF2D\xFF33 \xFF30\x660E\x671D", japaneseCodepage}}, + // MSゴシック, MS Gothic + {L"\xFF2D\xFF33 \x30B4\x30B7\x30C3\x30AF", {L"MS Gothic", japaneseCodepage}}, + {L"ms gothic", {L"\xFF2D\xFF33 \x30B4\x30B7\x30C3\x30AF", japaneseCodepage}}, + // MS 明朝, MS Mincho + {L"\xFF2D\xFF33 \x660E\x671D", {L"MS Mincho", japaneseCodepage}}, + {L"ms mincho", {L"\xFF2D\xFF33 \x660E\x671D", japaneseCodepage}}, + // メイリオ, Meiryo + {L"\x30E1\x30A4\x30EA\x30AA", {L"Meiryo", japaneseCodepage}}, + {L"meiryo", {L"\x30E1\x30A4\x30EA\x30AA", japaneseCodepage}}, + // 바탕, Batang + {L"\xBC14\xD0D5", {L"Batang", koreanCodepage}}, + {L"batang", {L"\xBC14\xD0D5", koreanCodepage}}, + // 바탕체, Batangche + {L"\xBC14\xD0D5\xCCB4", {L"Batangche", koreanCodepage}}, + {L"batangche", {L"\xBC14\xD0D5\xCCB4", koreanCodepage}}, + // 굴림, Gulim + {L"\xAD74\xB9BC", {L"Gulim", koreanCodepage}}, + {L"gulim", {L"\xAD74\xB9BC", koreanCodepage}}, + // 굴림체, Gulimche + {L"\xAD74\xB9BC\xCCB4", {L"Gulimche", koreanCodepage}}, + {L"gulimche", {L"\xAD74\xB9BC\xCCB4", koreanCodepage}}, + // 돋움, Dotum + {L"\xB3CB\xC6C0", {L"Dotum", koreanCodepage}}, + {L"dotum", {L"\xB3CB\xC6C0", koreanCodepage}}, + // 돋움체, Dotumche + {L"\xB3CB\xC6C0\xCCB4", {L"Dotumche", koreanCodepage}}, + {L"dotumche", {L"\xB3CB\xC6C0\xCCB4", koreanCodepage}}, + // 궁서, Gungsuh + {L"\xAD81\xC11C", {L"Gungsuh", koreanCodepage}}, + {L"gungsuh", {L"\xAD81\xC11C", koreanCodepage}}, + // 궁서체, Gungsuhche + {L"\xAD81\xC11C\xCCB4", {L"Gungsuhche", koreanCodepage}}, + {L"gungsuhche", {L"\xAD81\xC11C\xCCB4", koreanCodepage}}, + // 맑은 고딕, Malgun Gothic + {L"\xB9D1\xC740 \xACE0\xB515", {L"Malgun Gothic", koreanCodepage}}, + {L"malgun gothic", {L"\xB9D1\xC740 \xACE0\xB515", koreanCodepage}}, + // 宋体, SimSun + {L"\x5B8B\x4F53", {L"SimSun", simplifiedChineseCodepage}}, + {L"simsun", {L"\x5B8B\x4F53", simplifiedChineseCodepage}}, + // 黑体, SimHei + {L"\x9ED1\x4F53", {L"SimHei", simplifiedChineseCodepage}}, + {L"simhei", {L"\x9ED1\x4F53", simplifiedChineseCodepage}}, + // 新宋体, NSimSun + {L"\x65B0\x5B8B\x4F53", {L"NSimSun", simplifiedChineseCodepage}}, + {L"nsimsun", {L"\x65B0\x5B8B\x4F53", simplifiedChineseCodepage}}, + // 微软雅黑, Microsoft Yahei + {L"\x5FAE\x8F6F\x96C5\x9ED1", {L"Microsoft Yahei", simplifiedChineseCodepage}}, + {L"microsoft yahei", {L"\x5FAE\x8F6F\x96C5\x9ED1", simplifiedChineseCodepage}}, + // 仿宋, FangSong + {L"\x4EFF\x5B8B", {L"FangSong", simplifiedChineseCodepage}}, + {L"fangsong", {L"\x4EFF\x5B8B", simplifiedChineseCodepage}}, + // 楷体, KaiTi + {L"\x6977\x4F53", {L"KaiTi", simplifiedChineseCodepage}}, + {L"kaiti", {L"\x6977\x4F53", simplifiedChineseCodepage}}, + // 仿宋_GB2312, FangSong_GB2312 + {L"\x4EFF\x5B8B_GB2312", {L"FangSong_GB2312", simplifiedChineseCodepage}}, + {L"fangsong_gb2312", {L"\x4EFF\x5B8B_gb2312", simplifiedChineseCodepage}}, + // 楷体_GB2312, KaiTi_GB2312 + {L"\x6977\x4F53", {L"KaiTi_GB2312", simplifiedChineseCodepage}}, + {L"kaiti_gb2312", {L"\x6977\x4F53_gb2312", simplifiedChineseCodepage}}, + // 新細明體, PMingLiu + {L"\x65B0\x7D30\x660E\x9AD4", {L"PMingLiu", traditionalChineseCodepage}}, + {L"pmingliu", {L"\x65B0\x7D30\x660E\x9AD4", traditionalChineseCodepage}}, + // 細明體, MingLiu + {L"\x7D30\x660E\x9AD4", {L"MingLiu", traditionalChineseCodepage}}, + {L"mingliu", {L"\x7D30\x660E\x9AD4", traditionalChineseCodepage}}, + // 微軟正黑體, Microsoft JhengHei + {L"\x5FAE\x8EDF\x6B63\x9ED1\x9AD4", {L"Microsoft JhengHei", traditionalChineseCodepage}}, + {L"microsoft jhengHei", {L"\x5FAE\x8EDF\x6B63\x9ED1\x9AD4", traditionalChineseCodepage}}, + // 標楷體, DFKai-SB + {L"\x6A19\x6977\x9AD4", {L"DFKai-SB", traditionalChineseCodepage}}, + {L"dfkai-sb", {L"\x6A19\x6977\x9AD4", traditionalChineseCodepage}}, + // WenQuanYi Zen Hei + {L"\x6587\x6cc9\x9a5b\x6b63\x9ed1", {L"WenQuanYi Zen Hei", traditionalChineseCodepage}}, + {L"wenquanyi zen hei", {L"\x6587\x6cc9\x9a5b\x6b63\x9ed1", traditionalChineseCodepage}}, + // WenQuanYi Zen Hei + {L"\x6587\x6cc9\x9a7f\x6b63\x9ed1", {L"WenQuanYi Zen Hei", simplifiedChineseCodepage}}, + {L"wenquanyi zen hei", {L"\x6587\x6cc9\x9a7f\x6b63\x9ed1", simplifiedChineseCodepage}}, + // AR PL ShanHeiSun Uni, + {L"\x6587\x9f0e\x0050\x004c\x7d30\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", + {L"AR PL ShanHeiSun Uni", traditionalChineseCodepage}}, + {L"ar pl shanheisun uni", + {L"\x6587\x9f0e\x0050\x004c\x7d30\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", traditionalChineseCodepage}}, + // AR PL ShanHeiSun Uni, + {L"\x6587\x9f0e\x0050\x004c\x7ec6\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", + {L"AR PL ShanHeiSun Uni", simplifiedChineseCodepage}}, + {L"ar pl shanheisun uni", + {L"\x6587\x9f0e\x0050\x004c\x7ec6\x4e0a\x6d77\x5b8b\x0055\x006e\x0069", simplifiedChineseCodepage}}, + // AR PL ZenKai Uni + // Traditional Chinese and Simplified Chinese names are + // identical. + {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", {L"AR PL ZenKai Uni", traditionalChineseCodepage}}, + {L"ar pl zenkai uni", {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", traditionalChineseCodepage}}, + {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", {L"AR PL ZenKai Uni", simplifiedChineseCodepage}}, + {L"ar pl zenkai uni", {L"\x6587\x0050\x004C\x4E2D\x6977\x0055\x006E\x0069", simplifiedChineseCodepage}}, + }; + + typedef HashMap<String, const FontCodepage*> NameMap; + static NameMap* fontNameMap = 0; + + if (!fontNameMap) { + size_t numElements = sizeof(namePairs) / sizeof(NamePair); + fontNameMap = new NameMap; + for (size_t i = 0; i < numElements; ++i) + fontNameMap->set(String(namePairs[i].name), &(namePairs[i].altNameCodepage)); + } + + bool isAscii = false; + String n; + // use |lower| only for ASCII names + // For non-ASCII names, we don't want to invoke an expensive + // and unnecessary |lower|. + if (charactersAreAllASCII(name)) { + isAscii = true; + n = name.lower(); + } else + n = name; + + NameMap::iterator iter = fontNameMap->find(n); + if (iter == fontNameMap->end()) + return false; + + static int systemCp = ::GetACP(); + int fontCp = iter->second->codePage; + + if ((isAscii && systemCp == fontCp) || (!isAscii && systemCp != fontCp)) { + altName = String(iter->second->name); + return true; + } + + return false; +} + +static HFONT createFontIndirectAndGetWinName(const String& family, LOGFONT* winfont, String* winName) +{ + int len = min(static_cast<int>(family.length()), LF_FACESIZE - 1); + memcpy(winfont->lfFaceName, family.characters(), len * sizeof(WORD)); + winfont->lfFaceName[len] = '\0'; + + HFONT hfont = CreateFontIndirect(winfont); + if (!hfont) + return 0; + + HDC dc = GetDC(0); + HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont)); + WCHAR name[LF_FACESIZE]; + unsigned resultLength = GetTextFace(dc, LF_FACESIZE, name); + if (resultLength > 0) + resultLength--; // ignore the null terminator + + SelectObject(dc, oldFont); + ReleaseDC(0, dc); + *winName = String(name, resultLength); + return hfont; +} + +// This maps font family names to their repertoires of supported Unicode +// 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; + +static bool fontContainsCharacter(const FontPlatformData* fontData, + const wchar_t* family, UChar32 character) +{ + // FIXME: For non-BMP characters, GetFontUnicodeRanges is of + // no use. We have to read directly from the cmap table of a font. + // Return true for now. + if (character > 0xFFFF) + return true; + + // This cache is just leaked on shutdown. + static FontCmapCache* fontCmapCache = 0; + if (!fontCmapCache) + fontCmapCache = new FontCmapCache; + + HashMap<const wchar_t*, UnicodeSet*>::iterator it = fontCmapCache->find(family); + if (it != fontCmapCache->end()) + return it->second->contains(character); + + HFONT hfont = fontData->hfont(); + HDC hdc = GetDC(0); + HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(hdc, hfont)); + int count = GetFontUnicodeRanges(hdc, 0); + if (count == 0 && ChromiumBridge::ensureFontLoaded(hfont)) + count = GetFontUnicodeRanges(hdc, 0); + if (count == 0) { + ASSERT_NOT_REACHED(); + SelectObject(hdc, oldFont); + ReleaseDC(0, hdc); + return true; + } + + static Vector<char, 512> glyphsetBuffer; + glyphsetBuffer.resize(GetFontUnicodeRanges(hdc, 0)); + GLYPHSET* glyphset = reinterpret_cast<GLYPHSET*>(glyphsetBuffer.data()); + // In addition, refering to the OS/2 table and converting the codepage list + // to the coverage map might be faster. + count = GetFontUnicodeRanges(hdc, glyphset); + ASSERT(count > 0); + SelectObject(hdc, oldFont); + ReleaseDC(0, hdc); + + // FIXME: consider doing either of the following two: + // 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; + while (i < glyphset->cRanges) { + WCHAR start = glyphset->ranges[i].wcLow; + cmap->add(start, start + glyphset->ranges[i].cGlyphs - 1); + i++; + } + cmap->freeze(); + // We don't lowercase |family| because all of them are under our control + // and they're already lowercased. + fontCmapCache->set(family, cmap); + return cmap->contains(character); +} + +// Given the desired base font, this will create a SimpleFontData for a specific +// font that can be used to render the given range of characters. +const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length) +{ + // FIXME: Consider passing fontDescription.dominantScript() + // to GetFallbackFamily here. + FontDescription fontDescription = font.fontDescription(); + UChar32 c; + UScriptCode script; + const wchar_t* family = getFallbackFamily(characters, length, + fontDescription.genericFamily(), &c, &script); + FontPlatformData* data = 0; + if (family) + data = getCachedFontPlatformData(font.fontDescription(), AtomicString(family, wcslen(family)), false); + + // Last resort font list : PanUnicode. CJK fonts have a pretty + // large repertoire. Eventually, we need to scan all the fonts + // on the system to have a Firefox-like coverage. + // Make sure that all of them are lowercased. + const static wchar_t* const cjkFonts[] = { + L"arial unicode ms", + L"ms pgothic", + L"simsun", + L"gulim", + L"pmingliu", + L"wenquanyi zen hei", // partial CJK Ext. A coverage but more + // widely known to Chinese users. + L"ar pl shanheisun uni", + L"ar pl zenkai uni", + L"han nom a", // Complete CJK Ext. A coverage + L"code2000", // Complete CJK Ext. A coverage + // CJK Ext. B fonts are not listed here because it's of no use + // with our current non-BMP character handling because we use + // Uniscribe for it and that code path does not go through here. + }; + + const static wchar_t* const commonFonts[] = { + L"tahoma", + L"arial unicode ms", + L"lucida sans unicode", + L"microsoft sans serif", + L"palatino linotype", + // Four fonts below (and code2000 at the end) are not from MS, but + // once installed, cover a very wide range of characters. + L"freeserif", + L"freesans", + L"gentium", + L"gentiumalt", + L"ms pgothic", + L"simsun", + L"gulim", + L"pmingliu", + L"code2000", + }; + + const wchar_t* const* panUniFonts = 0; + int numFonts = 0; + if (script == USCRIPT_HAN) { + panUniFonts = cjkFonts; + numFonts = ARRAYSIZE(cjkFonts); + } else { + panUniFonts = commonFonts; + numFonts = ARRAYSIZE(commonFonts); + } + // Font returned from GetFallbackFamily may not cover |characters| + // because it's based on script to font mapping. This problem is + // critical enough for non-Latin scripts (especially Han) to + // warrant an additional (real coverage) check with fontCotainsCharacter. + int i; + for (i = 0; (!data || !fontContainsCharacter(data, family, c)) && i < numFonts; ++i) { + family = panUniFonts[i]; + data = getCachedFontPlatformData(font.fontDescription(), AtomicString(family, wcslen(family))); + } + if (i < numFonts) // we found the font that covers this character ! + return getCachedFontData(data); + + return 0; + +} + +const AtomicString& FontCache::alternateFamilyName(const AtomicString& familyName) +{ + // Note that mapping to Courier is removed because + // because it's a bitmap font on Windows. + // Alias Courier -> Courier New + static AtomicString courier("Courier"), courierNew("Courier New"); + if (equalIgnoringCase(familyName, courier)) + return courierNew; + + // Alias Times <-> Times New Roman. + static AtomicString times("Times"), timesNewRoman("Times New Roman"); + if (equalIgnoringCase(familyName, times)) + return timesNewRoman; + if (equalIgnoringCase(familyName, timesNewRoman)) + return times; + + // Alias Helvetica <-> Arial + static AtomicString arial("Arial"), helvetica("Helvetica"); + if (equalIgnoringCase(familyName, helvetica)) + return arial; + if (equalIgnoringCase(familyName, arial)) + return helvetica; + + // We block bitmap fonts altogether so that we have to + // alias MS Sans Serif (bitmap font) -> Microsoft Sans Serif (truetype font) + static AtomicString msSans("MS Sans Serif"); + static AtomicString microsoftSans("Microsoft Sans Serif"); + if (equalIgnoringCase(familyName, msSans)) + return microsoftSans; + + // Alias MS Serif (bitmap) -> Times New Roman (truetype font). There's no + // 'Microsoft Sans Serif-equivalent' for Serif. + static AtomicString msSerif("MS Serif"); + if (equalIgnoringCase(familyName, msSerif)) + return timesNewRoman; + + // FIXME: should we map 'system' to something ('Tahoma') ? + return emptyAtom; +} + +FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) +{ + return 0; +} + +FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& description) +{ + FontDescription::GenericFamilyType generic = description.genericFamily(); + // FIXME: Mapping webkit generic to GenericFamilyType needs to + // be more intelligent. + // This spot rarely gets reached. GetFontDataForCharacters() gets hit a lot + // more often (see FIXME comment there). + const wchar_t* family = getFontFamilyForScript(description.dominantScript(), generic); + + if (family) + return getCachedFontPlatformData(description, AtomicString(family, wcslen(family))); + + // 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"); + static AtomicString courierStr("Courier New"); + static AtomicString arialStr("Arial"); + + AtomicString& fontStr = timesStr; + if (generic == FontDescription::SansSerifFamily) + fontStr = arialStr; + else if (generic == FontDescription::MonospaceFamily) + fontStr = courierStr; + + return getCachedFontPlatformData(description, fontStr); +} + +static LONG toGDIFontWeight(FontWeight fontWeight) +{ + static LONG gdiFontWeights[] = { + FW_THIN, // FontWeight100 + FW_EXTRALIGHT, // FontWeight200 + FW_LIGHT, // FontWeight300 + FW_NORMAL, // FontWeight400 + FW_MEDIUM, // FontWeight500 + FW_SEMIBOLD, // FontWeight600 + FW_BOLD, // FontWeight700 + FW_EXTRABOLD, // FontWeight800 + FW_HEAVY // FontWeight900 + }; + return gdiFontWeights[fontWeight]; +} + +// FIXME: This may not be the best place to put this function +AtomicString FontCache::getGenericFontForScript(UScriptCode script, const FontDescription& description) +{ + const wchar_t* scriptFont = getFontFamilyForScript( script, description.genericFamily()); + return scriptFont ? AtomicString(scriptFont, wcslen(scriptFont)) : emptyAtom; +} + +static void FillLogFont(const FontDescription& fontDescription, LOGFONT* winfont) +{ + // The size here looks unusual. The negative number is intentional. + // Unlike WebKit trunk, we don't multiply the size by 32. That seems to be + // some kind of artifact of their CG backend, or something. + winfont->lfHeight = -fontDescription.computedPixelSize(); + winfont->lfWidth = 0; + winfont->lfEscapement = 0; + winfont->lfOrientation = 0; + winfont->lfUnderline = false; + winfont->lfStrikeOut = false; + winfont->lfCharSet = DEFAULT_CHARSET; + winfont->lfOutPrecision = OUT_TT_ONLY_PRECIS; + winfont->lfQuality = ChromiumBridge::layoutTestMode() ? NONANTIALIASED_QUALITY : DEFAULT_QUALITY; // Honor user's desktop settings. + winfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + winfont->lfItalic = fontDescription.italic(); + winfont->lfWeight = toGDIFontWeight(fontDescription.weight()); +} + +struct TraitsInFamilyProcData { + TraitsInFamilyProcData(const AtomicString& familyName) + : m_familyName(familyName) + { + } + + const AtomicString& m_familyName; + HashSet<unsigned> m_traitsMasks; +}; + +static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) +{ + TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>(lParam); + + unsigned traitsMask = 0; + traitsMask |= logFont->lfItalic ? FontStyleItalicMask : FontStyleNormalMask; + traitsMask |= FontVariantNormalMask; + LONG weight = logFont->lfWeight; + traitsMask |= weight == FW_THIN ? FontWeight100Mask : + weight == FW_EXTRALIGHT ? FontWeight200Mask : + weight == FW_LIGHT ? FontWeight300Mask : + weight == FW_NORMAL ? FontWeight400Mask : + weight == FW_MEDIUM ? FontWeight500Mask : + weight == FW_SEMIBOLD ? FontWeight600Mask : + weight == FW_BOLD ? FontWeight700Mask : + weight == FW_EXTRABOLD ? FontWeight800Mask : + FontWeight900Mask; + procData->m_traitsMasks.add(traitsMask); + return 1; +} + +void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks) +{ + HDC hdc = GetDC(0); + + LOGFONT logFont; + logFont.lfCharSet = DEFAULT_CHARSET; + unsigned familyLength = min(familyName.length(), static_cast<unsigned>(LF_FACESIZE - 1)); + memcpy(logFont.lfFaceName, familyName.characters(), familyLength * sizeof(UChar)); + logFont.lfFaceName[familyLength] = 0; + logFont.lfPitchAndFamily = 0; + + TraitsInFamilyProcData procData(familyName); + EnumFontFamiliesEx(hdc, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0); + copyToVector(procData.m_traitsMasks, traitsMasks); + + ReleaseDC(0, hdc); +} + +FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) +{ + LOGFONT winfont = {0}; + FillLogFont(fontDescription, &winfont); + + // Windows will always give us a valid pointer here, even if the face name + // is non-existent. We have to double-check and see if the family name was + // really used. + String winName; + HFONT hfont = createFontIndirectAndGetWinName(family, &winfont, &winName); + if (!hfont) + return 0; + + // FIXME: Do we need to use predefined fonts "guaranteed" to exist + // when we're running in layout-test mode? + if (!equalIgnoringCase(family, winName)) { + // For CJK fonts with both English and native names, + // GetTextFace returns a native name under the font's "locale" + // and an English name under other locales regardless of + // lfFaceName field of LOGFONT. As a result, we need to check + // if a font has an alternate name. If there is, we need to + // compare it with what's requested in the first place. + String altName; + if (!LookupAltName(family, altName) || + !equalIgnoringCase(altName, winName)) { + DeleteObject(hfont); + return 0; + } + } + + return new FontPlatformData(hfont, + fontDescription.computedPixelSize()); +} + +} diff --git a/WebCore/platform/graphics/chromium/FontCacheLinux.cpp b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp new file mode 100644 index 0000000..f187c55 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontCacheLinux.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2006, 2007, 2008, 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 "FontCache.h" + +#include <fontconfig/fontconfig.h> + +#include "AtomicString.h" +#include "CString.h" +#include "Font.h" +#include "FontDescription.h" +#include "FontPlatformData.h" +#include "Logging.h" +#include "NotImplemented.h" +#include "SimpleFontData.h" + +#include "SkPaint.h" +#include "SkTypeface.h" +#include "SkUtils.h" + +namespace WebCore { + +void FontCache::platformInit() +{ +} + +const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, + const UChar* characters, + int length) +{ + FcCharSet* cset = FcCharSetCreate(); + for (int i = 0; i < length; ++i) + FcCharSetAddChar(cset, characters[i]); + + FcPattern* pattern = FcPatternCreate(); + + FcValue fcvalue; + fcvalue.type = FcTypeCharSet; + fcvalue.u.c = cset; + FcPatternAdd(pattern, FC_CHARSET, fcvalue, 0); + + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + FcResult result; + FcPattern* match = FcFontMatch(0, pattern, &result); + FcPatternDestroy(pattern); + + SimpleFontData* ret = 0; + + if (match) { + FcChar8* family; + if (FcPatternGetString(match, FC_FAMILY, 0, &family) == FcResultMatch) { + FontPlatformData* fpd = + createFontPlatformData(font.fontDescription(), AtomicString((char*) family)); + ret = new SimpleFontData(*fpd); + } + FcPatternDestroy(match); + } + + FcCharSetDestroy(cset); + + return ret; +} + +const AtomicString& FontCache::alternateFamilyName(const AtomicString& familyName) +{ + notImplemented(); + + // This is just to stop GCC emitting a warning about returning a reference + // to a temporary variable + static AtomicString a; + return a; +} + +FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) +{ + return 0; +} + +FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& description) +{ + static AtomicString arialStr("Arial"); + return getCachedFontPlatformData(description, arialStr); +} + +void FontCache::getTraitsInFamily(const AtomicString& familyName, + Vector<unsigned>& traitsMasks) +{ + notImplemented(); +} + +FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, + const AtomicString& family) +{ + const char* name = 0; + CString s; + + if (family.length() == 0) { + static const struct { + FontDescription::GenericFamilyType mType; + const char* mName; + } fontDescriptions[] = { + { FontDescription::SerifFamily, "serif" }, + { FontDescription::SansSerifFamily, "sans-serif" }, + { FontDescription::MonospaceFamily, "monospace" }, + { FontDescription::CursiveFamily, "cursive" }, + { FontDescription::FantasyFamily, "fantasy" } + }; + + FontDescription::GenericFamilyType type = fontDescription.genericFamily(); + for (unsigned i = 0; i < SK_ARRAY_COUNT(fontDescriptions); i++) { + if (type == fontDescriptions[i].mType) { + name = fontDescriptions[i].mName; + break; + } + } + // if we fall out of the loop, it's ok for name to still be 0 + } + else { // convert the name to utf8 + s = family.string().utf8(); + name = s.data(); + } + + int style = SkTypeface::kNormal; + if (fontDescription.weight() >= FontWeightBold) + style |= SkTypeface::kBold; + if (fontDescription.italic()) + style |= SkTypeface::kItalic; + + SkTypeface* tf = SkTypeface::Create(name, static_cast<SkTypeface::Style>(style)); + if (!tf) + return 0; + + FontPlatformData* result = + new FontPlatformData(tf, + fontDescription.computedSize(), + (style & SkTypeface::kBold) && !tf->isBold(), + (style & SkTypeface::kItalic) && !tf->isItalic()); + tf->unref(); + return result; +} + +AtomicString FontCache::getGenericFontForScript(UScriptCode script, + const FontDescription& descript) +{ + notImplemented(); + return AtomicString(); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/FontChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp new file mode 100644 index 0000000..3cf18a6 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontChromiumWin.cpp @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2006, 2007 Apple Computer, Inc. + * Copyright (c) 2006, 2007, 2008, 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 "Font.h" + +#include "TransformationMatrix.h" +#include "ChromiumBridge.h" +#include "FontFallbackList.h" +#include "GlyphBuffer.h" +#include "PlatformContextSkia.h" +#include "SimpleFontData.h" +#include "SkiaFontWin.h" +#include "SkiaUtils.h" +#include "UniscribeHelperTextRun.h" + +#include "skia/ext/platform_canvas_win.h" +#include "skia/ext/skia_utils_win.h" // FIXME: remove this dependency. + +#include <windows.h> + +namespace WebCore { + +static bool windowsCanHandleTextDrawing(GraphicsContext* context) +{ + // Check for non-translation transforms. Sometimes zooms will look better in + // Skia, and sometimes better in Windows. The main problem is that zooming + // in using Skia will show you the hinted outlines for the smaller size, + // which look weird. All else being equal, it's better to use Windows' text + // drawing, so we don't check for zooms. + const TransformationMatrix& matrix = context->getCTM(); + if (matrix.b() != 0 || matrix.c() != 0) // Check for skew. + return false; + + // Check for stroke effects. + if (context->platformContext()->getTextDrawingMode() != cTextFill) + return false; + + // Check for shadow effects. + if (context->platformContext()->getDrawLooper()) + return false; + + return true; +} + +// Skia equivalents to Windows text drawing functions. They +// will get the outlines from Windows and draw then using Skia using the given +// parameters in the paint arguments. This allows more complex effects and +// transforms to be drawn than Windows allows. +// +// These functions will be significantly slower than Windows GDI, and the text +// will look different (no ClearType), so use only when necessary. +// +// When you call a Skia* text drawing function, various glyph outlines will be +// cached. As a result, you should call SkiaWinOutlineCache::removePathsForFont +// when the font is destroyed so that the cache does not outlive the font (since +// the HFONTs are recycled). + +// Analog of the Windows GDI function DrawText, except using the given SkPaint +// attributes for the text. See above for more. +// +// Returns true of the text was drawn successfully. False indicates an error +// from Windows. +static bool skiaDrawText(HFONT hfont, + SkCanvas* canvas, + const SkPoint& point, + SkPaint* paint, + const WORD* glyphs, + const int* advances, + int numGlyphs) +{ + HDC dc = GetDC(0); + HGDIOBJ oldFont = SelectObject(dc, hfont); + + canvas->save(); + canvas->translate(point.fX, point.fY); + + for (int i = 0; i < numGlyphs; i++) { + const SkPath* path = SkiaWinOutlineCache::lookupOrCreatePathForGlyph(dc, hfont, glyphs[i]); + if (!path) + return false; + canvas->drawPath(*path, *paint); + canvas->translate(advances[i], 0); + } + + canvas->restore(); + + SelectObject(dc, oldFont); + ReleaseDC(0, dc); + return true; +} + +static bool paintSkiaText(PlatformContextSkia* platformContext, + HFONT hfont, + int numGlyphs, + const WORD* glyphs, + const int* advances, + const SkPoint& origin) +{ + int textMode = platformContext->getTextDrawingMode(); + + // Filling (if necessary). This is the common case. + SkPaint paint; + platformContext->setupPaintForFilling(&paint); + paint.setFlags(SkPaint::kAntiAlias_Flag); + bool didFill = false; + if ((textMode & cTextFill) && SkColorGetA(paint.getColor())) { + if (!skiaDrawText(hfont, platformContext->canvas(), origin, &paint, &glyphs[0], &advances[0], numGlyphs)) + return false; + didFill = true; + } + + // Stroking on top (if necessary). + if ((textMode & WebCore::cTextStroke) + && platformContext->getStrokeStyle() != NoStroke + && platformContext->getStrokeThickness() > 0) { + + paint.reset(); + platformContext->setupPaintForStroking(&paint, 0, 0); + paint.setFlags(SkPaint::kAntiAlias_Flag); + if (didFill) { + // If there is a shadow and we filled above, there will already be + // a shadow. We don't want to draw it again or it will be too dark + // and it will go on top of the fill. + // + // Note that this isn't strictly correct, since the stroke could be + // very thick and the shadow wouldn't account for this. The "right" + // thing would be to draw to a new layer and then draw that layer + // with a shadow. But this is a lot of extra work for something + // that isn't normally an issue. + paint.setLooper(0)->safeUnref(); + } + + if (!skiaDrawText(hfont, platformContext->canvas(), origin, &paint, &glyphs[0], &advances[0], numGlyphs)) + return false; + } + return true; +} + +void Font::drawGlyphs(GraphicsContext* graphicsContext, + const SimpleFontData* font, + const GlyphBuffer& glyphBuffer, + int from, + int numGlyphs, + const FloatPoint& point) const +{ + PlatformGraphicsContext* context = graphicsContext->platformContext(); + + // Max buffer length passed to the underlying windows API. + const int kMaxBufferLength = 1024; + // Default size for the buffer. It should be enough for most of cases. + const int kDefaultBufferLength = 256; + + SkColor color = context->fillColor(); + unsigned char alpha = SkColorGetA(color); + // Skip 100% transparent text; no need to draw anything. + if (!alpha && context->getStrokeStyle() == NoStroke) + return; + + // Set up our graphics context. + HDC hdc = context->canvas()->beginPlatformPaint(); + HGDIOBJ oldFont = SelectObject(hdc, font->platformData().hfont()); + + // 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); + + // Windows needs the characters and the advances in nice contiguous + // buffers, which we build here. + Vector<WORD, kDefaultBufferLength> glyphs; + Vector<int, kDefaultBufferLength> advances; + + // Compute the coordinate. The 'origin' represents the baseline, so we need + // to move it up to the top of the bounding square. + int x = static_cast<int>(point.x()); + int lineTop = static_cast<int>(point.y()) - font->ascent(); + + bool canUseGDI = windowsCanHandleTextDrawing(graphicsContext); + + // We draw the glyphs in chunks to avoid having to do a heap allocation for + // the arrays of characters and advances. Since ExtTextOut is the + // lowest-level text output function on Windows, there should be little + // penalty for splitting up the text. On the other hand, the buffer cannot + // be bigger than 4094 or the function will fail. + int glyphIndex = 0; + while (glyphIndex < numGlyphs) { + // how many chars will be in this chunk? + int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex); + + glyphs.resize(curLen); + advances.resize(curLen); + + int curWidth = 0; + for (int i = 0; i < curLen; ++i, ++glyphIndex) { + glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex); + advances[i] = static_cast<int>(glyphBuffer.advanceAt(from + glyphIndex)); + curWidth += advances[i]; + } + + bool success = false; + for (int executions = 0; executions < 2; ++executions) { + if (canUseGDI) + success = !!ExtTextOut(hdc, x, lineTop, ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), curLen, &advances[0]); + else { + // Skia's text draing origin is the baseline, like WebKit, not + // the top, like Windows. + SkPoint origin = { x, point.y() }; + success = paintSkiaText(context, font->platformData().hfont(), numGlyphs, reinterpret_cast<const WORD*>(&glyphs[0]), &advances[0], origin); + } + + if (!success && executions == 0) { + // Ask the browser to load the font for us and retry. + ChromiumBridge::ensureFontLoaded(font->platformData().hfont()); + continue; + } + break; + } + + ASSERT(success); + + x += curWidth; + } + + SelectObject(hdc, oldFont); + context->canvas()->endPlatformPaint(); +} + +FloatRect Font::selectionRectForComplexText(const TextRun& run, + const IntPoint& point, + int h, + int from, + int to) const +{ + UniscribeHelperTextRun state(run, *this); + float left = static_cast<float>(point.x() + state.characterToX(from)); + float right = static_cast<float>(point.x() + state.characterToX(to)); + + // If the text is RTL, left will actually be after right. + if (left < right) + return FloatRect(left, static_cast<float>(point.y()), + right - left, static_cast<float>(h)); + + return FloatRect(right, static_cast<float>(point.y()), + left - right, static_cast<float>(h)); +} + +void Font::drawComplexText(GraphicsContext* graphicsContext, + const TextRun& run, + const FloatPoint& point, + int from, + int to) const +{ + PlatformGraphicsContext* context = graphicsContext->platformContext(); + UniscribeHelperTextRun state(run, *this); + + SkColor color = context->fillColor(); + unsigned char alpha = SkColorGetA(color); + // Skip 100% transparent text; no need to draw anything. + if (!alpha) + return; + + HDC hdc = context->canvas()->beginPlatformPaint(); + + // 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); + + // Uniscribe counts the coordinates from the upper left, while WebKit uses + // the baseline, so we have to subtract off the ascent. + state.draw(hdc, static_cast<int>(point.x()), static_cast<int>(point.y() - ascent()), from, to); + context->canvas()->endPlatformPaint(); +} + +float Font::floatWidthForComplexText(const TextRun& run) const +{ + UniscribeHelperTextRun state(run, *this); + return static_cast<float>(state.width()); +} + +int Font::offsetForPositionForComplexText(const TextRun& run, int x, + bool includePartialGlyphs) const +{ + // Mac code ignores includePartialGlyphs, and they don't know what it's + // supposed to do, so we just ignore it as well. + UniscribeHelperTextRun state(run, *this); + int charIndex = state.xToCharacter(x); + + // XToCharacter will return -1 if the position is before the first + // character (we get called like this sometimes). + if (charIndex < 0) + charIndex = 0; + return charIndex; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp new file mode 100644 index 0000000..8f8df88 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2007 Apple Computer, Inc. + * Copyright (c) 2007, 2008, 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 "FontCustomPlatformData.h" + +#if PLATFORM(WIN_OS) +#include "Base64.h" +#include "ChromiumBridge.h" +#include "OpenTypeUtilities.h" +#endif + +#include "FontPlatformData.h" +#include "NotImplemented.h" +#include "SharedBuffer.h" + +#if PLATFORM(WIN_OS) +#include <objbase.h> +#include <t2embapi.h> +#pragma comment(lib, "t2embed") +#endif + +namespace WebCore { + +FontCustomPlatformData::~FontCustomPlatformData() +{ +#if PLATFORM(WIN_OS) + if (m_fontReference) { + if (m_name.isNull()) { + ULONG status; + TTDeleteEmbeddedFont(m_fontReference, 0, &status); + } else + RemoveFontMemResourceEx(m_fontReference); + } +#endif +} + +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode mode) +{ +#if PLATFORM(WIN_OS) + ASSERT(m_fontReference); + + LOGFONT logFont; + if (m_name.isNull()) + TTGetNewFontName(&m_fontReference, logFont.lfFaceName, LF_FACESIZE, 0, 0); + else { + // m_name comes from createUniqueFontName, which, in turn, gets + // it from base64-encoded uuid (128-bit). So, m_name + // can never be longer than LF_FACESIZE (32). + if (m_name.length() + 1 >= LF_FACESIZE) { + ASSERT_NOT_REACHED(); + return FontPlatformData(); + } + memcpy(logFont.lfFaceName, m_name.charactersWithNullTermination(), + sizeof(logFont.lfFaceName[0]) * (1 + m_name.length())); + } + + // FIXME: almost identical to FillLogFont in FontCacheWin.cpp. + // Need to refactor. + logFont.lfHeight = -size; + logFont.lfWidth = 0; + logFont.lfEscapement = 0; + logFont.lfOrientation = 0; + logFont.lfUnderline = false; + logFont.lfStrikeOut = false; + logFont.lfCharSet = DEFAULT_CHARSET; + logFont.lfOutPrecision = OUT_TT_ONLY_PRECIS; + logFont.lfQuality = ChromiumBridge::layoutTestMode() ? + NONANTIALIASED_QUALITY : + DEFAULT_QUALITY; // Honor user's desktop settings. + logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + logFont.lfItalic = italic; + logFont.lfWeight = bold ? 700 : 400; + + HFONT hfont = CreateFontIndirect(&logFont); + return FontPlatformData(hfont, size); +#else + notImplemented(); + return FontPlatformData(); +#endif +} + +#if PLATFORM(WIN_OS) +// FIXME: EOTStream class and static functions in this #if block are +// duplicated from platform/graphics/win/FontCustomPlatformData.cpp +// and need to be shared. + +// Streams the concatenation of a header and font data. +class EOTStream { +public: + EOTStream(const Vector<UInt8, 512>& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength) + : m_eotHeader(eotHeader) + , m_fontData(fontData) + , m_overlayDst(overlayDst) + , m_overlaySrc(overlaySrc) + , m_overlayLength(overlayLength) + , m_offset(0) + , m_inHeader(true) + { + } + + size_t read(void* buffer, size_t count); + +private: + const Vector<UInt8, 512>& m_eotHeader; + const SharedBuffer* m_fontData; + size_t m_overlayDst; + size_t m_overlaySrc; + size_t m_overlayLength; + size_t m_offset; + bool m_inHeader; +}; + +size_t EOTStream::read(void* buffer, size_t count) +{ + size_t bytesToRead = count; + if (m_inHeader) { + size_t bytesFromHeader = std::min(m_eotHeader.size() - m_offset, count); + memcpy(buffer, m_eotHeader.data() + m_offset, bytesFromHeader); + m_offset += bytesFromHeader; + bytesToRead -= bytesFromHeader; + if (m_offset == m_eotHeader.size()) { + m_inHeader = false; + m_offset = 0; + } + } + if (bytesToRead && !m_inHeader) { + size_t bytesFromData = std::min(m_fontData->size() - m_offset, bytesToRead); + memcpy(buffer, m_fontData->data() + m_offset, bytesFromData); + if (m_offset < m_overlayDst + m_overlayLength && m_offset + bytesFromData >= m_overlayDst) { + size_t dstOffset = std::max<int>(m_overlayDst - m_offset, 0); + size_t srcOffset = std::max<int>(0, m_offset - m_overlayDst); + size_t bytesToCopy = std::min(bytesFromData - dstOffset, m_overlayLength - srcOffset); + memcpy(reinterpret_cast<char*>(buffer) + dstOffset, m_fontData->data() + m_overlaySrc + srcOffset, bytesToCopy); + } + m_offset += bytesFromData; + bytesToRead -= bytesFromData; + } + return count - bytesToRead; +} + +static unsigned long WINAPIV readEmbedProc(void* stream, void* buffer, unsigned long length) +{ + return static_cast<EOTStream*>(stream)->read(buffer, length); +} + +// Creates a unique and unpredictable font name, in order to avoid collisions and to +// not allow access from CSS. +static String createUniqueFontName() +{ + Vector<char> fontUuid(sizeof(GUID)); + CoCreateGuid(reinterpret_cast<GUID*>(fontUuid.data())); + + Vector<char> fontNameVector; + base64Encode(fontUuid, fontNameVector); + ASSERT(fontNameVector.size() < LF_FACESIZE); + return String(fontNameVector.data(), fontNameVector.size()); +} +#endif + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) +{ + ASSERT_ARG(buffer, buffer); + +#if PLATFORM(WIN_OS) + // Introduce the font to GDI. AddFontMemResourceEx cannot be used, because it will pollute the process's + // font namespace (Windows has no API for creating an HFONT from data without exposing the font to the + // entire process first). TTLoadEmbeddedFont lets us override the font family name, so using a unique name + // we avoid namespace collisions. + + String fontName = createUniqueFontName(); + + // TTLoadEmbeddedFont works only with Embedded OpenType (.eot) data, + // so we need to create an EOT header and prepend it to the font data. + Vector<UInt8, 512> eotHeader; + size_t overlayDst; + size_t overlaySrc; + size_t overlayLength; + + if (!getEOTHeader(buffer, eotHeader, overlayDst, overlaySrc, overlayLength)) + return 0; + + HANDLE fontReference; + ULONG privStatus; + ULONG status; + EOTStream eotStream(eotHeader, buffer, overlayDst, overlaySrc, overlayLength); + + LONG loadEmbeddedFontResult = TTLoadEmbeddedFont(&fontReference, TTLOAD_PRIVATE, &privStatus, LICENSE_PREVIEWPRINT, &status, readEmbedProc, &eotStream, const_cast<LPWSTR>(fontName.charactersWithNullTermination()), 0, 0); + if (loadEmbeddedFontResult == E_NONE) + fontName = String(); + else { + fontReference = renameAndActivateFont(buffer, fontName); + if (!fontReference) + return 0; + } + + return new FontCustomPlatformData(fontReference, fontName); +#else + notImplemented();; + return 0; +#endif +} + +} diff --git a/WebCore/platform/graphics/chromium/FontCustomPlatformData.h b/WebCore/platform/graphics/chromium/FontCustomPlatformData.h new file mode 100644 index 0000000..2f1a597 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontCustomPlatformData.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2007 Apple Computer, Inc. + * Copyright (c) 2007, 2008, 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 FontCustomPlatformData_h +#define FontCustomPlatformData_h + +#include <wtf/Noncopyable.h> + +#if PLATFORM(WIN_OS) +#include "FontRenderingMode.h" +#include "PlatformString.h" +#include <windows.h> +#endif + +namespace WebCore { + +class FontPlatformData; +class SharedBuffer; + +struct FontCustomPlatformData : Noncopyable { +#if PLATFORM(WIN_OS) + FontCustomPlatformData(HANDLE fontReference, const String& name) + : m_fontReference(fontReference) + , m_name(name) + {} +#endif + + ~FontCustomPlatformData(); + + FontPlatformData fontPlatformData(int size, bool bold, bool italic, + FontRenderingMode = NormalRenderingMode); + +#if PLATFORM(WIN_OS) + HANDLE m_fontReference; + String m_name; +#endif +}; + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*); +} + +#endif // FontCustomPlatformData_h diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp new file mode 100644 index 0000000..7a3e614 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontLinux.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2007, 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 "Font.h" + +#include "FloatRect.h" +#include "GlyphBuffer.h" +#include "GraphicsContext.h" +#include "NotImplemented.h" +#include "PlatformContextSkia.h" +#include "SimpleFontData.h" + +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkTemplates.h" +#include "SkTypeface.h" +#include "SkUtils.h" + +namespace WebCore { + +void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, + const GlyphBuffer& glyphBuffer, int from, int numGlyphs, + const FloatPoint& point) const { + SkCanvas* canvas = gc->platformContext()->canvas(); + SkPaint paint; + + gc->platformContext()->setupPaintCommon(&paint); + font->platformData().setupPaint(&paint); + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + paint.setColor(gc->fillColor().rgb()); + + SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert + + const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from); + SkScalar x = SkFloatToScalar(point.x()); + SkScalar y = SkFloatToScalar(point.y()); + + // FIXME: text rendering speed: + // Android has code in their WebCore fork to special case when the + // GlyphBuffer has no advances other than the defaults. In that case the + // text drawing can proceed faster. However, it's unclear when those + // patches may be upstreamed to WebKit so we always use the slower path + // here. + const GlyphBufferAdvance* adv = glyphBuffer.advances(from); + SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); + SkPoint* pos = storage.get(); + + for (int i = 0; i < numGlyphs; i++) { + pos[i].set(x, y); + x += SkFloatToScalar(adv[i].width()); + y += SkFloatToScalar(adv[i].height()); + } + canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint); +} + +void Font::drawComplexText(GraphicsContext* context, const TextRun& run, + const FloatPoint& point, int from, int to) const +{ + notImplemented(); +} + +float Font::floatWidthForComplexText(const TextRun& run) const +{ + notImplemented(); + return 0; +} + +int Font::offsetForPositionForComplexText(const TextRun& run, int x, + bool includePartialGlyphs) const +{ + notImplemented(); + return 0; +} + +FloatRect Font::selectionRectForComplexText(const TextRun& run, + const IntPoint& point, int h, + int from, int to) const +{ + notImplemented(); + return FloatRect(); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/FontPlatformData.h b/WebCore/platform/graphics/chromium/FontPlatformData.h new file mode 100644 index 0000000..c6f1912 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontPlatformData.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2007, 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. + */ + +#ifndef FontPlatformData_h +#define FontPlatformData_h + +#if PLATFORM(WIN_OS) +#include "FontPlatformDataChromiumWin.h" +#elif defined(__linux__) +#include "FontPlatformDataLinux.h" +#endif + +#endif // FontPlatformData_h diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp new file mode 100644 index 0000000..767fe76 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2006, 2007 Apple Computer, Inc. + * Copyright (c) 2006, 2007, 2008, 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 "FontPlatformData.h" + +#include <windows.h> +#include <objidl.h> +#include <mlang.h> + +#include "ChromiumBridge.h" +#include "SkiaFontWin.h" + +namespace WebCore { + +FontPlatformData::FontPlatformData(WTF::HashTableDeletedValueType) + : m_font(hashTableDeletedFontValue()) + , m_size(-1) + , m_scriptCache(0) + , m_scriptFontProperties(0) +{ +} + +FontPlatformData::FontPlatformData() + : m_font(0) + , m_size(0) + , m_scriptCache(0) + , m_scriptFontProperties(0) +{ +} + +FontPlatformData::FontPlatformData(HFONT font, float size) + : m_font(RefCountedHFONT::create(font)) + , m_size(size) + , m_scriptCache(0) + , m_scriptFontProperties(0) +{ +} + +// FIXME: this constructor is needed for SVG fonts but doesn't seem to do much +FontPlatformData::FontPlatformData(float size, bool bold, bool oblique) + : m_font(0) + , m_size(size) + , m_scriptCache(0) + , m_scriptFontProperties(0) +{ +} + +FontPlatformData::FontPlatformData(const FontPlatformData& data) + : m_font(data.m_font) + , m_size(data.m_size) + , m_scriptCache(0) + , m_scriptFontProperties(0) +{ +} + +FontPlatformData& FontPlatformData::operator=(const FontPlatformData& data) +{ + if (this != &data) { + m_font = data.m_font; + m_size = data.m_size; + + // The following fields will get re-computed if necessary. + ScriptFreeCache(&m_scriptCache); + m_scriptCache = 0; + + delete m_scriptFontProperties; + m_scriptFontProperties = 0; + } + return *this; +} + +FontPlatformData::~FontPlatformData() +{ + ScriptFreeCache(&m_scriptCache); + m_scriptCache = 0; + + delete m_scriptFontProperties; + m_scriptFontProperties = 0; +} + +FontPlatformData::RefCountedHFONT::~RefCountedHFONT() +{ + if (m_hfont != reinterpret_cast<HFONT>(-1)) { + SkiaWinOutlineCache::removePathsForFont(m_hfont); + DeleteObject(m_hfont); + } +} + +FontPlatformData::RefCountedHFONT* FontPlatformData::hashTableDeletedFontValue() +{ + static RefPtr<RefCountedHFONT> deletedValue = + RefCountedHFONT::create(reinterpret_cast<HFONT>(-1)); + return deletedValue.get(); +} + +SCRIPT_FONTPROPERTIES* FontPlatformData::scriptFontProperties() const +{ + if (!m_scriptFontProperties) { + m_scriptFontProperties = new SCRIPT_FONTPROPERTIES; + memset(m_scriptFontProperties, 0, sizeof(SCRIPT_FONTPROPERTIES)); + m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES); + HRESULT result = ScriptGetFontProperties(0, scriptCache(), + m_scriptFontProperties); + if (result == E_PENDING) { + HDC dc = GetDC(0); + HGDIOBJ oldFont = SelectObject(dc, hfont()); + HRESULT hr = ScriptGetFontProperties(dc, scriptCache(), + m_scriptFontProperties); + if (S_OK != hr) { + if (ChromiumBridge::ensureFontLoaded(hfont())) { + // FIXME: Handle gracefully the error if this call also fails. + hr = ScriptGetFontProperties(dc, scriptCache(), + m_scriptFontProperties); + if (S_OK != hr) { + ASSERT_NOT_REACHED(); + } + } + } + + SelectObject(dc, oldFont); + ReleaseDC(0, dc); + } + } + return m_scriptFontProperties; +} + +} diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h new file mode 100644 index 0000000..ce15a93 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontPlatformDataChromiumWin.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2006, 2007 Apple Computer, Inc. + * Copyright (c) 2006, 2007, 2008, 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 FontPlatformDataWin_h +#define FontPlatformDataWin_h + +#include "config.h" + +#include "StringImpl.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +#include <usp10.h> + +typedef struct HFONT__ *HFONT; + +namespace WebCore { + +class FontDescription; + +class FontPlatformData { +public: + // Used for deleted values in the font cache's hash tables. The hash table + // will create us with this structure, and it will compare other values + // to this "Deleted" one. It expects the Deleted one to be differentiable + // from the NULL one (created with the empty constructor), so we can't just + // set everything to NULL. + FontPlatformData(WTF::HashTableDeletedValueType); + FontPlatformData(); + FontPlatformData(HFONT, float size); + FontPlatformData(float size, bool bold, bool oblique); + FontPlatformData(const FontPlatformData&); + + FontPlatformData& operator=(const FontPlatformData&); + + bool isHashTableDeletedValue() const { return m_font == hashTableDeletedFontValue(); } + + ~FontPlatformData(); + + HFONT hfont() const { return m_font ? m_font->hfont() : 0; } + float size() const { return m_size; } + + unsigned hash() const + { + return m_font ? m_font->hash() : NULL; + } + + bool operator==(const FontPlatformData& other) const + { + return m_font == other.m_font && m_size == other.m_size; + } + + SCRIPT_FONTPROPERTIES* scriptFontProperties() const; + SCRIPT_CACHE* scriptCache() const { return &m_scriptCache; } + +private: + // We refcount the internal HFONT so that FontPlatformData can be + // efficiently copied. WebKit depends on being able to copy it, and we + // don't really want to re-create the HFONT. + class RefCountedHFONT : public RefCounted<RefCountedHFONT> { + public: + static PassRefPtr<RefCountedHFONT> create(HFONT hfont) + { + return adoptRef(new RefCountedHFONT(hfont)); + } + + ~RefCountedHFONT(); + + HFONT hfont() const { return m_hfont; } + unsigned hash() const + { + return StringImpl::computeHash(reinterpret_cast<const UChar*>(&m_hfont), sizeof(HFONT) / sizeof(UChar)); + } + + bool operator==(const RefCountedHFONT& other) const + { + return m_hfont == other.m_hfont; + } + + private: + // The create() function assumes there is already a refcount of one + // so it can do adoptRef. + RefCountedHFONT(HFONT hfont) : m_hfont(hfont) + { + } + + HFONT m_hfont; + }; + + static RefCountedHFONT* hashTableDeletedFontValue(); + + RefPtr<RefCountedHFONT> m_font; + float m_size; // Point size of the font in pixels. + + mutable SCRIPT_CACHE m_scriptCache; + mutable SCRIPT_FONTPROPERTIES* m_scriptFontProperties; +}; + +} // WebCore + +#endif // FontPlatformDataWin_h diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp new file mode 100644 index 0000000..86f96ee --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2006, 2007, 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 "FontPlatformData.h" + +#include "StringImpl.h" +#include "NotImplemented.h" + +#include "SkPaint.h" +#include "SkTypeface.h" + +namespace WebCore { + +FontPlatformData::FontPlatformData(const FontPlatformData& src) + : m_typeface(src.m_typeface) + , m_textSize(src.m_textSize) + , m_fakeBold(src.m_fakeBold) + , m_fakeItalic(src.m_fakeItalic) +{ + m_typeface->safeRef(); +} + +FontPlatformData::FontPlatformData(SkTypeface* tf, float textSize, bool fakeBold, bool fakeItalic) + : m_typeface(tf) + , m_textSize(textSize) + , m_fakeBold(fakeBold) + , m_fakeItalic(fakeItalic) +{ + m_typeface->safeRef(); +} + +FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize) + : m_typeface(src.m_typeface) + , m_textSize(textSize) + , m_fakeBold(src.m_fakeBold) + , m_fakeItalic(src.m_fakeItalic) +{ + m_typeface->safeRef(); +} + +FontPlatformData::~FontPlatformData() +{ + m_typeface->safeUnref(); +} + +FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src) +{ + SkRefCnt_SafeAssign(m_typeface, src.m_typeface); + + m_textSize = src.m_textSize; + m_fakeBold = src.m_fakeBold; + m_fakeItalic = src.m_fakeItalic; + + return *this; +} + +void FontPlatformData::setupPaint(SkPaint* paint) const +{ + const float ts = m_textSize > 0 ? m_textSize : 12; + + paint->setAntiAlias(false); + paint->setSubpixelText(false); + paint->setTextSize(SkFloatToScalar(ts)); + paint->setTypeface(m_typeface); + paint->setFakeBoldText(m_fakeBold); + paint->setTextSkewX(m_fakeItalic ? -SK_Scalar1 / 4 : 0); + paint->setTextEncoding(SkPaint::kUTF16_TextEncoding); +} + +bool FontPlatformData::operator==(const FontPlatformData& a) const +{ + // If either of the typeface pointers are invalid (either NULL or the + // special deleted value) then we test for pointer equality. Otherwise, we + // call SkTypeface::Equal on the valid pointers. + bool typefacesEqual; + if (m_typeface == hashTableDeletedFontValue() + || a.m_typeface == hashTableDeletedFontValue() + || !m_typeface + || !a.m_typeface) + typefacesEqual = m_typeface == a.m_typeface; + else + typefacesEqual = SkTypeface::Equal(m_typeface, a.m_typeface); + + return typefacesEqual + && m_textSize == a.m_textSize + && m_fakeBold == a.m_fakeBold + && m_fakeItalic == a.m_fakeItalic; +} + +unsigned FontPlatformData::hash() const +{ + unsigned h = SkTypeface::UniqueID(m_typeface); + h ^= 0x01010101 * ((static_cast<int>(m_fakeBold) << 1) | static_cast<int>(m_fakeItalic)); + + // This memcpy is to avoid a reinterpret_cast that breaks strict-aliasing + // rules. Memcpy is generally optimized enough so that performance doesn't + // matter here. + uint32_t textSizeBytes; + memcpy(&textSizeBytes, &m_textSize, sizeof(uint32_t)); + h ^= textSizeBytes; + + return h; +} + +bool FontPlatformData::isFixedPitch() const +{ + notImplemented(); + return false; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h new file mode 100644 index 0000000..ec7d837 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontPlatformDataLinux.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2006, 2007, 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. + */ + +#ifndef FontPlatformDataLinux_h +#define FontPlatformDataLinux_h + +#include "StringImpl.h" +#include <wtf/RefPtr.h> + +class SkPaint; +class SkTypeface; + +namespace WebCore { + +class FontDescription; + +// ----------------------------------------------------------------------------- +// FontPlatformData is the handle which WebKit has on a specific face. A face +// is the tuple of (font, size, ...etc). Here we are just wrapping a Skia +// SkTypeface pointer and dealing with the reference counting etc. +// ----------------------------------------------------------------------------- +class FontPlatformData { +public: + // Used for deleted values in the font cache's hash tables. The hash table + // will create us with this structure, and it will compare other values + // to this "Deleted" one. It expects the Deleted one to be differentiable + // from the NULL one (created with the empty constructor), so we can't just + // set everything to NULL. + FontPlatformData(WTF::HashTableDeletedValueType) + : m_typeface(hashTableDeletedFontValue()) + , m_textSize(0) + , m_fakeBold(false) + , m_fakeItalic(false) + { } + + FontPlatformData() + : m_typeface(0) + , m_textSize(0) + , m_fakeBold(false) + , m_fakeItalic(false) + { } + + FontPlatformData(float textSize, bool fakeBold, bool fakeItalic) + : m_typeface(0) + , m_textSize(textSize) + , m_fakeBold(fakeBold) + , m_fakeItalic(fakeItalic) + { } + + FontPlatformData(const FontPlatformData&); + FontPlatformData(SkTypeface*, float textSize, bool fakeBold, bool fakeItalic); + FontPlatformData(const FontPlatformData& src, float textSize); + ~FontPlatformData(); + + // ------------------------------------------------------------------------- + // Return true iff this font is monospaced (i.e. every glyph has an equal x + // advance) + // ------------------------------------------------------------------------- + bool isFixedPitch() const; + + // ------------------------------------------------------------------------- + // Setup a Skia painting context to use this font. + // ------------------------------------------------------------------------- + void setupPaint(SkPaint*) const; + + unsigned hash() const; + float size() const { return m_textSize; } + + bool operator==(const FontPlatformData&) const; + FontPlatformData& operator=(const FontPlatformData&); + bool isHashTableDeletedValue() const { return m_typeface == hashTableDeletedFontValue(); } + +private: + // FIXME: Could SkAutoUnref be used here? + SkTypeface* m_typeface; + float m_textSize; + bool m_fakeBold; + bool m_fakeItalic; + + SkTypeface* hashTableDeletedFontValue() const { return reinterpret_cast<SkTypeface*>(-1); } +}; + +} // namespace WebCore + +#endif // ifdef FontPlatformData_h diff --git a/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp new file mode 100644 index 0000000..ed326c8 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.cpp @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2006, 2007, 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 "FontUtilsChromiumWin.h" + +#include <limits> + +#include "PlatformString.h" +#include "StringHash.h" +#include "UniscribeHelper.h" +#include <unicode/locid.h> +#include <unicode/uchar.h> +#include <wtf/HashMap.h> + +namespace WebCore { + +namespace { + +// A simple mapping from UScriptCode to family name. This is a sparse array, +// which works well since the range of UScriptCode values is small. +typedef const UChar* ScriptToFontMap[USCRIPT_CODE_LIMIT]; + +void initializeScriptFontMap(ScriptToFontMap& scriptFontMap) +{ + struct FontMap { + UScriptCode script; + const UChar* family; + }; + + const static FontMap fontMap[] = { + {USCRIPT_LATIN, L"times new roman"}, + {USCRIPT_GREEK, L"times new roman"}, + {USCRIPT_CYRILLIC, L"times new roman"}, + {USCRIPT_SIMPLIFIED_HAN, L"simsun"}, + {USCRIPT_HIRAGANA, L"ms pgothic"}, + {USCRIPT_KATAKANA, L"ms pgothic"}, + {USCRIPT_KATAKANA_OR_HIRAGANA, L"ms pgothic"}, + {USCRIPT_HANGUL, L"gulim"}, + {USCRIPT_THAI, L"tahoma"}, + {USCRIPT_HEBREW, L"david"}, + {USCRIPT_ARABIC, L"tahoma"}, + {USCRIPT_DEVANAGARI, L"mangal"}, + {USCRIPT_BENGALI, L"vrinda"}, + {USCRIPT_GURMUKHI, L"raavi"}, + {USCRIPT_GUJARATI, L"shruti"}, + {USCRIPT_ORIYA, L"kalinga"}, + {USCRIPT_TAMIL, L"latha"}, + {USCRIPT_TELUGU, L"gautami"}, + {USCRIPT_KANNADA, L"tunga"}, + {USCRIPT_MALAYALAM, L"kartika"}, + {USCRIPT_LAO, L"dokchampa"}, + {USCRIPT_TIBETAN, L"microsoft himalaya"}, + {USCRIPT_GEORGIAN, L"sylfaen"}, + {USCRIPT_ARMENIAN, L"sylfaen"}, + {USCRIPT_ETHIOPIC, L"nyala"}, + {USCRIPT_CANADIAN_ABORIGINAL, L"euphemia"}, + {USCRIPT_CHEROKEE, L"plantagenet cherokee"}, + {USCRIPT_YI, L"microsoft yi balti"}, + {USCRIPT_SINHALA, L"iskoola pota"}, + {USCRIPT_SYRIAC, L"estrangelo edessa"}, + {USCRIPT_KHMER, L"daunpenh"}, + {USCRIPT_THAANA, L"mv boli"}, + {USCRIPT_MONGOLIAN, L"mongolian balti"}, + {USCRIPT_MYANMAR, L"padauk"}, + // For USCRIPT_COMMON, we map blocks to scripts when + // that makes sense. + }; + + for (int i = 0; i < sizeof(fontMap) / sizeof(fontMap[0]); ++i) + scriptFontMap[fontMap[i].script] = fontMap[i].family; + + // 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(); + const UChar* localeFamily = 0; + if (locale == Locale::getJapanese()) + localeFamily = scriptFontMap[USCRIPT_HIRAGANA]; + else if (locale == Locale::getKorean()) + localeFamily = scriptFontMap[USCRIPT_HANGUL]; + else { + // Use Simplified Chinese font for all other locales including + // Traditional Chinese because Simsun (SC font) has a wider + // coverage (covering both SC and TC) than PMingLiu (TC font). + // Note that |fontMap| does not have a separate entry for + // USCRIPT_TRADITIONAL_HAN for that reason. + // This also speeds up the TC version of Chrome when rendering SC + // pages. + localeFamily = scriptFontMap[USCRIPT_SIMPLIFIED_HAN]; + } + if (localeFamily) + scriptFontMap[USCRIPT_HAN] = localeFamily; +} + +const int kUndefinedAscent = std::numeric_limits<int>::min(); + +// Given an HFONT, return the ascent. If GetTextMetrics fails, +// kUndefinedAscent is returned, instead. +int getAscent(HFONT hfont) +{ + HDC dc = GetDC(0); + HGDIOBJ oldFont = SelectObject(dc, hfont); + TEXTMETRIC tm; + BOOL gotMetrics = GetTextMetrics(dc, &tm); + SelectObject(dc, oldFont); + ReleaseDC(0, dc); + return gotMetrics ? tm.tmAscent : kUndefinedAscent; +} + +struct FontData { + FontData() + : hfont(0) + , ascent(kUndefinedAscent) + , scriptCache(0) + { + } + + HFONT hfont; + int ascent; + mutable SCRIPT_CACHE scriptCache; +}; + +// Again, using hash_map does not earn us much here. page_cycler_test intl2 +// gave us a 'better' result with map than with hash_map even though they're +// well-within 1-sigma of each other so that the difference is not significant. +// On the other hand, some pages in intl2 seem to take longer to load with map +// in the 1st pass. Need to experiment further. +typedef HashMap<String, FontData> FontDataCache; + +} // namespace + +// FIXME: this is font fallback code version 0.1 +// - Cover all the scripts +// - Get the default font for each script/generic family from the +// preference instead of hardcoding in the source. +// (at least, read values from the registry for IE font settings). +// - Support generic families (from FontDescription) +// - If the default font for a script is not available, +// try some more fonts known to support it. Finally, we can +// use EnumFontFamilies or similar APIs to come up with a list of +// fonts supporting the script and cache the result. +// - Consider using UnicodeSet (or UnicodeMap) converted from +// GLYPHSET (BMP) or directly read from truetype cmap tables to +// keep track of which character is supported by which font +// - Update script_font_cache in response to WM_FONTCHANGE + +const UChar* getFontFamilyForScript(UScriptCode script, + FontDescription::GenericFamilyType generic) +{ + static ScriptToFontMap scriptFontMap; + static bool initialized = false; + if (!initialized) { + initializeScriptFontMap(scriptFontMap); + initialized = true; + } + if (script == USCRIPT_INVALID_CODE) + return 0; + ASSERT(script < USCRIPT_CODE_LIMIT); + return scriptFontMap[script]; +} + +// FIXME: +// - Handle 'Inherited', 'Common' and 'Unknown' +// (see http://www.unicode.org/reports/tr24/#Usage_Model ) +// For 'Inherited' and 'Common', perhaps we need to +// accept another parameter indicating the previous family +// and just return it. +// - All the characters (or characters up to the point a single +// font can cover) need to be taken into account +const UChar* getFallbackFamily(const UChar* characters, + int length, + FontDescription::GenericFamilyType generic, + UChar32* charChecked, + UScriptCode* scriptChecked) +{ + ASSERT(characters && characters[0] && length > 0); + UScriptCode script = USCRIPT_COMMON; + + // Sometimes characters common to script (e.g. space) is at + // the beginning of a string so that we need to skip them + // to get a font required to render the string. + int i = 0; + UChar32 ucs4 = 0; + while (i < length && script == USCRIPT_COMMON || script == USCRIPT_INVALID_CODE) { + U16_NEXT(characters, i, length, ucs4); + UErrorCode err = U_ZERO_ERROR; + script = uscript_getScript(ucs4, &err); + // silently ignore the error + } + + // For the full-width ASCII characters (U+FF00 - U+FF5E), use the font for + // Han (determined in a locale-dependent way above). Full-width ASCII + // characters are rather widely used in Japanese and Chinese documents and + // they're fully covered by Chinese, Japanese and Korean fonts. + if (0xFF00 < ucs4 && ucs4 < 0xFF5F) + script = USCRIPT_HAN; + + // There are a lot of characters in USCRIPT_COMMON that can be covered + // by fonts for scripts closely related to them. See + // http://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:Script=Common:] + // FIXME: make this more efficient with a wider coverage + if (script == USCRIPT_COMMON || script == USCRIPT_INHERITED) { + UBlockCode block = ublock_getCode(ucs4); + switch (block) { + case UBLOCK_BASIC_LATIN: + script = USCRIPT_LATIN; + break; + case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION: + script = USCRIPT_HAN; + break; + case UBLOCK_HIRAGANA: + case UBLOCK_KATAKANA: + script = USCRIPT_HIRAGANA; + break; + case UBLOCK_ARABIC: + script = USCRIPT_ARABIC; + break; + case UBLOCK_GREEK: + script = USCRIPT_GREEK; + break; + case UBLOCK_DEVANAGARI: + // For Danda and Double Danda (U+0964, U+0965), use a Devanagari + // font for now although they're used by other scripts as well. + // Without a context, we can't do any better. + script = USCRIPT_DEVANAGARI; + break; + case UBLOCK_ARMENIAN: + script = USCRIPT_ARMENIAN; + break; + case UBLOCK_GEORGIAN: + script = USCRIPT_GEORGIAN; + break; + case UBLOCK_KANNADA: + script = USCRIPT_KANNADA; + break; + } + } + + // Another lame work-around to cover non-BMP characters. + const UChar* family = getFontFamilyForScript(script, generic); + if (!family) { + int plane = ucs4 >> 16; + switch (plane) { + case 1: + family = L"code2001"; + break; + case 2: + family = L"simsun-extb"; + break; + default: + family = L"lucida sans unicode"; + } + } + + if (charChecked) + *charChecked = ucs4; + if (scriptChecked) + *scriptChecked = script; + return family; +} + +// Be aware that this is not thread-safe. +bool getDerivedFontData(const UChar* family, + int style, + LOGFONT* logfont, + int* ascent, + HFONT* hfont, + SCRIPT_CACHE** scriptCache) +{ + ASSERT(logfont); + ASSERT(family); + ASSERT(*family); + + // It does not matter that we leak font data when we exit. + static FontDataCache fontDataCache; + + // FIXME: This comes up pretty high in the profile so that + // we need to measure whether using SHA256 (after coercing all the + // fields to char*) is faster than String::format. + String fontKey = String::format("%1d:%d:%ls", style, logfont->lfHeight, family); + FontDataCache::iterator iter = fontDataCache.find(fontKey); + FontData* derived; + if (iter == fontDataCache.end()) { + ASSERT(wcslen(family) < LF_FACESIZE); + wcscpy_s(logfont->lfFaceName, LF_FACESIZE, family); + // FIXME: CreateFontIndirect always comes up with + // a font even if there's no font matching the name. Need to + // check it against what we actually want (as is done in + // FontCacheWin.cpp) + pair<FontDataCache::iterator, bool> entry = fontDataCache.add(fontKey, FontData()); + derived = &entry.first->second; + derived->hfont = CreateFontIndirect(logfont); + // GetAscent may return kUndefinedAscent, but we still want to + // cache it so that we won't have to call CreateFontIndirect once + // more for HFONT next time. + derived->ascent = getAscent(derived->hfont); + } else { + derived = &iter->second; + // Last time, GetAscent failed so that only HFONT was + // cached. Try once more assuming that TryPreloadFont + // was called by a caller between calls. + if (kUndefinedAscent == derived->ascent) + derived->ascent = getAscent(derived->hfont); + } + *hfont = derived->hfont; + *ascent = derived->ascent; + *scriptCache = &(derived->scriptCache); + return *ascent != kUndefinedAscent; +} + +int getStyleFromLogfont(const LOGFONT* logfont) +{ + // FIXME: consider defining UNDEFINED or INVALID for style and + // returning it when logfont is 0 + if (!logfont) { + ASSERT_NOT_REACHED(); + return FontStyleNormal; + } + return (logfont->lfItalic ? FontStyleItalic : FontStyleNormal) | + (logfont->lfUnderline ? FontStyleUnderlined : FontStyleNormal) | + (logfont->lfWeight >= 700 ? FontStyleBold : FontStyleNormal); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h new file mode 100644 index 0000000..6a964c4 --- /dev/null +++ b/WebCore/platform/graphics/chromium/FontUtilsChromiumWin.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2006, 2007, 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. + */ + +// A collection of utilities for font handling. + +// FIXME: Move all methods to the files that have their callsites and remove this file. +// *Utils files are not very WebKit-ty. + +#ifndef FontUtilsWin_h +#define FontUtilsWin_h + +#include <usp10.h> +#include <wchar.h> +#include <windows.h> + +#include "FontDescription.h" +#include <unicode/uscript.h> + +namespace WebCore { + +// Return a font family that supports a script and belongs to |generic| font +// family. It can return NULL and a caller has to implement its own fallback. +const UChar* getFontFamilyForScript(UScriptCode, FontDescription::GenericFamilyType); + +// Return a font family that can render |characters| based on +// what script characters belong to. When char_checked is non-NULL, +// it's filled with the character used to determine the script. +// When script_checked is non-NULL, the script used to determine +// the family is returned. +// FIXME: This function needs a total overhaul. +const UChar* getFallbackFamily(const UChar* characters, int length, + FontDescription::GenericFamilyType, + UChar32* charChecked, + UScriptCode* scriptChecked); + +// Derive a new HFONT by replacing lfFaceName of LOGFONT with |family|, +// calculate the ascent for the derived HFONT, and initialize SCRIPT_CACHE +// in FontData. +// |style| is only used for cache key generation. |style| is +// bit-wise OR of BOLD(1), UNDERLINED(2) and ITALIC(4) and +// should match what's contained in LOGFONT. It should be calculated +// by calling GetStyleFromLogFont. +// Returns false if the font is not accessible, in which case |ascent| field +// of |fontdata| is set to kUndefinedAscent. +// Be aware that this is not thread-safe. +// FIXME: Instead of having three out params, we'd better have one +// (|*FontData|), but somehow it mysteriously messes up the layout for +// certain complex script pages (e.g. hi.wikipedia.org) and also crashes +// at the start-up if recently visited page list includes pages with complex +// scripts in their title. Moreover, somehow the very first-pass of +// intl2 page-cycler test is noticeably slower with one out param than +// the current version although the subsequent 9 passes take about the +// same time. +bool getDerivedFontData(const UChar* family, int style, LOGFONT*, int* ascent, HFONT*, SCRIPT_CACHE**); + +enum { + FontStyleNormal = 0, + FontStyleBold = 1, + FontStyleItalic = 2, + FontStyleUnderlined = 4 +}; + +// Derive style (bit-wise OR of FONT_STYLE_BOLD, FONT_STYLE_UNDERLINED, and +// FONT_STYLE_ITALIC) from LOGFONT. Returns 0 if |*logfont| is NULL. +int getStyleFromLogfont(const LOGFONT*); + +} // namespace WebCore + +#endif // FontUtilsWin_h diff --git a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp new file mode 100644 index 0000000..4c5cf7b --- /dev/null +++ b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2008, 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 <windows.h> +#include <vector> + +#include "ChromiumBridge.h" +#include "Font.h" +#include "GlyphPageTreeNode.h" +#include "SimpleFontData.h" +#include "UniscribeHelperTextRun.h" +#include "WindowsVersion.h" + +namespace WebCore { + +// Fills one page of font data pointers with 0 to indicate that there +// are no glyphs for the characters. +static void fillEmptyGlyphs(GlyphPage* page) +{ + for (int i = 0; i < GlyphPage::size; ++i) + page->setGlyphDataForIndex(i, 0, 0); +} + +// Lazily initializes space glyph +static Glyph initSpaceGlyph(HDC dc, Glyph* spaceGlyph) +{ + if (*spaceGlyph) + return *spaceGlyph; + + static wchar_t space = ' '; + GetGlyphIndices(dc, &space, 1, spaceGlyph, 0); + return *spaceGlyph; +} + +// Fills |length| glyphs starting at |offset| in a |page| in the Basic +// Multilingual Plane (<= U+FFFF). The input buffer size should be the +// same as |length|. We can use the standard Windows GDI functions here. +// Returns true if any glyphs were found. +static bool fillBMPGlyphs(unsigned offset, + unsigned length, + UChar* buffer, + GlyphPage* page, + const SimpleFontData* fontData, + bool recurse) +{ + HDC dc = GetDC((HWND)0); + HGDIOBJ oldFont = SelectObject(dc, fontData->m_font.hfont()); + + TEXTMETRIC tm = {0}; + if (!GetTextMetrics(dc, &tm)) { + SelectObject(dc, oldFont); + ReleaseDC(0, dc); + + if (recurse) { + if (ChromiumBridge::ensureFontLoaded(fontData->m_font.hfont())) + return fillBMPGlyphs(offset, length, buffer, page, fontData, false); + else { + fillEmptyGlyphs(page); + return false; + } + } else { + // FIXME: This should never happen. We want to crash the + // process and receive a crash dump. We should revisit this code later. + // See http://crbug.com/6401 + ASSERT_NOT_REACHED(); + fillEmptyGlyphs(page); + return false; + } + } + + // FIXME: GetGlyphIndices() sets each item of localGlyphBuffer[] + // with the one of the values listed below. + // * With the GGI_MARK_NONEXISTING_GLYPHS flag + // + If the font has a glyph available for the character, + // localGlyphBuffer[i] > 0x0. + // + If the font does not have glyphs available for the character, + // localGlyphBuffer[i] = 0x1F (TrueType Collection?) or + // 0xFFFF (OpenType?). + // * Without the GGI_MARK_NONEXISTING_GLYPHS flag + // + If the font has a glyph available for the character, + // localGlyphBuffer[i] > 0x0. + // + If the font does not have glyphs available for the character, + // localGlyphBuffer[i] = 0x80. + // (Windows automatically assigns the glyph for a box character to + // prevent ExtTextOut() from returning errors.) + // To avoid from hurting the rendering performance, this code just + // tells WebKit whether or not the all glyph indices for the given + // characters are 0x80 (i.e. a possibly-invalid glyph) and let it + // use alternative fonts for the characters. + // Although this may cause a problem, it seems to work fine as far as I + // have tested. (Obviously, I need more tests.) + WORD localGlyphBuffer[GlyphPage::size]; + + // FIXME: I find some Chinese characters can not be correctly displayed + // when call GetGlyphIndices without flag GGI_MARK_NONEXISTING_GLYPHS, + // because the corresponding glyph index is set as 0x20 when current font + // does not have glyphs available for the character. According a blog post + // http://blogs.msdn.com/michkap/archive/2006/06/28/649791.aspx + // I think we should switch to the way about calling GetGlyphIndices with + // flag GGI_MARK_NONEXISTING_GLYPHS, it should be OK according the + // description of MSDN. + // Also according to Jungshik and Hironori's suggestion and modification + // we treat turetype and raster Font as different way when windows version + // is less than Vista. + GetGlyphIndices(dc, buffer, length, localGlyphBuffer, GGI_MARK_NONEXISTING_GLYPHS); + + // Copy the output to the GlyphPage + bool haveGlyphs = false; + int invalidGlyph = 0xFFFF; + if (!isVistaOrNewer() && !(tm.tmPitchAndFamily & TMPF_TRUETYPE)) + invalidGlyph = 0x1F; + + Glyph spaceGlyph = 0; // Glyph for a space. Lazily filled. + + for (unsigned i = 0; i < length; i++) { + UChar c = buffer[i]; + Glyph glyph = localGlyphBuffer[i]; + const SimpleFontData* glyphFontData = fontData; + // When this character should be a space, we ignore whatever the font + // says and use a space. Otherwise, if fonts don't map one of these + // space or zero width glyphs, we will get a box. + if (Font::treatAsSpace(c)) + // Hard code the glyph indices for characters that should be + // treated like spaces. + glyph = initSpaceGlyph(dc, &spaceGlyph); + else if (Font::treatAsZeroWidthSpace(c) || c == 0x200B) { + // FIXME: change Font::treatAsZeroWidthSpace to use + // u_hasBinaryProperty, per jungshik's comment here: + // https://bugs.webkit.org/show_bug.cgi?id=20237#c6. + // Then the additional OR above won't be necessary. + glyph = initSpaceGlyph(dc, &spaceGlyph); + glyphFontData = fontData->zeroWidthFontData(); + } else if (glyph == invalidGlyph) { + // WebKit expects both the glyph index and FontData + // pointer to be 0 if the glyph is not present + glyph = 0; + glyphFontData = 0; + } else { + if (SimpleFontData::isCJKCodePoint(c)) + glyphFontData = fontData->cjkWidthFontData(); + haveGlyphs = true; + } + page->setGlyphDataForCharacter(offset + i, glyph, glyphFontData); + } + + SelectObject(dc, oldFont); + ReleaseDC(0, dc); + return haveGlyphs; +} + +// For non-BMP characters, each is two words (UTF-16) and the input buffer +// size is 2 * |length|. Since GDI doesn't know how to handle non-BMP +// characters, we must use Uniscribe to tell us the glyph indices. +// +// We don't want to call this in the case of "regular" characters since some +// fonts may not have the correct combining rules for accents. See the notes +// at the bottom of ScriptGetCMap. We can't use ScriptGetCMap, though, since +// it doesn't seem to support UTF-16, despite what this blog post says: +// http://blogs.msdn.com/michkap/archive/2006/06/29/650680.aspx +// +// So we fire up the full Uniscribe doohicky, give it our string, and it will +// correctly handle the UTF-16 for us. The hard part is taking this and getting +// the glyph indices back out that correspond to the correct input characters, +// since they may be missing. +// +// Returns true if any glyphs were found. +static bool fillNonBMPGlyphs(unsigned offset, + unsigned length, + UChar* buffer, + GlyphPage* page, + const SimpleFontData* fontData) +{ + bool haveGlyphs = false; + + UniscribeHelperTextRun state(buffer, length * 2, false, + fontData->m_font.hfont(), + fontData->m_font.scriptCache(), + fontData->m_font.scriptFontProperties()); + state.setInhibitLigate(true); + state.init(); + + for (unsigned i = 0; i < length; i++) { + // Each character in this input buffer is a surrogate pair, which + // consists of two UChars. So, the offset for its i-th character is + // (i * 2). + WORD glyph = state.firstGlyphForCharacter(i * 2); + if (glyph) { + haveGlyphs = true; + page->setGlyphDataForIndex(offset + i, glyph, fontData); + } else + // Clear both glyph and fontData fields. + page->setGlyphDataForIndex(offset + i, 0, 0); + } + return haveGlyphs; +} + +// We're supposed to return true if there are any glyphs in the range +// specified by |offset| and |length| in our font, +// false if there are none. +bool GlyphPage::fill(unsigned offset, unsigned length, UChar* characterBuffer, + unsigned bufferLength, const SimpleFontData* fontData) +{ + // We have to handle BMP and non-BMP characters differently. + // FIXME: Add assertions to make sure that buffer is entirely in BMP + // or entirely in non-BMP. + if (bufferLength == length) + return fillBMPGlyphs(offset, length, characterBuffer, this, fontData, true); + + if (bufferLength == 2 * length) { + // A non-BMP input buffer will be twice as long as output glyph buffer + // because each character in the non-BMP input buffer will be + // represented by a surrogate pair (two UChar's). + return fillNonBMPGlyphs(offset, length, characterBuffer, this, fontData); + } + + ASSERT_NOT_REACHED(); + return false; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp new file mode 100644 index 0000000..6024d43 --- /dev/null +++ b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2008, 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 "GlyphPageTreeNode.h" + +#include "Font.h" +#include "SimpleFontData.h" + +#include "SkTemplates.h" +#include "SkPaint.h" +#include "SkUtils.h" + +namespace WebCore { + +bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) +{ + if (SkUTF16_IsHighSurrogate(buffer[bufferLength-1])) { + SkDebugf("%s last char is high-surrogate", __FUNCTION__); + return false; + } + + SkPaint paint; + fontData->platformData().setupPaint(&paint); + paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); + + SkAutoSTMalloc <GlyphPage::size, uint16_t> glyphStorage(length); + uint16_t* glyphs = glyphStorage.get(); + // textToGlyphs takes a byte count, not a glyph count so we multiply by two. + unsigned count = paint.textToGlyphs(buffer, bufferLength * 2, glyphs); + if (count != length) { + SkDebugf("%s count != length\n", __FUNCTION__); + return false; + } + + unsigned allGlyphs = 0; // track if any of the glyphIDs are non-zero + for (unsigned i = 0; i < length; i++) { + setGlyphDataForIndex(offset + i, glyphs[i], glyphs[i] ? fontData : NULL); + allGlyphs |= glyphs[i]; + } + + return allGlyphs != 0; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp b/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp new file mode 100644 index 0000000..a5a6e1f --- /dev/null +++ b/WebCore/platform/graphics/chromium/IconChromiumLinux.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2008, 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 "Icon.h" + +#include "GraphicsContext.h" +#include "NotImplemented.h" +#include "PlatformString.h" + +namespace WebCore { + +Icon::Icon(const PlatformIcon& icon) + : m_icon(icon) +{ +} + +Icon::~Icon() +{ +} + +PassRefPtr<Icon> Icon::createIconForFile(const String&) +{ + notImplemented(); + return 0; +} + +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&) +{ + notImplemented(); + return 0; +} + +void Icon::paint(GraphicsContext*, const IntRect&) +{ + notImplemented(); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/IconChromiumMac.cpp b/WebCore/platform/graphics/chromium/IconChromiumMac.cpp new file mode 100644 index 0000000..93e36ba --- /dev/null +++ b/WebCore/platform/graphics/chromium/IconChromiumMac.cpp @@ -0,0 +1,60 @@ +/* + * 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 "Icon.h" + +#include "PassRefPtr.h" + +// FIXME: These are temporary stubs, we need real implementations which +// may come in the form of IconChromium.cpp. The Windows Chromium +// implementation is currently in IconWin.cpp. + +namespace WebCore { + +PassRefPtr<Icon> Icon::createIconForFile(const String&) +{ + return 0; +} + +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>&) +{ + return 0; +} + +Icon::~Icon() +{ +} + +void Icon::paint(GraphicsContext*, const IntRect&) +{ +} + +} diff --git a/WebCore/platform/graphics/chromium/IconChromiumWin.cpp b/WebCore/platform/graphics/chromium/IconChromiumWin.cpp new file mode 100644 index 0000000..b419e6f --- /dev/null +++ b/WebCore/platform/graphics/chromium/IconChromiumWin.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2008, 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 "Icon.h" + +#include <windows.h> +#include <shellapi.h> + +#include "GraphicsContext.h" +#include "PlatformContextSkia.h" +#include "PlatformString.h" +#include "SkiaUtils.h" + +namespace WebCore { + +Icon::Icon(const PlatformIcon& icon) + : m_icon(icon) +{ +} + +Icon::~Icon() +{ + if (m_icon) + DestroyIcon(m_icon); +} + +PassRefPtr<Icon> Icon::createIconForFile(const String& filename) +{ + SHFILEINFO sfi; + memset(&sfi, 0, sizeof(sfi)); + + String tmpFilename = filename; + if (!SHGetFileInfo(tmpFilename.charactersWithNullTermination(), 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_SHELLICONSIZE | SHGFI_SMALLICON)) + return 0; + + return adoptRef(new Icon(sfi.hIcon)); +} + +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) +{ + // FIXME: support multiple files. + // http://code.google.com/p/chromium/issues/detail?id=4092 + if (!filenames.size()) + return 0; + + return createIconForFile(filenames[0]); +} + +void Icon::paint(GraphicsContext* context, const IntRect& rect) +{ + if (context->paintingDisabled()) + return; + + HDC hdc = context->platformContext()->canvas()->beginPlatformPaint(); + DrawIconEx(hdc, rect.x(), rect.y(), m_icon, rect.width(), rect.height(), 0, 0, DI_NORMAL); + context->platformContext()->canvas()->endPlatformPaint(); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/ImageBufferData.h b/WebCore/platform/graphics/chromium/ImageBufferData.h new file mode 100644 index 0000000..504b893 --- /dev/null +++ b/WebCore/platform/graphics/chromium/ImageBufferData.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2008, 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 ImageBufferData_h +#define ImageBufferData_h + +#include "PlatformContextSkia.h" + +#include "skia/ext/platform_canvas.h" + +namespace WebCore { + +class ImageBufferData { +public: + ImageBufferData(const IntSize&); + + skia::PlatformCanvas m_canvas; + PlatformContextSkia m_platformContext; +}; + +} // namespace WebCore + +#endif // ImageBufferData_h diff --git a/WebCore/platform/graphics/chromium/ImageChromiumMac.mm b/WebCore/platform/graphics/chromium/ImageChromiumMac.mm new file mode 100644 index 0000000..073a409 --- /dev/null +++ b/WebCore/platform/graphics/chromium/ImageChromiumMac.mm @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2008, 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. + */ + +// A wrapper around Uniscribe that provides a reasonable API. + +#include "config.h" +#include "BitmapImage.h" + +#include "ChromiumBridge.h" +#include "Image.h" + +namespace WebCore { + +PassRefPtr<Image> Image::loadPlatformResource(const char* name) +{ + return ChromiumBridge::loadPlatformImageResource(name); +} + +// FIXME: These are temporary stubs, we need real implementations which +// may come in the form of ImageChromium.cpp. The Windows Chromium +// implementation is currently in ImageSkia.cpp. + +void BitmapImage::initPlatformData() +{ +} + +void BitmapImage::invalidatePlatformData() +{ +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h b/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h new file mode 100644 index 0000000..959147a --- /dev/null +++ b/WebCore/platform/graphics/chromium/MediaPlayerPrivateChromium.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2008, 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 MediaPlayerPrivateChromium_h +#define MediaPlayerPrivateChromium_h + +#if ENABLE(VIDEO) + +#include "MediaPlayer.h" + +namespace WebCore { + +class MediaPlayerPrivate : public Noncopyable { +public: + MediaPlayerPrivate(MediaPlayer*); + ~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; + MediaPlayer::ReadyState readyState() const; + + float maxTimeBuffered() const; + float maxTimeSeekable() const; + unsigned bytesLoaded() const; + bool totalBytesKnown() const; + unsigned totalBytes() const; + + void setVisible(bool); + void setRect(const IntRect&); + + void paint(GraphicsContext*, const IntRect&); + + static void getSupportedTypes(HashSet<String>&); + static bool isAvailable(); + + // Public methods to be called by WebMediaPlayer + FrameView* frameView(); + void networkStateChanged(); + void readyStateChanged(); + void timeChanged(); + void volumeChanged(); + void repaint(); + +private: + MediaPlayer* m_player; + void* m_data; +}; + +} // namespace WebCore + +#endif + +#endif // MediaPlayerPrivateChromium_h diff --git a/WebCore/platform/graphics/chromium/PlatformIcon.h b/WebCore/platform/graphics/chromium/PlatformIcon.h new file mode 100644 index 0000000..51613b8 --- /dev/null +++ b/WebCore/platform/graphics/chromium/PlatformIcon.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2008, 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 PlatformIcon_h +#define PlatformIcon_h + +typedef struct HICON__* HICON; + +namespace WebCore { + +typedef HICON PlatformIcon; + +} // namespace WebCore + +#endif // PlatformIcon_h diff --git a/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp b/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp new file mode 100644 index 0000000..06e997f --- /dev/null +++ b/WebCore/platform/graphics/chromium/SimpleFontDataChromiumWin.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All Rights Reserved. + * Copyright (c) 2008, 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 "SimpleFontData.h" + +#include "ChromiumBridge.h" +#include "Font.h" +#include "FontCache.h" +#include "FloatRect.h" +#include "FontDescription.h" +#include <wtf/MathExtras.h> + +#include <unicode/uchar.h> +#include <unicode/unorm.h> +#include <objidl.h> +#include <mlang.h> + +namespace WebCore { + +static inline float scaleEmToUnits(float x, int unitsPerEm) +{ + return unitsPerEm ? x / static_cast<float>(unitsPerEm) : x; +} + +void SimpleFontData::platformInit() +{ + HDC dc = GetDC(0); + HGDIOBJ oldFont = SelectObject(dc, m_font.hfont()); + + TEXTMETRIC textMetric = {0}; + if (!GetTextMetrics(dc, &textMetric)) { + if (ChromiumBridge::ensureFontLoaded(m_font.hfont())) { + // Retry GetTextMetrics. + // FIXME: Handle gracefully the error if this call also fails. + // See http://crbug.com/6401. + if (!GetTextMetrics(dc, &textMetric)) + ASSERT_NOT_REACHED(); + } + } + + m_avgCharWidth = textMetric.tmAveCharWidth; + m_maxCharWidth = textMetric.tmMaxCharWidth; + + m_ascent = textMetric.tmAscent; + m_descent = textMetric.tmDescent; + m_lineGap = textMetric.tmExternalLeading; + m_xHeight = m_ascent * 0.56f; // Best guess for xHeight for non-Truetype fonts. + + OUTLINETEXTMETRIC outlineTextMetric; + if (GetOutlineTextMetrics(dc, sizeof(outlineTextMetric), &outlineTextMetric) > 0) { + // This is a TrueType font. We might be able to get an accurate xHeight. + GLYPHMETRICS glyphMetrics = {0}; + MAT2 identityMatrix = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; + DWORD len = GetGlyphOutlineW(dc, 'x', GGO_METRICS, &glyphMetrics, 0, 0, &identityMatrix); + if (len != GDI_ERROR && glyphMetrics.gmBlackBoxY > 0) + m_xHeight = static_cast<float>(glyphMetrics.gmBlackBoxY); + } + + m_lineSpacing = m_ascent + m_descent + m_lineGap; + + SelectObject(dc, oldFont); + ReleaseDC(0, dc); +} + +void SimpleFontData::platformDestroy() +{ + // We don't hash this on Win32, so it's effectively owned by us. + delete m_smallCapsFontData; + m_smallCapsFontData = 0; +} + +SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const +{ + if (!m_smallCapsFontData) { + LOGFONT winFont; + GetObject(m_font.hfont(), sizeof(LOGFONT), &winFont); + float smallCapsSize = 0.70f * fontDescription.computedSize(); + // Unlike WebKit trunk, we don't multiply the size by 32. That seems + // to be some kind of artifact of their CG backend, or something. + winFont.lfHeight = -lroundf(smallCapsSize); + HFONT hfont = CreateFontIndirect(&winFont); + m_smallCapsFontData = + new SimpleFontData(FontPlatformData(hfont, smallCapsSize)); + } + return m_smallCapsFontData; +} + +bool SimpleFontData::containsCharacters(const UChar* characters, int length) const +{ + // This used to be implemented with IMLangFontLink2, but since that code has + // been disabled, this would always return false anyway. + return false; +} + +void SimpleFontData::determinePitch() +{ + // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that. + HDC dc = GetDC(0); + HGDIOBJ oldFont = SelectObject(dc, m_font.hfont()); + + // Yes, this looks backwards, but the fixed pitch bit is actually set if the font + // is *not* fixed pitch. Unbelievable but true. + TEXTMETRIC textMetric = {0}; + if (!GetTextMetrics(dc, &textMetric)) { + if (ChromiumBridge::ensureFontLoaded(m_font.hfont())) { + // Retry GetTextMetrics. + // FIXME: Handle gracefully the error if this call also fails. + // See http://crbug.com/6401. + if (!GetTextMetrics(dc, &textMetric)) + ASSERT_NOT_REACHED(); + } + } + + m_treatAsFixedPitch = ((textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0); + + SelectObject(dc, oldFont); + ReleaseDC(0, dc); +} + +float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +{ + HDC dc = GetDC(0); + HGDIOBJ oldFont = SelectObject(dc, m_font.hfont()); + + int width = 0; + if (!GetCharWidthI(dc, glyph, 1, 0, &width)) { + // Ask the browser to preload the font and retry. + if (ChromiumBridge::ensureFontLoaded(m_font.hfont())) { + // FIXME: Handle gracefully the error if this call also fails. + // See http://crbug.com/6401. + if (!GetCharWidthI(dc, glyph, 1, 0, &width)) + ASSERT_NOT_REACHED(); + } + } + + SelectObject(dc, oldFont); + ReleaseDC(0, dc); + + return static_cast<float>(width); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp b/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp new file mode 100644 index 0000000..8200175 --- /dev/null +++ b/WebCore/platform/graphics/chromium/SimpleFontDataLinux.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2008, 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 "SimpleFontData.h" + +#include "Font.h" +#include "FontCache.h" +#include "FloatRect.h" +#include "FontDescription.h" +#include "Logging.h" +#include "NotImplemented.h" + +#include "SkPaint.h" +#include "SkTypeface.h" +#include "SkTime.h" + +namespace WebCore { + +// Smallcaps versions of fonts are 70% the size of the normal font. +static const float smallCapsFraction = 0.7f; + +void SimpleFontData::platformInit() +{ + SkPaint paint; + SkPaint::FontMetrics metrics; + + m_font.setupPaint(&paint); + paint.getFontMetrics(&metrics); + + // Beware those who step here: This code is designed to match Win32 font + // metrics *exactly*. + if (metrics.fVDMXMetricsValid) { + m_ascent = metrics.fVDMXAscent; + m_descent = metrics.fVDMXDescent; + } else { + m_ascent = SkScalarRound(-metrics.fAscent); + m_descent = SkScalarRound(metrics.fHeight) - m_ascent; + } + + if (metrics.fXHeight) + m_xHeight = metrics.fXHeight; + else { + // hack taken from the Windows port + m_xHeight = static_cast<float>(m_ascent) * 0.56; + } + + m_lineGap = SkScalarRound(metrics.fLeading); + m_lineSpacing = m_ascent + m_descent + m_lineGap; + + // In WebKit/WebCore/platform/graphics/SimpleFontData.cpp, m_spaceWidth is + // calculated for us, but we need to calculate m_maxCharWidth and + // m_avgCharWidth in order for text entry widgets to be sized correctly. + + m_maxCharWidth = SkScalarRound(metrics.fXRange * SkScalarRound(m_font.size())); + + if (metrics.fAvgCharWidth) + m_avgCharWidth = SkScalarRound(metrics.fAvgCharWidth); + else { + m_avgCharWidth = m_xHeight; + + GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); + + if (glyphPageZero) { + static const UChar32 x_char = 'x'; + const Glyph xGlyph = glyphPageZero->glyphDataForCharacter(x_char).glyph; + + if (xGlyph) + m_avgCharWidth = widthForGlyph(xGlyph); + } + } +} + +void SimpleFontData::platformDestroy() +{ + delete m_smallCapsFontData; + m_smallCapsFontData = 0; +} + +SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const +{ + if (!m_smallCapsFontData) { + const float smallCapsSize = lroundf(fontDescription.computedSize() * smallCapsFraction); + m_smallCapsFontData = new SimpleFontData(FontPlatformData(m_font, smallCapsSize)); + } + + return m_smallCapsFontData; +} + +bool SimpleFontData::containsCharacters(const UChar* characters, int length) const +{ + SkPaint paint; + static const unsigned maxBufferCount = 64; + uint16_t glyphs[maxBufferCount]; + + m_font.setupPaint(&paint); + paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); + + while (length > 0) { + int n = SkMin32(length, SK_ARRAY_COUNT(glyphs)); + + // textToGlyphs takes a byte count so we double the character count. + int count = paint.textToGlyphs(characters, n * 2, glyphs); + for (int i = 0; i < count; i++) { + if (0 == glyphs[i]) + return false; // missing glyph + } + + characters += n; + length -= n; + } + + return true; +} + +void SimpleFontData::determinePitch() +{ + m_treatAsFixedPitch = platformData().isFixedPitch(); +} + +float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +{ + SkASSERT(sizeof(glyph) == 2); // compile-time assert + + SkPaint paint; + + m_font.setupPaint(&paint); + + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + SkScalar width = paint.measureText(&glyph, 2); + + return SkScalarToFloat(width); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.cpp b/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.cpp new file mode 100644 index 0000000..798ee32 --- /dev/null +++ b/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2008, 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 "ThemeHelperChromiumWin.h" + +#include "FloatRect.h" +#include "GraphicsContext.h" + +namespace WebCore { + +ThemeHelperWin::ThemeHelperWin(GraphicsContext* context, const IntRect& rect) + : m_orgContext(context) + , m_orgMatrix(context->getCTM()) + , m_orgRect(rect) +{ + if (m_orgMatrix.b() != 0 || m_orgMatrix.c() != 0) { // Check for skew. + // Complicated effects, make a copy and draw the bitmap there. + m_type = COPY; + m_rect.setSize(rect.size()); + + m_newBuffer.set(ImageBuffer::create(rect.size(), false).release()); + + // Theme drawing messes with the transparency. + // FIXME: Ideally, we would leave this transparent, but I was + // having problems with button drawing, so we fill with white. Buttons + // looked good with transparent here and no fixing up of the alpha + // later, but text areas didn't. This makes text areas look good but + // gives buttons a white halo. Is there a way to fix this? I think + // buttons actually have antialised edges which is just not possible + // to handle on a transparent background given that it messes with the + // alpha channel. + FloatRect newContextRect(0, 0, rect.width(), rect.height()); + GraphicsContext* newContext = m_newBuffer->context(); + newContext->setFillColor(Color::white); + newContext->fillRect(newContextRect); + + return; + } + + if (m_orgMatrix.a() != 1.0 || m_orgMatrix.d() != 1.0) { // Check for scale. + // Only a scaling is applied. + m_type = SCALE; + + // Save the transformed coordinates to draw. + m_rect = m_orgMatrix.mapRect(rect); + + m_orgContext->save(); + m_orgContext->concatCTM(m_orgContext->getCTM().inverse()); + return; + } + + // Nothing interesting. + m_rect = rect; + m_type = ORIGINAL; +} + +ThemeHelperWin::~ThemeHelperWin() +{ + switch (m_type) { + case SCALE: + m_orgContext->restore(); + break; + case COPY: { + // Copy the duplicate bitmap with our control to the original canvas. + FloatRect destRect(m_orgRect); + m_newBuffer->context()->platformContext()->canvas()-> + getTopPlatformDevice().fixupAlphaBeforeCompositing(); + m_orgContext->drawImage(m_newBuffer->image(), destRect); + break; + } + case ORIGINAL: + break; + } +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.h b/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.h new file mode 100644 index 0000000..1771fb4 --- /dev/null +++ b/WebCore/platform/graphics/chromium/ThemeHelperChromiumWin.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2008, 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 ThemeHelperWin_h +#define ThemeHelperWin_h + +#include "TransformationMatrix.h" +#include "ImageBuffer.h" +#include "IntRect.h" +#include <wtf/OwnPtr.h> + +namespace WebCore { + +class GraphicsContext; +class IntRect; + +// Helps drawing theme elements like buttons and scroll bars. This will handle +// translations and scalings that Windows might not, by either making Windows +// draw the appropriate sized control, or by rendering it into an off-screen +// context and transforming it ourselves. +class ThemeHelperWin { + enum Type { + // Use the original canvas with no changes. This is the normal mode. + ORIGINAL, + + // Use the original canvas but scale the rectangle of the control so + // that it will be the correct size, undoing any scale already on the + // canvas. This will have the effect of just drawing the control bigger + // or smaller and not actually expanding or contracting the pixels in + // it. This usually looks better. + SCALE, + + // Make a copy of the control and then transform it ourselves after + // Windows draws it. This allows us to get complex effects. + COPY, + }; + +public: + // Prepares drawing a control with the given rect to the given context. + ThemeHelperWin(GraphicsContext* context, const IntRect& rect); + ~ThemeHelperWin(); + + // Returns the context to draw the control into, which may be the original + // or the copy, depending on the mode. + GraphicsContext* context() + { + return m_newBuffer.get() ? m_newBuffer->context() : m_orgContext; + } + + // Returns the rectangle in which to draw into the canvas() by Windows. + const IntRect& rect() { return m_rect; } + +private: + Type m_type; + + // The original canvas to wrote to. Not owned by this class. + GraphicsContext* m_orgContext; + TransformationMatrix m_orgMatrix; + IntRect m_orgRect; + + // When m_type == COPY, this will be a new surface owned by this class that + // represents the copy. + OwnPtr<ImageBuffer> m_newBuffer; + + // The control rectangle in the coordinate space of canvas(). + IntRect m_rect; +}; + +} // namespace WebCore + +#endif // ThemeHelperWin_h diff --git a/WebCore/platform/graphics/chromium/UniscribeHelper.cpp b/WebCore/platform/graphics/chromium/UniscribeHelper.cpp new file mode 100644 index 0000000..caeb959 --- /dev/null +++ b/WebCore/platform/graphics/chromium/UniscribeHelper.cpp @@ -0,0 +1,902 @@ +/* + * Copyright (c) 2006, 2007, 2008, 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 "UniscribeHelper.h" + +#include <windows.h> + +#include "FontUtilsChromiumWin.h" +#include <wtf/Assertions.h> + +namespace WebCore { + +// This function is used to see where word spacing should be applied inside +// runs. Note that this must match Font::treatAsSpace so we all agree where +// and how much space this is, so we don't want to do more general Unicode +// "is this a word break" thing. +static bool treatAsSpace(UChar c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == 0x00A0; +} + +// SCRIPT_FONTPROPERTIES contains glyph indices for default, invalid +// and blank glyphs. Just because ScriptShape succeeds does not mean +// that a text run is rendered correctly. Some characters may be rendered +// with default/invalid/blank glyphs. Therefore, we need to check if the glyph +// array returned by ScriptShape contains any of those glyphs to make +// sure that the text run is rendered successfully. +static bool containsMissingGlyphs(WORD *glyphs, + int length, + SCRIPT_FONTPROPERTIES* properties) +{ + for (int i = 0; i < length; ++i) { + if (glyphs[i] == properties->wgDefault + || (glyphs[i] == properties->wgInvalid + && glyphs[i] != properties->wgBlank)) + return true; + } + + return false; +} + +// HFONT is the 'incarnation' of 'everything' about font, but it's an opaque +// handle and we can't directly query it to make a new HFONT sharing +// its characteristics (height, style, etc) except for family name. +// This function uses GetObject to convert HFONT back to LOGFONT, +// resets the fields of LOGFONT and calculates style to use later +// for the creation of a font identical to HFONT other than family name. +static void setLogFontAndStyle(HFONT hfont, LOGFONT *logfont, int *style) +{ + ASSERT(hfont && logfont); + if (!hfont || !logfont) + return; + + GetObject(hfont, sizeof(LOGFONT), logfont); + // We reset these fields to values appropriate for CreateFontIndirect. + // while keeping lfHeight, which is the most important value in creating + // a new font similar to hfont. + logfont->lfWidth = 0; + logfont->lfEscapement = 0; + logfont->lfOrientation = 0; + logfont->lfCharSet = DEFAULT_CHARSET; + logfont->lfOutPrecision = OUT_TT_ONLY_PRECIS; + logfont->lfQuality = DEFAULT_QUALITY; // Honor user's desktop settings. + logfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + if (style) + *style = getStyleFromLogfont(logfont); +} + +UniscribeHelper::UniscribeHelper(const UChar* input, + int inputLength, + bool isRtl, + HFONT hfont, + SCRIPT_CACHE* scriptCache, + SCRIPT_FONTPROPERTIES* fontProperties) + : m_input(input) + , m_inputLength(inputLength) + , m_isRtl(isRtl) + , m_hfont(hfont) + , m_scriptCache(scriptCache) + , m_fontProperties(fontProperties) + , m_directionalOverride(false) + , m_inhibitLigate(false) + , m_letterSpacing(0) + , m_spaceWidth(0) + , m_wordSpacing(0) + , m_ascent(0) +{ + m_logfont.lfFaceName[0] = 0; +} + +UniscribeHelper::~UniscribeHelper() +{ +} + +void UniscribeHelper::initWithOptionalLengthProtection(bool lengthProtection) +{ + // We cap the input length and just don't do anything. We'll allocate a lot + // of things of the size of the number of characters, so the allocated + // memory will be several times the input length. Plus shaping such a large + // buffer may be a form of denial of service. No legitimate text should be + // this long. It also appears that Uniscribe flatly rejects very long + // strings, so we don't lose anything by doing this. + // + // The input length protection may be disabled by the unit tests to cause + // an error condition. + static const int kMaxInputLength = 65535; + if (m_inputLength == 0 || (lengthProtection && m_inputLength > kMaxInputLength)) + return; + + fillRuns(); + fillShapes(); + fillScreenOrder(); +} + +int UniscribeHelper::width() const +{ + int width = 0; + for (int itemIndex = 0; itemIndex < static_cast<int>(m_runs.size()); itemIndex++) + width += advanceForItem(itemIndex); + return width; +} + +void UniscribeHelper::justify(int additionalSpace) +{ + // Count the total number of glyphs we have so we know how big to make the + // buffers below. + int totalGlyphs = 0; + for (size_t run = 0; run < m_runs.size(); run++) { + int runIndex = m_screenOrder[run]; + totalGlyphs += static_cast<int>(m_shapes[runIndex].glyphLength()); + } + if (totalGlyphs == 0) + return; // Nothing to do. + + // We make one big buffer in screen order of all the glyphs we are drawing + // across runs so that the justification function will adjust evenly across + // all glyphs. + Vector<SCRIPT_VISATTR, 64> visualAttributes; + visualAttributes.resize(totalGlyphs); + Vector<int, 64> advances; + advances.resize(totalGlyphs); + Vector<int, 64> justify; + justify.resize(totalGlyphs); + + // Build the packed input. + int destIndex = 0; + for (size_t run = 0; run < m_runs.size(); run++) { + int runIndex = m_screenOrder[run]; + const Shaping& shaping = m_shapes[runIndex]; + + for (int i = 0; i < shaping.glyphLength(); i++, destIndex++) { + memcpy(&visualAttributes[destIndex], &shaping.m_visualAttributes[i], + sizeof(SCRIPT_VISATTR)); + advances[destIndex] = shaping.m_advance[i]; + } + } + + // The documentation for Scriptjustify is wrong, the parameter is the space + // to add and not the width of the column you want. + const int minKashida = 1; // How do we decide what this should be? + ScriptJustify(&visualAttributes[0], &advances[0], totalGlyphs, + additionalSpace, minKashida, &justify[0]); + + // Now we have to unpack the justification amounts back into the runs so + // the glyph indices match. + int globalGlyphIndex = 0; + for (size_t run = 0; run < m_runs.size(); run++) { + int runIndex = m_screenOrder[run]; + Shaping& shaping = m_shapes[runIndex]; + + shaping.m_justify.resize(shaping.glyphLength()); + for (int i = 0; i < shaping.glyphLength(); i++, globalGlyphIndex++) + shaping.m_justify[i] = justify[globalGlyphIndex]; + } +} + +int UniscribeHelper::characterToX(int offset) const +{ + HRESULT hr; + ASSERT(offset <= m_inputLength); + + // Our algorithm is to traverse the items in screen order from left to + // right, adding in each item's screen width until we find the item with + // the requested character in it. + int width = 0; + for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) { + // Compute the length of this run. + int itemIndex = m_screenOrder[screenIndex]; + const SCRIPT_ITEM& item = m_runs[itemIndex]; + const Shaping& shaping = m_shapes[itemIndex]; + int itemLength = shaping.charLength(); + + if (offset >= item.iCharPos && offset <= item.iCharPos + itemLength) { + // Character offset is in this run. + int charLength = offset - item.iCharPos; + + int curX = 0; + hr = ScriptCPtoX(charLength, FALSE, itemLength, + shaping.glyphLength(), + &shaping.m_logs[0], &shaping.m_visualAttributes[0], + shaping.effectiveAdvances(), &item.a, &curX); + if (FAILED(hr)) + return 0; + + width += curX + shaping.m_prePadding; + ASSERT(width >= 0); + return width; + } + + // Move to the next item. + width += advanceForItem(itemIndex); + } + ASSERT(width >= 0); + return width; +} + +int UniscribeHelper::xToCharacter(int x) const +{ + // We iterate in screen order until we find the item with the given pixel + // position in it. When we find that guy, we ask Uniscribe for the + // character index. + HRESULT hr; + for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) { + int itemIndex = m_screenOrder[screenIndex]; + int itemAdvance = advanceForItem(itemIndex); + + // Note that the run may be empty if shaping failed, so we want to skip + // over it. + const Shaping& shaping = m_shapes[itemIndex]; + int itemLength = shaping.charLength(); + if (x <= itemAdvance && itemLength > 0) { + // The requested offset is within this item. + const SCRIPT_ITEM& item = m_runs[itemIndex]; + + // Account for the leading space we've added to this run that + // Uniscribe doesn't know about. + x -= shaping.m_prePadding; + + int charX = 0; + int trailing; + hr = ScriptXtoCP(x, itemLength, shaping.glyphLength(), + &shaping.m_logs[0], &shaping.m_visualAttributes[0], + shaping.effectiveAdvances(), &item.a, &charX, + &trailing); + + // The character offset is within the item. We need to add the + // item's offset to transform it into the space of the TextRun + return charX + item.iCharPos; + } + + // The offset is beyond this item, account for its length and move on. + x -= itemAdvance; + } + + // Error condition, we don't know what to do if we don't have that X + // position in any of our items. + return 0; +} + +void UniscribeHelper::draw(HDC dc, int x, int y, int from, int to) +{ + HGDIOBJ oldFont = 0; + int curX = x; + bool firstRun = true; + + for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) { + int itemIndex = m_screenOrder[screenIndex]; + const SCRIPT_ITEM& item = m_runs[itemIndex]; + const Shaping& shaping = m_shapes[itemIndex]; + + // Character offsets within this run. THESE MAY NOT BE IN RANGE and may + // be negative, etc. The code below handles this. + int fromChar = from - item.iCharPos; + int toChar = to - item.iCharPos; + + // See if we need to draw any characters in this item. + if (shaping.charLength() == 0 || + fromChar >= shaping.charLength() || toChar <= 0) { + // No chars in this item to display. + curX += advanceForItem(itemIndex); + continue; + } + + // Compute the starting glyph within this span. |from| and |to| are + // global offsets that may intersect arbitrarily with our local run. + int fromGlyph, afterGlyph; + if (item.a.fRTL) { + // To compute the first glyph when going RTL, we use |to|. + if (toChar >= shaping.charLength()) + // The end of the text is after (to the left) of us. + fromGlyph = 0; + else { + // Since |to| is exclusive, the first character we draw on the + // left is actually the one right before (to the right) of + // |to|. + fromGlyph = shaping.m_logs[toChar - 1]; + } + + // The last glyph is actually the first character in the range. + if (fromChar <= 0) { + // The first character to draw is before (to the right) of this + // span, so draw all the way to the end. + afterGlyph = shaping.glyphLength(); + } else { + // We want to draw everything up until the character to the + // right of |from|. To the right is - 1, so we look that up + // (remember our character could be more than one glyph, so we + // can't look up our glyph and add one). + afterGlyph = shaping.m_logs[fromChar - 1]; + } + } else { + // Easy case, everybody agrees about directions. We only need to + // handle boundary conditions to get a range inclusive at the + // beginning, and exclusive at the ending. We have to do some + // computation to see the glyph one past the end. + fromGlyph = shaping.m_logs[fromChar < 0 ? 0 : fromChar]; + if (toChar >= shaping.charLength()) + afterGlyph = shaping.glyphLength(); + else + afterGlyph = shaping.m_logs[toChar]; + } + + // Account for the characters that were skipped in this run. When + // WebKit asks us to draw a subset of the run, it actually tells us + // to draw at the X offset of the beginning of the run, since it + // doesn't know the internal position of any of our characters. + const int* effectiveAdvances = shaping.effectiveAdvances(); + int innerOffset = 0; + for (int i = 0; i < fromGlyph; i++) + innerOffset += effectiveAdvances[i]; + + // Actually draw the glyphs we found. + int glyphCount = afterGlyph - fromGlyph; + if (fromGlyph >= 0 && glyphCount > 0) { + // Account for the preceeding space we need to add to this run. We + // don't need to count for the following space because that will be + // counted in advanceForItem below when we move to the next run. + innerOffset += shaping.m_prePadding; + + // 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); + + // Fonts with different ascents can be used to render different + // runs. 'Across-runs' y-coordinate correction needs to be + // adjusted for each font. + HRESULT hr = S_FALSE; + for (int executions = 0; executions < 2; ++executions) { + hr = ScriptTextOut(dc, shaping.m_scriptCache, + curX + innerOffset, + y - shaping.m_ascentOffset, + 0, 0, &item.a, 0, 0, + &shaping.m_glyphs[fromGlyph], + glyphCount, + &shaping.m_advance[fromGlyph], + justify, + &shaping.m_offsets[fromGlyph]); + if (S_OK != hr && 0 == executions) { + // If this ScriptTextOut is called from the renderer it + // might fail because the sandbox is preventing it from + // opening the font files. If we are running in the + // renderer, TryToPreloadFont is overridden to ask the + // browser to preload the font for us so we can access it. + tryToPreloadFont(shaping.m_hfont); + continue; + } + break; + } + + ASSERT(S_OK == hr); + } + + curX += advanceForItem(itemIndex); + } + + if (oldFont) + SelectObject(dc, oldFont); +} + +WORD UniscribeHelper::firstGlyphForCharacter(int charOffset) const +{ + // Find the run for the given character. + for (int i = 0; i < static_cast<int>(m_runs.size()); i++) { + int firstChar = m_runs[i].iCharPos; + const Shaping& shaping = m_shapes[i]; + int localOffset = charOffset - firstChar; + if (localOffset >= 0 && localOffset < shaping.charLength()) { + // The character is in this run, return the first glyph for it + // (should generally be the only glyph). It seems Uniscribe gives + // glyph 0 for empty, which is what we want to return in the + // "missing" case. + size_t glyphIndex = shaping.m_logs[localOffset]; + if (glyphIndex >= shaping.m_glyphs.size()) { + // The glyph should be in this run, but the run has too few + // actual characters. This can happen when shaping the run + // fails, in which case, we should have no data in the logs at + // all. + ASSERT(shaping.m_glyphs.size() == 0); + return 0; + } + return shaping.m_glyphs[glyphIndex]; + } + } + + return 0; +} + +void UniscribeHelper::fillRuns() +{ + HRESULT hr; + m_runs.resize(UNISCRIBE_HELPER_STACK_RUNS); + + SCRIPT_STATE inputState; + inputState.uBidiLevel = m_isRtl; + inputState.fOverrideDirection = m_directionalOverride; + inputState.fInhibitSymSwap = false; + inputState.fCharShape = false; // Not implemented in Uniscribe + inputState.fDigitSubstitute = false; // Do we want this for Arabic? + inputState.fInhibitLigate = m_inhibitLigate; + inputState.fDisplayZWG = false; // Don't draw control characters. + inputState.fArabicNumContext = m_isRtl; // Do we want this for Arabic? + inputState.fGcpClusters = false; + inputState.fReserved = 0; + inputState.fEngineReserved = 0; + // The psControl argument to ScriptItemize should be non-0 for RTL text, + // per http://msdn.microsoft.com/en-us/library/ms776532.aspx . So use a + // SCRIPT_CONTROL that is set to all zeros. Zero as a locale ID means the + // neutral locale per http://msdn.microsoft.com/en-us/library/ms776294.aspx + static SCRIPT_CONTROL inputControl = {0, // uDefaultLanguage :16; + 0, // fContextDigits :1; + 0, // fInvertPreBoundDir :1; + 0, // fInvertPostBoundDir :1; + 0, // fLinkStringBefore :1; + 0, // fLinkStringAfter :1; + 0, // fNeutralOverride :1; + 0, // fNumericOverride :1; + 0, // fLegacyBidiClass :1; + 0, // fMergeNeutralItems :1; + 0};// fReserved :7; + // Calling ScriptApplyDigitSubstitution( 0, &inputControl, &inputState) + // here would be appropriate if we wanted to set the language ID, and get + // local digit substitution behavior. For now, don't do it. + + while (true) { + int numberOfItems = 0; + + // Ideally, we would have a way to know the runs before and after this + // one, and put them into the control parameter of ScriptItemize. This + // would allow us to shape characters properly that cross style + // boundaries (WebKit bug 6148). + // + // We tell ScriptItemize that the output list of items is one smaller + // than it actually is. According to Mozilla bug 366643, if there is + // not enough room in the array on pre-SP2 systems, ScriptItemize will + // write one past the end of the buffer. + // + // ScriptItemize is very strange. It will often require a much larger + // ITEM buffer internally than it will give us as output. For example, + // it will say a 16-item buffer is not big enough, and will write + // interesting numbers into all those items. But when we give it a 32 + // item buffer and it succeeds, it only has one item output. + // + // It seems to be doing at least two passes, the first where it puts a + // lot of intermediate data into our items, and the second where it + // collates them. + hr = ScriptItemize(m_input, m_inputLength, + static_cast<int>(m_runs.size()) - 1, &inputControl, + &inputState, + &m_runs[0], &numberOfItems); + if (SUCCEEDED(hr)) { + m_runs.resize(numberOfItems); + break; + } + if (hr != E_OUTOFMEMORY) { + // Some kind of unexpected error. + m_runs.resize(0); + break; + } + // There was not enough items for it to write into, expand. + m_runs.resize(m_runs.size() * 2); + } +} + +bool UniscribeHelper::shape(const UChar* input, + int itemLength, + int numGlyphs, + SCRIPT_ITEM& run, + Shaping& shaping) +{ + HFONT hfont = m_hfont; + SCRIPT_CACHE* scriptCache = m_scriptCache; + SCRIPT_FONTPROPERTIES* fontProperties = m_fontProperties; + int ascent = m_ascent; + HDC tempDC = 0; + HGDIOBJ oldFont = 0; + HRESULT hr; + bool lastFallbackTried = false; + bool result; + + int generatedGlyphs = 0; + + // In case HFONT passed in ctor cannot render this run, we have to scan + // other fonts from the beginning of the font list. + resetFontIndex(); + + // Compute shapes. + while (true) { + shaping.m_logs.resize(itemLength); + shaping.m_glyphs.resize(numGlyphs); + shaping.m_visualAttributes.resize(numGlyphs); + +#ifdef PURIFY + // http://code.google.com/p/chromium/issues/detail?id=5309 + // Purify isn't able to track the assignments that ScriptShape makes to + // shaping.m_glyphs. Consequently, any bytes with value 0xCD that it + // writes, will be considered un-initialized data. + // + // This hack avoid the false-positive UMRs by marking the buffer as + // initialized. + // + // FIXME: A better solution would be to use Purify's API and mark only + // the populated range as initialized: + // + // PurifyMarkAsInitialized( + // &shaping.m_glyphs[0], + // sizeof(shaping.m_glyphs[0] * generatedGlyphs); + + ZeroMemory(&shaping.m_glyphs[0], + sizeof(shaping.m_glyphs[0]) * shaping.m_glyphs.size()); +#endif + + // Firefox sets SCRIPT_ANALYSIS.SCRIPT_STATE.fDisplayZWG to true + // here. Is that what we want? It will display control characters. + hr = ScriptShape(tempDC, scriptCache, input, itemLength, + numGlyphs, &run.a, + &shaping.m_glyphs[0], &shaping.m_logs[0], + &shaping.m_visualAttributes[0], &generatedGlyphs); + if (hr == E_PENDING) { + // Allocate the DC. + tempDC = GetDC(0); + oldFont = SelectObject(tempDC, hfont); + continue; + } else if (hr == E_OUTOFMEMORY) { + numGlyphs *= 2; + continue; + } else if (SUCCEEDED(hr) && (lastFallbackTried || !containsMissingGlyphs(&shaping.m_glyphs[0], generatedGlyphs, fontProperties))) + break; + + // The current font can't render this run. clear DC and try + // next font. + if (tempDC) { + SelectObject(tempDC, oldFont); + ReleaseDC(0, tempDC); + tempDC = 0; + } + + if (nextWinFontData(&hfont, &scriptCache, &fontProperties, &ascent)) { + // The primary font does not support this run. Try next font. + // In case of web page rendering, they come from fonts specified in + // CSS stylesheets. + continue; + } else if (!lastFallbackTried) { + lastFallbackTried = true; + + // Generate a last fallback font based on the script of + // a character to draw while inheriting size and styles + // from the primary font + if (!m_logfont.lfFaceName[0]) + setLogFontAndStyle(m_hfont, &m_logfont, &m_style); + + // TODO(jungshik): generic type should come from webkit for + // UniscribeHelperTextRun (a derived class used in webkit). + const UChar *family = getFallbackFamily(input, itemLength, + FontDescription::StandardFamily, 0, 0); + bool fontOk = getDerivedFontData(family, m_style, &m_logfont, + &ascent, &hfont, &scriptCache); + + if (!fontOk) { + // If this GetDerivedFontData is called from the renderer it + // might fail because the sandbox is preventing it from opening + // the font files. If we are running in the renderer, + // TryToPreloadFont is overridden to ask the browser to preload + // the font for us so we can access it. + tryToPreloadFont(hfont); + + // Try again. + fontOk = getDerivedFontData(family, m_style, &m_logfont, + &ascent, &hfont, &scriptCache); + ASSERT(fontOk); + } + + // TODO(jungshik) : Currently GetDerivedHFont always returns a + // a valid HFONT, but in the future, I may change it to return 0. + ASSERT(hfont); + + // We don't need a font_properties for the last resort fallback font + // because we don't have anything more to try and are forced to + // accept empty glyph boxes. If we tried a series of fonts as + // 'last-resort fallback', we'd need it, but currently, we don't. + continue; + } else if (hr == USP_E_SCRIPT_NOT_IN_FONT) { + run.a.eScript = SCRIPT_UNDEFINED; + continue; + } else if (FAILED(hr)) { + // Error shaping. + generatedGlyphs = 0; + result = false; + goto cleanup; + } + } + + // Sets Windows font data for this run to those corresponding to + // a font supporting this run. we don't need to store font_properties + // because it's not used elsewhere. + shaping.m_hfont = hfont; + shaping.m_scriptCache = scriptCache; + + // The ascent of a font for this run can be different from + // that of the primary font so that we need to keep track of + // the difference per run and take that into account when calling + // ScriptTextOut in |draw|. Otherwise, different runs rendered by + // different fonts would not be aligned vertically. + shaping.m_ascentOffset = m_ascent ? ascent - m_ascent : 0; + result = true; + + cleanup: + shaping.m_glyphs.resize(generatedGlyphs); + shaping.m_visualAttributes.resize(generatedGlyphs); + shaping.m_advance.resize(generatedGlyphs); + shaping.m_offsets.resize(generatedGlyphs); + if (tempDC) { + SelectObject(tempDC, oldFont); + ReleaseDC(0, tempDC); + } + // On failure, our logs don't mean anything, so zero those out. + if (!result) + shaping.m_logs.clear(); + + return result; +} + +void UniscribeHelper::fillShapes() +{ + m_shapes.resize(m_runs.size()); + for (size_t i = 0; i < m_runs.size(); i++) { + int startItem = m_runs[i].iCharPos; + int itemLength = m_inputLength - startItem; + if (i < m_runs.size() - 1) + itemLength = m_runs[i + 1].iCharPos - startItem; + + int numGlyphs; + if (itemLength < UNISCRIBE_HELPER_STACK_CHARS) { + // We'll start our buffer sizes with the current stack space + // available in our buffers if the current input fits. As long as + // it doesn't expand past that we'll save a lot of time mallocing. + numGlyphs = UNISCRIBE_HELPER_STACK_CHARS; + } else { + // When the input doesn't fit, give up with the stack since it will + // almost surely not be enough room (unless the input actually + // shrinks, which is unlikely) and just start with the length + // recommended by the Uniscribe documentation as a "usually fits" + // size. + numGlyphs = itemLength * 3 / 2 + 16; + } + + // Convert a string to a glyph string trying the primary font, fonts in + // the fallback list and then script-specific last resort font. + Shaping& shaping = m_shapes[i]; + if (!shape(&m_input[startItem], itemLength, numGlyphs, m_runs[i], shaping)) + continue; + + // Compute placements. Note that offsets is documented incorrectly + // and is actually an array. + + // DC that we lazily create if Uniscribe commands us to. + // (this does not happen often because scriptCache is already + // updated when calling ScriptShape). + HDC tempDC = 0; + HGDIOBJ oldFont = 0; + HRESULT hr; + while (true) { + shaping.m_prePadding = 0; + hr = ScriptPlace(tempDC, shaping.m_scriptCache, + &shaping.m_glyphs[0], + static_cast<int>(shaping.m_glyphs.size()), + &shaping.m_visualAttributes[0], &m_runs[i].a, + &shaping.m_advance[0], &shaping.m_offsets[0], + &shaping.m_abc); + if (hr != E_PENDING) + break; + + // Allocate the DC and run the loop again. + tempDC = GetDC(0); + oldFont = SelectObject(tempDC, shaping.m_hfont); + } + + if (FAILED(hr)) { + // Some error we don't know how to handle. Nuke all of our data + // since we can't deal with partially valid data later. + m_runs.clear(); + m_shapes.clear(); + m_screenOrder.clear(); + } + + if (tempDC) { + SelectObject(tempDC, oldFont); + ReleaseDC(0, tempDC); + } + } + + adjustSpaceAdvances(); + + if (m_letterSpacing != 0 || m_wordSpacing != 0) + applySpacing(); +} + +void UniscribeHelper::fillScreenOrder() +{ + m_screenOrder.resize(m_runs.size()); + + // We assume that the input has only one text direction in it. + // TODO(brettw) are we sure we want to keep this restriction? + if (m_isRtl) { + for (int i = 0; i < static_cast<int>(m_screenOrder.size()); i++) + m_screenOrder[static_cast<int>(m_screenOrder.size()) - i - 1] = i; + } else { + for (int i = 0; i < static_cast<int>(m_screenOrder.size()); i++) + m_screenOrder[i] = i; + } +} + +void UniscribeHelper::adjustSpaceAdvances() +{ + if (m_spaceWidth == 0) + return; + + int spaceWidthWithoutLetterSpacing = m_spaceWidth - m_letterSpacing; + + // This mostly matches what WebKit's UniscribeController::shapeAndPlaceItem. + for (size_t run = 0; run < m_runs.size(); run++) { + Shaping& shaping = m_shapes[run]; + + for (int i = 0; i < shaping.charLength(); i++) { + if (!treatAsSpace(m_input[m_runs[run].iCharPos + i])) + continue; + + int glyphIndex = shaping.m_logs[i]; + int currentAdvance = shaping.m_advance[glyphIndex]; + // Don't give zero-width spaces a width. + if (!currentAdvance) + continue; + + // currentAdvance does not include additional letter-spacing, but + // space_width does. Here we find out how off we are from the + // correct width for the space not including letter-spacing, then + // just subtract that diff. + int diff = currentAdvance - spaceWidthWithoutLetterSpacing; + // The shaping can consist of a run of text, so only subtract the + // difference in the width of the glyph. + shaping.m_advance[glyphIndex] -= diff; + shaping.m_abc.abcB -= diff; + } + } +} + +void UniscribeHelper::applySpacing() +{ + for (size_t run = 0; run < m_runs.size(); run++) { + Shaping& shaping = m_shapes[run]; + bool isRtl = m_runs[run].a.fRTL; + + if (m_letterSpacing != 0) { + // RTL text gets padded to the left of each character. We increment + // the run's advance to make this happen. This will be balanced out + // by NOT adding additional advance to the last glyph in the run. + if (isRtl) + shaping.m_prePadding += m_letterSpacing; + + // Go through all the glyphs in this run and increase the "advance" + // to account for letter spacing. We adjust letter spacing only on + // cluster boundaries. + // + // This works for most scripts, but may have problems with some + // indic scripts. This behavior is better than Firefox or IE for + // Hebrew. + for (int i = 0; i < shaping.glyphLength(); i++) { + if (shaping.m_visualAttributes[i].fClusterStart) { + // Ick, we need to assign the extra space so that the glyph + // comes first, then is followed by the space. This is + // opposite for RTL. + if (isRtl) { + if (i != shaping.glyphLength() - 1) { + // All but the last character just get the spacing + // applied to their advance. The last character + // doesn't get anything, + shaping.m_advance[i] += m_letterSpacing; + shaping.m_abc.abcB += m_letterSpacing; + } + } else { + // LTR case is easier, we just add to the advance. + shaping.m_advance[i] += m_letterSpacing; + shaping.m_abc.abcB += m_letterSpacing; + } + } + } + } + + // Go through all the characters to find whitespace and insert the + // extra wordspacing amount for the glyphs they correspond to. + if (m_wordSpacing != 0) { + for (int i = 0; i < shaping.charLength(); i++) { + if (!treatAsSpace(m_input[m_runs[run].iCharPos + i])) + continue; + + // The char in question is a word separator... + int glyphIndex = shaping.m_logs[i]; + + // Spaces will not have a glyph in Uniscribe, it will just add + // additional advance to the character to the left of the + // space. The space's corresponding glyph will be the character + // following it in reading order. + if (isRtl) { + // In RTL, the glyph to the left of the space is the same + // as the first glyph of the following character, so we can + // just increment it. + shaping.m_advance[glyphIndex] += m_wordSpacing; + shaping.m_abc.abcB += m_wordSpacing; + } else { + // LTR is actually more complex here, we apply it to the + // previous character if there is one, otherwise we have to + // apply it to the leading space of the run. + if (glyphIndex == 0) + shaping.m_prePadding += m_wordSpacing; + else { + shaping.m_advance[glyphIndex - 1] += m_wordSpacing; + shaping.m_abc.abcB += m_wordSpacing; + } + } + } + } // m_wordSpacing != 0 + + // Loop for next run... + } +} + +// The advance is the ABC width of the run +int UniscribeHelper::advanceForItem(int itemIndex) const +{ + int accum = 0; + const Shaping& shaping = m_shapes[itemIndex]; + + if (shaping.m_justify.size() == 0) { + // Easy case with no justification, the width is just the ABC width of + // the run. (The ABC width is the sum of the advances). + return shaping.m_abc.abcA + shaping.m_abc.abcB + + shaping.m_abc.abcC + shaping.m_prePadding; + } + + // With justification, we use the justified amounts instead. The + // justification array contains both the advance and the extra space + // added for justification, so is the width we want. + int justification = 0; + for (size_t i = 0; i < shaping.m_justify.size(); i++) + justification += shaping.m_justify[i]; + + return shaping.m_prePadding + justification; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/UniscribeHelper.h b/WebCore/platform/graphics/chromium/UniscribeHelper.h new file mode 100644 index 0000000..d291105 --- /dev/null +++ b/WebCore/platform/graphics/chromium/UniscribeHelper.h @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2006, 2007, 2008, 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. + */ + +// A wrapper around Uniscribe that provides a reasonable API. + +#ifndef UniscribeHelper_h +#define UniscribeHelper_h + +#include <windows.h> +#include <usp10.h> +#include <map> + +#include <unicode/uchar.h> +#include <wtf/Vector.h> + +class UniscribeTest_TooBig_Test; // A gunit test for UniscribeHelper. + +namespace WebCore { + +#define UNISCRIBE_HELPER_STACK_RUNS 8 +#define UNISCRIBE_HELPER_STACK_CHARS 32 + +// This object should be safe to create & destroy frequently, as long as the +// caller preserves the script_cache when possible (this data may be slow to +// compute). +// +// This object is "kind of large" (~1K) because it reserves a lot of space for +// working with to avoid expensive heap operations. Therefore, not only should +// you not worry about creating and destroying it, you should try to not keep +// them around. +class UniscribeHelper { +public: + // Initializes this Uniscribe run with the text pointed to by |run| with + // |length|. The input is NOT null terminated. + // + // The is_rtl flag should be set if the input script is RTL. It is assumed + // that the caller has already divided up the input text (using ICU, for + // example) into runs of the same direction of script. This avoids + // disagreements between the caller and Uniscribe later (see FillItems). + // + // A script cache should be provided by the caller that is initialized to + // NULL. When the caller is done with the cache (it may be stored between + // runs as long as it is used consistently with the same HFONT), it should + // call ScriptFreeCache(). + UniscribeHelper(const UChar* input, + int inputLength, + bool isRtl, + HFONT, + SCRIPT_CACHE*, + SCRIPT_FONTPROPERTIES*); + + virtual ~UniscribeHelper(); + + // Sets Uniscribe's directional override flag. False by default. + bool directionalOverride() const + { + return m_directionalOverride; + } + void setDirectionalOverride(bool override) + { + m_directionalOverride = override; + } + + // Set's Uniscribe's no-ligate override flag. False by default. + bool inhibitLigate() const + { + return m_inhibitLigate; + } + void setInhibitLigate(bool inhibit) + { + m_inhibitLigate = inhibit; + } + + // Set letter spacing. We will try to insert this much space between + // graphemes (one or more glyphs perceived as a single unit by ordinary + // users of a script). Positive values increase letter spacing, negative + // values decrease it. 0 by default. + int letterSpacing() const + { + return m_letterSpacing; + } + void setLetterSpacing(int letterSpacing) + { + m_letterSpacing = letterSpacing; + } + + // Set the width of a standard space character. We use this to normalize + // space widths. Windows will make spaces after Hindi characters larger than + // other spaces. A space_width of 0 means to use the default space width. + // + // Must be set before Init() is called. + int spaceWidth() const + { + return m_spaceWidth; + } + void setSpaceWidth(int spaceWidth) + { + m_spaceWidth = spaceWidth; + } + + // Set word spacing. We will try to insert this much extra space between + // each word in the input (beyond whatever whitespace character separates + // words). Positive values lead to increased letter spacing, negative values + // decrease it. 0 by default. + // + // Must be set before Init() is called. + int wordSpacing() const + { + return m_wordSpacing; + } + void setWordSpacing(int wordSpacing) + { + m_wordSpacing = wordSpacing; + } + + void setAscent(int ascent) + { + m_ascent = ascent; + } + + // You must call this after setting any options but before doing any + // other calls like asking for widths or drawing. + void init() + { + initWithOptionalLengthProtection(true); + } + + // Returns the total width in pixels of the text run. + int width() const; + + // Call to justify the text, with the amount of space that should be ADDED + // to get the desired width that the column should be justified to. + // Normally, spaces are inserted, but for Arabic there will be kashidas + // (extra strokes) inserted instead. + // + // This function MUST be called AFTER Init(). + void justify(int additionalSpace); + + // Computes the given character offset into a pixel offset of the beginning + // of that character. + int characterToX(int offset) const; + + // Converts the given pixel X position into a logical character offset into + // the run. For positions appearing before the first character, this will + // return -1. + int xToCharacter(int x) const; + + // Draws the given characters to (x, y) in the given DC. The font will be + // handled by this function, but the font color and other attributes should + // be pre-set. + // + // The y position is the upper left corner, NOT the baseline. + void draw(HDC, int x, int y, int from, int to); + + // Returns the first glyph assigned to the character at the given offset. + // This function is used to retrieve glyph information when Uniscribe is + // being used to generate glyphs for non-complex, non-BMP (above U+FFFF) + // characters. These characters are not otherwise special and have no + // complex shaping rules, so we don't otherwise need Uniscribe, except + // Uniscribe is the only way to get glyphs for non-BMP characters. + // + // Returns 0 if there is no glyph for the given character. + WORD firstGlyphForCharacter(int charOffset) const; + +protected: + // Backend for init. The flag allows the unit test to specify whether we + // should fail early for very long strings like normal, or try to pass the + // long string to Uniscribe. The latter provides a way to force failure of + // shaping. + void initWithOptionalLengthProtection(bool lengthProtection); + + // Tries to preload the font when the it is not accessible. + // This is the default implementation and it does not do anything. + virtual void tryToPreloadFont(HFONT) {} + +private: + friend class UniscribeTest_TooBig_Test; + + // An array corresponding to each item in runs_ containing information + // on each of the glyphs that were generated. Like runs_, this is in + // reading order. However, for rtl text, the characters within each + // item will be reversed. + struct Shaping { + Shaping() + : m_prePadding(0) + , m_hfont(NULL) + , m_scriptCache(NULL) + , m_ascentOffset(0) { + m_abc.abcA = 0; + m_abc.abcB = 0; + m_abc.abcC = 0; + } + + // Returns the number of glyphs (which will be drawn to the screen) + // in this run. + int glyphLength() const + { + return static_cast<int>(m_glyphs.size()); + } + + // Returns the number of characters (that we started with) in this run. + int charLength() const + { + return static_cast<int>(m_logs.size()); + } + + // Returns the advance array that should be used when measuring glyphs. + // The returned pointer will indicate an array with glyph_length() + // elements and the advance that should be used for each one. This is + // either the real advance, or the justified advances if there is one, + // and is the array we want to use for measurement. + const int* effectiveAdvances() const + { + if (m_advance.size() == 0) + return 0; + if (m_justify.size() == 0) + return &m_advance[0]; + return &m_justify[0]; + } + + // This is the advance amount of space that we have added to the + // beginning of the run. It is like the ABC's |A| advance but one that + // we create and must handle internally whenever computing with pixel + // offsets. + int m_prePadding; + + // Glyph indices in the font used to display this item. These indices + // are in screen order. + Vector<WORD, UNISCRIBE_HELPER_STACK_CHARS> m_glyphs; + + // For each input character, this tells us the first glyph index it + // generated. This is the only array with size of the input chars. + // + // All offsets are from the beginning of this run. Multiple characters + // can generate one glyph, in which case there will be adjacent + // duplicates in this list. One character can also generate multiple + // glyphs, in which case there will be skipped indices in this list. + Vector<WORD, UNISCRIBE_HELPER_STACK_CHARS> m_logs; + + // Flags and such for each glyph. + Vector<SCRIPT_VISATTR, UNISCRIBE_HELPER_STACK_CHARS> m_visualAttributes; + + // Horizontal advances for each glyph listed above, this is basically + // how wide each glyph is. + Vector<int, UNISCRIBE_HELPER_STACK_CHARS> m_advance; + + // This contains glyph offsets, from the nominal position of a glyph. + // It is used to adjust the positions of multiple combining characters + // around/above/below base characters in a context-sensitive manner so + // that they don't bump against each other and the base character. + Vector<GOFFSET, UNISCRIBE_HELPER_STACK_CHARS> m_offsets; + + // Filled by a call to Justify, this is empty for nonjustified text. + // If nonempty, this contains the array of justify characters for each + // character as returned by ScriptJustify. + // + // This is the same as the advance array, but with extra space added + // for some characters. The difference between a glyph's |justify| + // width and it's |advance| width is the extra space added. + Vector<int, UNISCRIBE_HELPER_STACK_CHARS> m_justify; + + // Sizing information for this run. This treats the entire run as a + // character with a preceeding advance, width, and ending advance. The + // B width is the sum of the |advance| array, and the A and C widths + // are any extra spacing applied to each end. + // + // It is unclear from the documentation what this actually means. From + // experimentation, it seems that the sum of the character advances is + // always the sum of the ABC values, and I'm not sure what you're + // supposed to do with the ABC values. + ABC m_abc; + + // Pointers to windows font data used to render this run. + HFONT m_hfont; + SCRIPT_CACHE* m_scriptCache; + + // Ascent offset between the ascent of the primary font + // and that of the fallback font. The offset needs to be applied, + // when drawing a string, to align multiple runs rendered with + // different fonts. + int m_ascentOffset; + }; + + // Computes the runs_ array from the text run. + void fillRuns(); + + // Computes the shapes_ array given an runs_ array already filled in. + void fillShapes(); + + // Fills in the screen_order_ array (see below). + void fillScreenOrder(); + + // Called to update the glyph positions based on the current spacing + // options that are set. + void applySpacing(); + + // Normalizes all advances for spaces to the same width. This keeps windows + // from making spaces after Hindi characters larger, which is then + // inconsistent with our meaure of the width since WebKit doesn't include + // spaces in text-runs sent to uniscribe unless white-space:pre. + void adjustSpaceAdvances(); + + // Returns the total width of a single item. + int advanceForItem(int) const; + + // Shapes a run (pointed to by |input|) using |hfont| first. + // Tries a series of fonts specified retrieved with NextWinFontData + // and finally a font covering characters in |*input|. A string pointed + // by |input| comes from ScriptItemize and is supposed to contain + // characters belonging to a single script aside from characters common to + // all scripts (e.g. space). + bool shape(const UChar* input, int itemLength, int numGlyphs, SCRIPT_ITEM& run, Shaping&); + + // Gets Windows font data for the next best font to try in the list + // of fonts. When there's no more font available, returns false + // without touching any of out params. Need to call ResetFontIndex + // to start scanning of the font list from the beginning. + virtual bool nextWinFontData(HFONT*, SCRIPT_CACHE**, SCRIPT_FONTPROPERTIES**, int* ascent) + { + return false; + } + + // Resets the font index to the first in the list of fonts to try after the + // primaryFont turns out not to work. With fontIndex reset, + // NextWinFontData scans fallback fonts from the beginning. + virtual void resetFontIndex() {} + + // The input data for this run of Uniscribe. See the constructor. + const UChar* m_input; + const int m_inputLength; + const bool m_isRtl; + + // Windows font data for the primary font. In a sense, m_logfont and m_style + // are redundant because m_hfont contains all the information. However, + // invoking GetObject, everytime we need the height and the style, is rather + // expensive so that we cache them. Would it be better to add getter and + // (virtual) setter for the height and the style of the primary font, + // instead of m_logfont? Then, a derived class ctor can set m_ascent, + // m_height and m_style if they're known. Getters for them would have to + // 'infer' their values from m_hfont ONLY when they're not set. + HFONT m_hfont; + SCRIPT_CACHE* m_scriptCache; + SCRIPT_FONTPROPERTIES* m_fontProperties; + int m_ascent; + LOGFONT m_logfont; + int m_style; + + // Options, see the getters/setters above. + bool m_directionalOverride; + bool m_inhibitLigate; + int m_letterSpacing; + int m_spaceWidth; + int m_wordSpacing; + + // Uniscribe breaks the text into Runs. These are one length of text that is + // in one script and one direction. This array is in reading order. + Vector<SCRIPT_ITEM, UNISCRIBE_HELPER_STACK_RUNS> m_runs; + + Vector<Shaping, UNISCRIBE_HELPER_STACK_RUNS> m_shapes; + + // This is a mapping between reading order and screen order for the items. + // Uniscribe's items array are in reading order. For right-to-left text, + // or mixed (although WebKit's |TextRun| should really be only one + // direction), this makes it very difficult to compute character offsets + // and positions. This list is in screen order from left to right, and + // gives the index into the |m_runs| and |m_shapes| arrays of each + // subsequent item. + Vector<int, UNISCRIBE_HELPER_STACK_RUNS> m_screenOrder; +}; + +} // namespace WebCore + +#endif // UniscribeHelper_h diff --git a/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp b/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp new file mode 100644 index 0000000..f801c13 --- /dev/null +++ b/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2006, 2007, 2008, 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 "UniscribeHelperTextRun.h" + +#include "ChromiumBridge.h" +#include "Font.h" +#include "SimpleFontData.h" + +namespace WebCore { + +UniscribeHelperTextRun::UniscribeHelperTextRun(const TextRun& run, + const Font& font) + : UniscribeHelper(run.characters(), run.length(), run.rtl(), + font.primaryFont()->platformData().hfont(), + font.primaryFont()->platformData().scriptCache(), + font.primaryFont()->platformData().scriptFontProperties()) + , m_font(&font) + , m_fontIndex(0) +{ + setDirectionalOverride(run.directionalOverride()); + setLetterSpacing(font.letterSpacing()); + setSpaceWidth(font.spaceWidth()); + setWordSpacing(font.wordSpacing()); + setAscent(font.primaryFont()->ascent()); + + init(); + + // Padding is the amount to add to make justification happen. This + // should be done after Init() so all the runs are already measured. + if (run.padding() > 0) + justify(run.padding()); +} + +UniscribeHelperTextRun::UniscribeHelperTextRun( + const wchar_t* input, + int inputLength, + bool isRtl, + HFONT hfont, + SCRIPT_CACHE* scriptCache, + SCRIPT_FONTPROPERTIES* fontProperties) + : UniscribeHelper(input, inputLength, isRtl, hfont, + scriptCache, fontProperties) + , m_font(0) + , m_fontIndex(-1) +{ +} + +void UniscribeHelperTextRun::tryToPreloadFont(HFONT font) +{ + // Ask the browser to get the font metrics for this font. + // That will preload the font and it should now be accessible + // from the renderer. + ChromiumBridge::ensureFontLoaded(font); +} + +bool UniscribeHelperTextRun::nextWinFontData( + HFONT* hfont, + SCRIPT_CACHE** scriptCache, + SCRIPT_FONTPROPERTIES** fontProperties, + int* ascent) +{ + // This check is necessary because NextWinFontData can be called again + // after we already ran out of fonts. fontDataAt behaves in a strange + // manner when the difference between param passed and # of fonts stored in + // WebKit::Font is larger than one. We can avoid this check by setting + // font_index_ to # of elements in hfonts_ when we run out of font. In that + // case, we'd have to go through a couple of more checks before returning + // false. + if (m_fontIndex == -1 || !m_font) + return false; + + // If the font data for a fallback font requested is not yet retrieved, add + // them to our vectors. Note that '>' rather than '>=' is used to test that + // condition. primaryFont is not stored in hfonts_, and friends so that + // indices for fontDataAt and our vectors for font data are 1 off from each + // other. That is, when fully populated, hfonts_ and friends have one font + // fewer than what's contained in font_. + if (static_cast<size_t>(++m_fontIndex) > m_hfonts.size()) { + const FontData *fontData = m_font->fontDataAt(m_fontIndex); + if (!fontData) { + // Ran out of fonts. + m_fontIndex = -1; + return false; + } + + // FIXME: this won't work for SegmentedFontData + // http://crbug.com/6425 + const SimpleFontData* simpleFontData = + fontData->fontDataForCharacter(' '); + + m_hfonts.append(simpleFontData->platformData().hfont()); + m_scriptCaches.append(simpleFontData->platformData().scriptCache()); + m_fontProperties.append(simpleFontData->platformData().scriptFontProperties()); + m_ascents.append(simpleFontData->ascent()); + } + + *hfont = m_hfonts[m_fontIndex - 1]; + *scriptCache = m_scriptCaches[m_fontIndex - 1]; + *fontProperties = m_fontProperties[m_fontIndex - 1]; + *ascent = m_ascents[m_fontIndex - 1]; + return true; +} + +void UniscribeHelperTextRun::resetFontIndex() +{ + m_fontIndex = 0; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.h b/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.h new file mode 100644 index 0000000..b5c54a0 --- /dev/null +++ b/WebCore/platform/graphics/chromium/UniscribeHelperTextRun.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2006, 2007, 2008, 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 UniscribeHelperTextRun_h +#define UniscribeHelperTextRun_h + +#include "UniscribeHelper.h" + +namespace WebCore { + +class Font; +class TextRun; + +// Wrapper around the Uniscribe helper that automatically sets it up with the +// WebKit types we supply. +class UniscribeHelperTextRun : public UniscribeHelper { +public: + // Regular constructor used for WebCore text run processing. + UniscribeHelperTextRun(const TextRun&, const Font&); + + // Constructor with the same interface as the gfx::UniscribeState. Using + // this constructor will not give you font fallback, but it will provide + // the ability to load fonts that may not be in the OS cache + // ("TryToPreloadFont") if the caller does not have a TextRun/Font. + UniscribeHelperTextRun(const wchar_t* input, + int inputLength, + bool isRtl, + HFONT hfont, + SCRIPT_CACHE*, + SCRIPT_FONTPROPERTIES*); + +protected: + virtual void tryToPreloadFont(HFONT); + +private: + // This function retrieves the Windows font data (HFONT, etc) for the next + // WebKit font in the list. If the font data corresponding to font_index_ + // has been obtained before, returns the values stored in our internal + // vectors (hfonts_, etc). Otherwise, it gets next SimpleFontData from + // WebKit and adds them to in hfonts_ and friends so that font data can be + // returned quickly next time they're requested. + virtual bool nextWinFontData(HFONT*, SCRIPT_CACHE**, SCRIPT_FONTPROPERTIES**, int* ascent); + virtual void resetFontIndex(); + + // Reference to WebKit::Font that contains all the information about fonts + // we can use to render this input run of text. It is used in + // NextWinFontData to retrieve Windows font data for a series of + // non-primary fonts. + // + // This pointer can be NULL for no font fallback handling. + const Font* m_font; + + // It's rare that many fonts are listed in stylesheets. + // Four would be large enough in most cases. + const static size_t kNumberOfFonts = 4; + + // These vectors are used to store Windows font data for non-primary fonts. + Vector<HFONT, kNumberOfFonts> m_hfonts; + Vector<SCRIPT_CACHE*, kNumberOfFonts> m_scriptCaches; + Vector<SCRIPT_FONTPROPERTIES*, kNumberOfFonts> m_fontProperties; + Vector<int, kNumberOfFonts> m_ascents; + + // Index of the fallback font we're currently using for NextWinFontData. + int m_fontIndex; +}; + +} // namespace WebCore + +#endif // UniscribeHelperTextRun_h diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp index 1ca3e95..d076cb6 100644 --- a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp +++ b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp @@ -63,6 +63,7 @@ void SimpleFontData::platformInit() void SimpleFontData::platformDestroy() { delete m_smallCapsFontData; + m_smallCapsFontData = 0; if (isCustomFont()) return; diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp index 8621865..db8dd3b 100644 --- a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp +++ b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp @@ -80,6 +80,7 @@ void SimpleFontData::platformDestroy() } delete m_smallCapsFontData; + m_smallCapsFontData = 0; } SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const @@ -97,25 +98,27 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con { bool result = true; - PangoCoverage* requested = pango_coverage_from_bytes((guchar*)characters, length); - PangoCoverage* available = pango_font_get_coverage(m_font.m_font, pango_language_get_default()); - pango_coverage_max(requested, available); + PangoCoverage* coverage = pango_font_get_coverage(m_font.m_font, pango_language_get_default()); for (int i = 0; i < length; i++) { - if (PANGO_COVERAGE_NONE == pango_coverage_get(requested, i)) { + if (PANGO_COVERAGE_NONE == pango_coverage_get(coverage, characters[i])) { result = false; break; } } - pango_coverage_unref(requested); - pango_coverage_unref(available); + pango_coverage_unref(coverage); return result; } void SimpleFontData::determinePitch() { + if (isCustomFont()) { + m_treatAsFixedPitch = false; + return; + } + m_treatAsFixedPitch = m_font.isFixedPitch(); } diff --git a/WebCore/platform/graphics/mac/ColorMac.h b/WebCore/platform/graphics/mac/ColorMac.h index 3be9094..830e9d9 100644 --- a/WebCore/platform/graphics/mac/ColorMac.h +++ b/WebCore/platform/graphics/mac/ColorMac.h @@ -39,6 +39,7 @@ class NSColor; namespace WebCore { + // These functions assume NSColors are in DeviceRGB colorspace Color colorFromNSColor(NSColor *); NSColor* nsColor(const Color&); diff --git a/WebCore/platform/graphics/mac/ColorMac.mm b/WebCore/platform/graphics/mac/ColorMac.mm index 96fdc39..9b0f770 100644 --- a/WebCore/platform/graphics/mac/ColorMac.mm +++ b/WebCore/platform/graphics/mac/ColorMac.mm @@ -28,6 +28,7 @@ #import "ColorMac.h" #import <wtf/Assertions.h> +#import <wtf/StdLibExtras.h> #import <wtf/RetainPtr.h> @interface WebCoreControlTintObserver : NSObject @@ -59,37 +60,30 @@ NSColor* nsColor(const Color& color) switch (c) { case 0: { // Need this to avoid returning nil because cachedRGBAValues will default to 0. - static RetainPtr<NSColor> clearColor = [NSColor clearColor]; + DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, clearColor, ([NSColor colorWithDeviceRed:0.0f green:0.0f blue:0.0f alpha:0.0f])); return clearColor.get(); } case Color::black: { - static RetainPtr<NSColor> blackColor = [NSColor blackColor]; + DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, blackColor, ([NSColor colorWithDeviceRed:0.0f green:0.0f blue:0.0f alpha:1.0f])); return blackColor.get(); } case Color::white: { - static RetainPtr<NSColor> whiteColor = [NSColor whiteColor]; + DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, whiteColor, ([NSColor colorWithDeviceRed:1.0f green:1.0f blue:1.0f alpha:1.0f])); return whiteColor.get(); } default: { const int cacheSize = 32; static unsigned cachedRGBAValues[cacheSize]; - static RetainPtr<NSColor> cachedColors[cacheSize]; + static RetainPtr<NSColor>* cachedColors = new RetainPtr<NSColor>[cacheSize]; for (int i = 0; i != cacheSize; ++i) if (cachedRGBAValues[i] == c) return cachedColors[i].get(); -#ifdef COLORMATCH_EVERYTHING - NSColor* result = [NSColor colorWithCalibratedRed:color.red() / 255.0f - green:color.green() / 255.0f - blue:color.blue() / 255.0f - alpha:color.alpha() /255.0f]; -#else NSColor* result = [NSColor colorWithDeviceRed:color.red() / 255.0f green:color.green() / 255.0f blue:color.blue() / 255.0f alpha:color.alpha() /255.0f]; -#endif static int cursor; cachedRGBAValues[cursor] = c; @@ -158,12 +152,8 @@ void setUsesTestModeFocusRingColor(bool newValue) + (void)controlTintDidChange { -#ifdef COLORMATCH_EVERYTHING -#error Not yet implemented. -#else NSColor* color = [[NSColor keyboardFocusIndicatorColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace]; WebCore::systemFocusRingColor = WebCore::makeRGBAFromNSColor(color); -#endif } @end diff --git a/WebCore/platform/graphics/mac/CoreTextController.cpp b/WebCore/platform/graphics/mac/CoreTextController.cpp index 171a7ec..49e83c4 100644 --- a/WebCore/platform/graphics/mac/CoreTextController.cpp +++ b/WebCore/platform/graphics/mac/CoreTextController.cpp @@ -369,9 +369,9 @@ void CoreTextController::collectCoreTextRunsForCharacters(const UChar* cp, unsig static const void* optionKeys[] = { kCTTypesetterOptionForcedEmbeddingLevel }; static const void* ltrOptionValues[] = { kCFBooleanFalse }; static const void* rtlOptionValues[] = { kCFBooleanTrue }; - static RetainPtr<CFDictionaryRef> ltrTypesetterOptions(AdoptCF, CFDictionaryCreate(kCFAllocatorDefault, optionKeys, ltrOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); - static RetainPtr<CFDictionaryRef> rtlTypesetterOptions(AdoptCF, CFDictionaryCreate(kCFAllocatorDefault, optionKeys, rtlOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); - typesetter.adoptCF(CTTypesetterCreateWithAttributedStringAndOptions(attributedString.get(), m_run.ltr() ? ltrTypesetterOptions.get() : rtlTypesetterOptions.get())); + static CFDictionaryRef ltrTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, ltrOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + static CFDictionaryRef rtlTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, rtlOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + typesetter.adoptCF(CTTypesetterCreateWithAttributedStringAndOptions(attributedString.get(), m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions)); } else typesetter.adoptCF(CTTypesetterCreateWithAttributedString(attributedString.get())); diff --git a/WebCore/platform/graphics/mac/FontCacheMac.mm b/WebCore/platform/graphics/mac/FontCacheMac.mm index e7cda66..26d84cc 100644 --- a/WebCore/platform/graphics/mac/FontCacheMac.mm +++ b/WebCore/platform/graphics/mac/FontCacheMac.mm @@ -35,6 +35,7 @@ #import "FontPlatformData.h" #import "WebCoreSystemInterface.h" #import "WebFontCache.h" +#include <wtf/StdLibExtras.h> #ifdef BUILDING_ON_TIGER typedef int NSInteger; @@ -44,7 +45,7 @@ namespace WebCore { static void fontCacheATSNotificationCallback(ATSFontNotificationInfoRef, void*) { - FontCache::invalidate(); + fontCache()->invalidate(); } void FontCache::platformInit() @@ -139,10 +140,10 @@ FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) const FontFamily* currFamily = &font.fontDescription().family(); while (currFamily && !platformData) { if (currFamily->family().length()) { - static String matchWords[3] = { String("Arabic"), String("Pashto"), String("Urdu") }; - static AtomicString geezaStr("Geeza Pro"); + static String* matchWords[3] = { new String("Arabic"), new String("Pashto"), new String("Urdu") }; + DEFINE_STATIC_LOCAL(AtomicString, geezaStr, ("Geeza Pro")); for (int j = 0; j < 3 && !platformData; ++j) - if (currFamily->family().contains(matchWords[j], false)) + if (currFamily->family().contains(*matchWords[j], false)) platformData = getCachedFontPlatformData(font.fontDescription(), geezaStr); } currFamily = currFamily->next(); @@ -153,8 +154,8 @@ FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription) { - static AtomicString timesStr("Times"); - static AtomicString lucidaGrandeStr("Lucida Grande"); + DEFINE_STATIC_LOCAL(AtomicString, timesStr, ("Times")); + DEFINE_STATIC_LOCAL(AtomicString, lucidaGrandeStr, ("Lucida Grande")); // 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. diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp index 1fb144c..9aa4997 100644 --- a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp @@ -68,7 +68,7 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) CGFontRef cgFontRef = CGFontCreateWithPlatformFont(&fontRef); #ifndef BUILDING_ON_TIGER // Workaround for <rdar://problem/5675504>. - if (!CGFontGetNumberOfGlyphs(cgFontRef)) { + if (cgFontRef && !CGFontGetNumberOfGlyphs(cgFontRef)) { CFRelease(cgFontRef); cgFontRef = 0; } diff --git a/WebCore/platform/graphics/mac/FontMacATSUI.mm b/WebCore/platform/graphics/mac/FontMacATSUI.mm index 9a45c5a..52493e7 100644 --- a/WebCore/platform/graphics/mac/FontMacATSUI.mm +++ b/WebCore/platform/graphics/mac/FontMacATSUI.mm @@ -154,8 +154,7 @@ static void initializeATSUStyle(const SimpleFontData* fontData) fontData->m_ATSUStyleInitialized = true; } -static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector iCurrentOperation, ATSULineRef iLineRef, URefCon iRefCon, - void *iOperationCallbackParameterPtr, ATSULayoutOperationCallbackStatus *oCallbackStatus) +static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef iLineRef, URefCon iRefCon, void*, ATSULayoutOperationCallbackStatus* oCallbackStatus) { ATSULayoutParameters* params = reinterpret_cast<ATSULayoutParameters*>(iRefCon); OSStatus status; @@ -592,7 +591,7 @@ float Font::floatWidthForComplexText(const TextRun& run) const MIN(FixedToFloat(firstGlyphBounds.upperLeft.x), FixedToFloat(firstGlyphBounds.lowerLeft.x)); } -int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const +int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool /*includePartialGlyphs*/) const { OwnArrayPtr<UChar> charactersWithOverride; TextRun adjustedRun = copyRunForDirectionalOverrideIfNecessary(run, charactersWithOverride); diff --git a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm index 15e573d..7cd9ab6 100644 --- a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm +++ b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm @@ -34,7 +34,7 @@ FontPlatformData::FontPlatformData(NSFont *f, bool b , bool o) CFRetain(f); m_size = f ? [f pointSize] : 0.0f; #ifndef BUILDING_ON_TIGER - m_cgFont = CTFontCopyGraphicsFont(toCTFontRef(f), 0); + m_cgFont.adoptCF(CTFontCopyGraphicsFont(toCTFontRef(f), 0)); m_atsuFontID = CTFontGetPlatformFont(toCTFontRef(f), 0); #else m_cgFont = wkGetCGFontFromNSFont(f); @@ -86,7 +86,7 @@ void FontPlatformData::setFont(NSFont *font) m_font = font; m_size = font ? [font pointSize] : 0.0f; #ifndef BUILDING_ON_TIGER - m_cgFont = CTFontCopyGraphicsFont(toCTFontRef(font), 0); + m_cgFont.adoptCF(CTFontCopyGraphicsFont(toCTFontRef(font), 0)); m_atsuFontID = CTFontGetPlatformFont(toCTFontRef(font), 0); #else m_cgFont = wkGetCGFontFromNSFont(font); diff --git a/WebCore/platform/graphics/mac/GraphicsContextMac.mm b/WebCore/platform/graphics/mac/GraphicsContextMac.mm index 3f9176c..ae829e2 100644 --- a/WebCore/platform/graphics/mac/GraphicsContextMac.mm +++ b/WebCore/platform/graphics/mac/GraphicsContextMac.mm @@ -27,6 +27,7 @@ #import "GraphicsContext.h" #import "../cg/GraphicsContextPlatformPrivateCG.h" +#import <wtf/StdLibExtras.h> #import "WebCoreSystemInterface.h" @@ -80,53 +81,42 @@ void GraphicsContext::setCompositeOperation(CompositeOperator op) [pool drain]; } #endif - + +static NSColor* createPatternColor(NSString* name, NSColor* defaultColor, bool& usingDot) +{ + NSImage *image = [NSImage imageNamed:name]; + ASSERT(image); // if image is not available, we want to know + NSColor *color = (image ? [NSColor colorWithPatternImage:image] : nil); + if (color) + usingDot = true; + else + color = defaultColor; + return color; +} + void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& point, int width, bool grammar) { if (paintingDisabled()) return; - // Constants for spelling pattern color - static RetainPtr<NSColor> spellingPatternColor = nil; - static bool usingDotForSpelling = false; - - // Constants for grammar pattern color - static RetainPtr<NSColor> grammarPatternColor = nil; - static bool usingDotForGrammar = false; - // These are the same for misspelling or bad grammar int patternHeight = cMisspellingLineThickness; int patternWidth = cMisspellingLinePatternWidth; - // Initialize pattern color if needed - if (!grammar && !spellingPatternColor) { - NSImage *image = [NSImage imageNamed:@"SpellingDot"]; - ASSERT(image); // if image is not available, we want to know - NSColor *color = (image ? [NSColor colorWithPatternImage:image] : nil); - if (color) - usingDotForSpelling = true; - else - color = [NSColor redColor]; - spellingPatternColor = color; - } - - if (grammar && !grammarPatternColor) { - NSImage *image = [NSImage imageNamed:@"GrammarDot"]; - ASSERT(image); // if image is not available, we want to know - NSColor *color = (image ? [NSColor colorWithPatternImage:image] : nil); - if (color) - usingDotForGrammar = true; - else - color = [NSColor greenColor]; - grammarPatternColor = color; - } - bool usingDot; NSColor *patternColor; if (grammar) { + // Constants for grammar pattern color + static bool usingDotForGrammar = false; + DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, grammarPatternColor, (createPatternColor(@"GrammarDot", [NSColor greenColor], usingDotForGrammar))); + usingDot = usingDotForGrammar; patternColor = grammarPatternColor.get(); } else { + // Constants for spelling pattern color + static bool usingDotForSpelling = false; + DEFINE_STATIC_LOCAL(RetainPtr<NSColor>, spellingPatternColor, (createPatternColor(@"SpellingDot", [NSColor redColor], usingDotForSpelling))); + usingDot = usingDotForSpelling; patternColor = spellingPatternColor.get(); } diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm index 0ec56d6..a33c8d2 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm @@ -29,14 +29,19 @@ #import "MediaPlayerPrivateQTKit.h" +#ifdef BUILDING_ON_TIGER +#import "AutodrainedPool.h" +#endif + #import "BlockExceptions.h" +#import "FrameView.h" #import "GraphicsContext.h" #import "KURL.h" -#import "FrameView.h" #import "SoftLinking.h" #import "WebCoreSystemInterface.h" #import <QTKit/QTKit.h> #import <objc/objc-runtime.h> +#import <wtf/UnusedParam.h> #if DRAW_FRAME_RATE #import "Font.h" @@ -239,7 +244,7 @@ void MediaPlayerPrivate::createQTMovie(const String& url) object:m_qtMovie.get()]; } -static void mainThreadSetNeedsDisplay(id self, SEL _cmd) +static void mainThreadSetNeedsDisplay(id self, SEL) { id movieView = [self superview]; ASSERT(!movieView || [movieView isKindOfClass:[QTMovieView class]]); @@ -772,6 +777,10 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r) context->scale(FloatSize(1.0f, -1.0f)); context->setImageInterpolationQuality(InterpolationLow); IntRect paintRect(IntPoint(0, 0), IntSize(r.width(), r.height())); + +#ifdef BUILDING_ON_TIGER + AutodrainedPool pool; +#endif NSGraphicsContext* newContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context->platformContext() flipped:NO]; // draw the current video frame @@ -969,48 +978,54 @@ void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount) m_callback->repaint(); } -- (void)loadStateChanged:(NSNotification *)notification +- (void)loadStateChanged:(NSNotification *)unusedNotification { + UNUSED_PARAM(unusedNotification); if (m_delayCallbacks) [self performSelector:_cmd withObject:nil afterDelay:0]; else m_callback->loadStateChanged(); } -- (void)rateChanged:(NSNotification *)notification +- (void)rateChanged:(NSNotification *)unusedNotification { + UNUSED_PARAM(unusedNotification); if (m_delayCallbacks) [self performSelector:_cmd withObject:nil afterDelay:0]; else m_callback->rateChanged(); } -- (void)sizeChanged:(NSNotification *)notification +- (void)sizeChanged:(NSNotification *)unusedNotification { + UNUSED_PARAM(unusedNotification); if (m_delayCallbacks) [self performSelector:_cmd withObject:nil afterDelay:0]; else m_callback->sizeChanged(); } -- (void)timeChanged:(NSNotification *)notification +- (void)timeChanged:(NSNotification *)unusedNotification { + UNUSED_PARAM(unusedNotification); if (m_delayCallbacks) [self performSelector:_cmd withObject:nil afterDelay:0]; else m_callback->timeChanged(); } -- (void)didEnd:(NSNotification *)notification +- (void)didEnd:(NSNotification *)unusedNotification { + UNUSED_PARAM(unusedNotification); if (m_delayCallbacks) [self performSelector:_cmd withObject:nil afterDelay:0]; else m_callback->didEnd(); } -- (void)newImageAvailable:(NSNotification *)notification +- (void)newImageAvailable:(NSNotification *)unusedNotification { + UNUSED_PARAM(unusedNotification); [self repaint]; } diff --git a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm index 4ee5933..30dbf97 100644 --- a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm +++ b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm @@ -42,6 +42,7 @@ #import <float.h> #import <unicode/uchar.h> #import <wtf/Assertions.h> +#import <wtf/StdLibExtras.h> #import <wtf/RetainPtr.h> @interface NSFont (WebAppKitSecretAPI) @@ -54,7 +55,7 @@ const float smallCapsFontSizeMultiplier = 0.7f; const float contextDPI = 72.0f; static inline float scaleEmToUnits(float x, unsigned unitsPerEm) { return x * (contextDPI / (contextDPI * unitsPerEm)); } -bool initFontData(SimpleFontData* fontData) +static bool initFontData(SimpleFontData* fontData) { if (!fontData->m_font.cgFont()) return false; @@ -92,9 +93,7 @@ bool initFontData(SimpleFontData* fontData) static NSString *webFallbackFontFamily(void) { - static RetainPtr<NSString> webFallbackFontFamily = nil; - if (!webFallbackFontFamily) - webFallbackFontFamily = [[NSFont systemFontOfSize:16.0f] familyName]; + DEFINE_STATIC_LOCAL(RetainPtr<NSString>, webFallbackFontFamily, ([[NSFont systemFontOfSize:16.0f] familyName])); return webFallbackFontFamily.get(); } @@ -315,7 +314,7 @@ SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDes smallCapsFont.m_syntheticBold = (fontTraits & NSBoldFontMask) && !(smallCapsFontTraits & NSBoldFontMask); smallCapsFont.m_syntheticOblique = (fontTraits & NSItalicFontMask) && !(smallCapsFontTraits & NSItalicFontMask); - m_smallCapsFontData = FontCache::getCachedFontData(&smallCapsFont); + m_smallCapsFontData = fontCache()->getCachedFontData(&smallCapsFont); } END_BLOCK_OBJC_EXCEPTIONS; } @@ -325,7 +324,7 @@ SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDes bool SimpleFontData::containsCharacters(const UChar* characters, int length) const { - NSString *string = [[NSString alloc] initWithCharactersNoCopy:(UniChar*)characters length:length freeWhenDone:NO]; + NSString *string = [[NSString alloc] initWithCharactersNoCopy:const_cast<unichar*>(characters) length:length freeWhenDone:NO]; NSCharacterSet *set = [[m_font.font() coveredCharacterSet] invertedSet]; bool result = set && [string rangeOfCharacterFromSet:set].location == NSNotFound; [string release]; diff --git a/WebCore/platform/graphics/qt/FontCacheQt.cpp b/WebCore/platform/graphics/qt/FontCacheQt.cpp index be31d96..114f073 100644 --- a/WebCore/platform/graphics/qt/FontCacheQt.cpp +++ b/WebCore/platform/graphics/qt/FontCacheQt.cpp @@ -1,5 +1,6 @@ /* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2008 Holger Hans Peter Freyther This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -21,18 +22,31 @@ */ #include "config.h" #include "FontCache.h" + #include "FontDescription.h" +#include "FontPlatformData.h" #include "Font.h" +#include <wtf/StdLibExtras.h> namespace WebCore { +FontCache* fontCache() +{ + DEFINE_STATIC_LOCAL(FontCache, globalFontCache, ()); + return &globalFontCache; +} + +FontCache::FontCache() +{ +} + void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks) { } -FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription&, const AtomicString& family, bool checkingAlternateName) +FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& description, const AtomicString& family, bool checkingAlternateName) { - return 0; + return new FontPlatformData(description); } SimpleFontData* FontCache::getCachedFontData(const FontPlatformData*) @@ -45,6 +59,10 @@ FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription&) return 0; } +void FontCache::releaseFontData(const WebCore::SimpleFontData*) +{ +} + void FontCache::addClient(FontSelector*) { } diff --git a/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp b/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp index 8fc3ea0..a19464e 100644 --- a/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/qt/FontCustomPlatformData.cpp @@ -25,19 +25,25 @@ #include "FontPlatformData.h" #include "SharedBuffer.h" #include <QFontDatabase> +#include <QStringList> namespace WebCore { FontCustomPlatformData::~FontCustomPlatformData() { - QFontDatabase::removeApplicationFont(handle); + QFontDatabase::removeApplicationFont(m_handle); } FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode) { - FontPlatformData result; - result.handle = handle; - return result; + QFont font; + font.setFamily(QFontDatabase::applicationFontFamilies(m_handle)[0]); + font.setPixelSize(size); + if (bold) + font.setWeight(QFont::Bold); + font.setItalic(italic); + + return FontPlatformData(font, bold); } FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) @@ -47,8 +53,11 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) int id = QFontDatabase::addApplicationFontFromData(QByteArray(buffer->data(), buffer->size())); if (id == -1) return 0; + + Q_ASSERT(QFontDatabase::applicationFontFamilies(id).size() > 0); + FontCustomPlatformData *data = new FontCustomPlatformData; - data->handle = id; + data->m_handle = id; return data; } diff --git a/WebCore/platform/graphics/qt/FontCustomPlatformData.h b/WebCore/platform/graphics/qt/FontCustomPlatformData.h index da5159d..4305b87 100644 --- a/WebCore/platform/graphics/qt/FontCustomPlatformData.h +++ b/WebCore/platform/graphics/qt/FontCustomPlatformData.h @@ -33,7 +33,8 @@ class FontPlatformData; struct FontCustomPlatformData : Noncopyable { ~FontCustomPlatformData(); - int handle; // for use with QFontDatabase::addApplicationFont/removeApplicationFont + // for use with QFontDatabase::addApplicationFont/removeApplicationFont + int m_handle; FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode); }; diff --git a/WebCore/platform/graphics/qt/FontFallbackListQt.cpp b/WebCore/platform/graphics/qt/FontFallbackListQt.cpp new file mode 100644 index 0000000..22ae205 --- /dev/null +++ b/WebCore/platform/graphics/qt/FontFallbackListQt.cpp @@ -0,0 +1,106 @@ +/* + Copyright (C) 2008 Holger Hans Peter Freyther + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + Replacement of the stock FontFallbackList as Qt is going to find us a + replacement font, will do caching and the other stuff we implement in + WebKit. +*/ + +#include "config.h" +#include "FontFallbackList.h" + +#include "Font.h" +#include "SegmentedFontData.h" + +#include <QDebug> + +namespace WebCore { + +FontFallbackList::FontFallbackList() + : m_familyIndex(0) + , m_pitch(UnknownPitch) + , m_loadingCustomFonts(false) + , m_fontSelector(0) + , m_generation(0) +{ +} + +void FontFallbackList::invalidate(WTF::PassRefPtr<WebCore::FontSelector> fontSelector) +{ + releaseFontData(); + m_fontList.clear(); + m_familyIndex = 0; + m_pitch = UnknownPitch; + m_loadingCustomFonts = false; + m_fontSelector = fontSelector; + m_generation = 0; +} + +void FontFallbackList::releaseFontData() +{ +} + +void FontFallbackList::determinePitch(const WebCore::Font* font) const +{ + const FontData* fontData = primaryFont(font); + if (!fontData->isSegmented()) + m_pitch = static_cast<const SimpleFontData*>(fontData)->pitch(); + else { + const SegmentedFontData* segmentedFontData = static_cast<const SegmentedFontData*>(fontData); + unsigned numRanges = segmentedFontData->numRanges(); + if (numRanges == 1) + m_pitch = segmentedFontData->rangeAt(0).fontData()->pitch(); + else + m_pitch = VariablePitch; + } +} + +const FontData* FontFallbackList::fontDataAt(const WebCore::Font* _font, unsigned index) const +{ + if (index != 0) + return 0; + + // Use the FontSelector to get a WebCore font and then fallback to Qt + const FontDescription& description = _font->fontDescription(); + const FontFamily* family = &description.family(); + while (family) { + if (m_fontSelector) { + FontData* data = m_fontSelector->getFontData(description, family->family()); + if (data) { + if (data->isLoading()) + m_loadingCustomFonts = true; + return data; + } + } + family = family->next(); + } + + return new SimpleFontData(FontPlatformData(description), _font->wordSpacing(), _font->letterSpacing()); +} + +const FontData* FontFallbackList::fontDataForCharacters(const WebCore::Font* font, const UChar*, int) const +{ + return primaryFont(font); +} + +void FontFallbackList::setPlatformFont(const WebCore::FontPlatformData& platformData) +{ + m_familyIndex = cAllFamiliesScanned; +} + +} diff --git a/WebCore/platform/graphics/qt/FontPlatformData.h b/WebCore/platform/graphics/qt/FontPlatformData.h index e4363be..5e97678 100644 --- a/WebCore/platform/graphics/qt/FontPlatformData.h +++ b/WebCore/platform/graphics/qt/FontPlatformData.h @@ -1,5 +1,6 @@ /* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2008 Holger Hans Peter Freyther This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -22,14 +23,29 @@ #ifndef FontPlatformData_h #define FontPlatformData_h +#include "FontDescription.h" + +#include <QFont> + namespace WebCore { class FontPlatformData { public: - // this is only used for custom loaded fonts and represents the id handle passed to - // QFontDatabase::addApplicationFont/removeApplicationFont - int handle; +#if ENABLE(SVG_FONTS) + FontPlatformData(float size, bool bold, bool oblique); +#endif + FontPlatformData(); + FontPlatformData(const FontDescription&, int wordSpacing = 0, int letterSpacing = 0); + FontPlatformData(const QFont&, bool bold); + + QFont font() const { return m_font; } + float size() const { return m_size; } + + float m_size; + bool m_bold; + bool m_oblique; + QFont m_font; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp new file mode 100644 index 0000000..ea51fe8 --- /dev/null +++ b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp @@ -0,0 +1,78 @@ +/* + Copyright (C) 2008 Holger Hans Peter Freyther + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "config.h" +#include "FontPlatformData.h" + +namespace WebCore { + +FontPlatformData::FontPlatformData(const FontDescription& description, int wordSpacing, int letterSpacing) + : m_size(0.0f) + , m_bold(false) + , m_oblique(false) +{ + QString familyName; + const FontFamily* family = &description.family(); + while (family) { + familyName += family->family(); + family = family->next(); + if (family) + familyName += QLatin1Char(','); + } + + m_font.setFamily(familyName); + m_font.setPixelSize(qRound(description.computedSize())); + m_font.setItalic(description.italic()); + // FIXME: Map all FontWeight values to QFont weights. + if (description.weight() >= FontWeight600) + m_font.setWeight(QFont::Bold); + else + m_font.setWeight(QFont::Normal); + + bool smallCaps = description.smallCaps(); + m_font.setCapitalization(smallCaps ? QFont::SmallCaps : QFont::MixedCase); + m_font.setWordSpacing(wordSpacing); + m_font.setLetterSpacing(QFont::AbsoluteSpacing, letterSpacing); + m_size = m_font.pointSize(); +} + +FontPlatformData::FontPlatformData(const QFont& font, bool bold) + : m_size(font.pointSize()) + , m_bold(bold) + , m_oblique(false) + , m_font(font) +{ +} + +FontPlatformData::FontPlatformData(float size, bool bold, bool oblique) + : m_size(size) + , m_bold(bold) + , m_oblique(oblique) +{ +} + +FontPlatformData::FontPlatformData() + : m_size(0.0f) + , m_bold(false) + , m_oblique(false) +{ +} + +} diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp index e2ef605..deeea99 100644 --- a/WebCore/platform/graphics/qt/FontQt.cpp +++ b/WebCore/platform/graphics/qt/FontQt.cpp @@ -1,5 +1,6 @@ /* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2008 Holger Hans Peter Freyther This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -20,6 +21,7 @@ #include "config.h" #include "Font.h" #include "FontDescription.h" +#include "FontFallbackList.h" #include "FontSelector.h" #include "GraphicsContext.h" @@ -31,66 +33,9 @@ #include <qdebug.h> #include <limits.h> -namespace WebCore { #if QT_VERSION >= 0x040400 - -Font::Font() - : m_letterSpacing(0) - , m_wordSpacing(0) - , m_font() - , m_scFont() -{ - QFontMetrics metrics(m_font); - m_spaceWidth = metrics.width(QLatin1Char(' ')); -} - -Font::Font(const FontDescription& description, short letterSpacing, short wordSpacing) - : m_fontDescription(description) - , m_letterSpacing(letterSpacing) - , m_wordSpacing(wordSpacing) -{ - const FontFamily* family = &description.family(); - QString familyName; - while (family) { - familyName += family->family(); - family = family->next(); - if (family) - familyName += QLatin1Char(','); - } - - m_font.setFamily(familyName); - m_font.setPixelSize(qRound(description.computedSize())); - m_font.setItalic(description.italic()); - // FIXME: Map all FontWeight values to QFont weights. - if (description.weight() >= FontWeight600) - m_font.setWeight(QFont::Bold); - else - m_font.setWeight(QFont::Normal); - - bool smallCaps = description.smallCaps(); - m_font.setCapitalization(smallCaps ? QFont::SmallCaps : QFont::MixedCase); - - QFontMetrics metrics = QFontMetrics(m_font); - m_spaceWidth = metrics.width(QLatin1Char(' ')); - - if (wordSpacing) - m_font.setWordSpacing(wordSpacing); - if (letterSpacing) - m_font.setLetterSpacing(QFont::AbsoluteSpacing, letterSpacing); -} - -void Font::setWordSpacing(short s) -{ - m_font.setWordSpacing(s); - m_wordSpacing = s; -} -void Font::setLetterSpacing(short s) -{ - m_font.setLetterSpacing(QFont::AbsoluteSpacing, s); - m_letterSpacing = s; -} - +namespace WebCore { static QString qstring(const TextRun& run) { @@ -121,10 +66,11 @@ static QTextLine setupLayout(QTextLayout* layout, const TextRun& style) return line; } -void Font::drawText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const +void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const { if (to < 0) to = run.length(); + QPainter *p = ctx->platformContext(); Color color = ctx->fillColor(); p->setPen(QColor(color)); @@ -138,14 +84,14 @@ void Font::drawText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& bool hasShadow = ctx->textDrawingMode() == cTextFill && ctx->getShadow(shadowSize, shadowBlur, shadowColor); if (from > 0 || to < run.length()) { - QTextLayout layout(string, m_font); + QTextLayout layout(string, font()); QTextLine line = setupLayout(&layout, run); float x1 = line.cursorToX(from); float x2 = line.cursorToX(to); if (x2 < x1) qSwap(x1, x2); - QFontMetrics fm(m_font); + QFontMetrics fm(font()); int ascent = fm.ascent(); QRectF clip(point.x() + x1, point.y() - ascent, x2 - x1, fm.height()); @@ -179,7 +125,7 @@ void Font::drawText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& return; } - p->setFont(m_font); + p->setFont(font()); QPointF pt(point.x(), point.y()); int flags = run.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight; @@ -194,12 +140,12 @@ void Font::drawText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& p->drawText(pt, string, flags, run.padding()); } -int Font::width(const TextRun& run) const +float Font::floatWidthForComplexText(const TextRun& run) const { if (!run.length()) return 0; QString string = qstring(run); - QTextLayout layout(string, m_font); + QTextLayout layout(string, font()); QTextLine line = setupLayout(&layout, run); int w = int(line.naturalTextWidth()); // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does) @@ -209,30 +155,18 @@ int Font::width(const TextRun& run) const return w + run.padding(); } -float Font::floatWidth(const TextRun& run) const -{ - return width(run); -} - -float Font::floatWidth(const TextRun& run, int /*extraCharsAvailable*/, int& charsConsumed, String& glyphName) const -{ - charsConsumed = run.length(); - glyphName = ""; - return width(run); -} - -int Font::offsetForPosition(const TextRun& run, int position, bool /*includePartialGlyphs*/) const +int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool includePartialGlyphs) const { QString string = qstring(run); - QTextLayout layout(string, m_font); + QTextLayout layout(string, font()); QTextLine line = setupLayout(&layout, run); return line.xToCursor(position); } -FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& pt, int h, int from, int to) const +FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& pt, int h, int from, int to) const { QString string = qstring(run); - QTextLayout layout(string, m_font); + QTextLayout layout(string, font()); QTextLine line = setupLayout(&layout, run); float x1 = line.cursorToX(from); @@ -243,464 +177,12 @@ FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& pt, int return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h); } -#else - - -struct TextRunComponent { - TextRunComponent() : font(0) {} - TextRunComponent(const UChar *start, int length, bool rtl, const QFont *font, int offset, bool sc = false); - TextRunComponent(int spaces, bool rtl, const QFont *font, int offset); - - inline bool isSpace() const { return spaces != 0; } - - QString string; - const QFont *font; - int width; - int offset; - int spaces; -}; - -TextRunComponent::TextRunComponent(const UChar *start, int length, bool rtl, const QFont *f, int o, bool sc) - : string(reinterpret_cast<const QChar*>(start), length) - , font(f) - , offset(o) - , spaces(0) -{ - if (sc) - string = string.toUpper(); - string.prepend(rtl ? QChar(0x202e) : QChar(0x202d)); - width = QFontMetrics(*font).width(string); -} - -TextRunComponent::TextRunComponent(int s, bool rtl, const QFont *f, int o) - : string(s, QLatin1Char(' ')) - , font(f) - , offset(o) - , spaces(s) -{ - string.prepend(rtl ? QChar(0x202e) : QChar(0x202d)); - width = spaces * QFontMetrics(*font).width(QLatin1Char(' ')); -} - - -Font::Font() - : m_letterSpacing(0) - , m_wordSpacing(0) - , m_font() - , m_scFont() -{ - QFontMetrics metrics(m_font); - m_spaceWidth = metrics.width(QLatin1Char(' ')); - qreal pointsize = m_font.pointSizeF(); - if (pointsize > 0) - m_scFont.setPointSizeF(pointsize*0.7); - else - m_scFont.setPixelSize(qRound(m_font.pixelSize()*.7)); -} - -Font::Font(const FontDescription& description, short letterSpacing, short wordSpacing) - : m_fontDescription(description) - , m_letterSpacing(letterSpacing) - , m_wordSpacing(wordSpacing) -{ - const FontFamily* family = &description.family(); - QString familyName; - while (family) { - familyName += family->family(); - family = family->next(); - if (family) - familyName += QLatin1Char(','); - } - - m_font.setFamily(familyName); - m_font.setPixelSize(qRound(description.computedSize())); - m_font.setItalic(description.italic()); - // FIXME: Map all FontWeight values to QFont weights. - if (description.weight() >= FontWeight600) - m_font.setWeight(QFont::Bold); - else - m_font.setWeight(QFont::Normal); - - QFontMetrics metrics = QFontMetrics(m_font); - m_spaceWidth = metrics.width(QLatin1Char(' ')); - m_scFont = m_font; - m_scFont.setPixelSize(qRound(description.computedSize()*.7)); -} - -void Font::setWordSpacing(short s) -{ - m_wordSpacing = s; -} -void Font::setLetterSpacing(short s) -{ - m_letterSpacing = s; -} - -static int generateComponents(Vector<TextRunComponent, 1024>* components, const Font &font, const TextRun &run) -{ -// qDebug() << "generateComponents" << QString((const QChar *)run.characters(), run.length()); - int letterSpacing = font.letterSpacing(); - int wordSpacing = font.wordSpacing(); - bool smallCaps = font.fontDescription().smallCaps(); - int padding = run.padding(); - int numSpaces = 0; - if (padding) { - for (int i = 0; i < run.length(); i++) - if (Font::treatAsSpace(run[i])) - ++numSpaces; - } - - int offset = 0; - const QFont *f = &font.font(); - if (letterSpacing || smallCaps) { - // need to draw every letter on it's own - int start = 0; - if (Font::treatAsSpace(run[0])) { - int add = 0; - if (numSpaces) { - add = padding/numSpaces; - padding -= add; - --numSpaces; - } - components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); - offset += add + letterSpacing + components->last().width; - start = 1; -// qDebug() << "space at 0" << offset; - } else if (smallCaps) { - f = (QChar::category(run[0]) == QChar::Letter_Lowercase ? &font.scFont() : &font.font()); - } - for (int i = 1; i < run.length(); ++i) { - uint ch = run[i]; - if (QChar(ch).isHighSurrogate() && QChar(run[i-1]).isLowSurrogate()) - ch = QChar::surrogateToUcs4(ch, run[i-1]); - if (QChar(ch).isLowSurrogate() || QChar::category(ch) == QChar::Mark_NonSpacing) - continue; - if (Font::treatAsSpace(run[i])) { - int add = 0; -// qDebug() << " treatAsSpace:" << i << start; - if (i - start > 0) { - components->append(TextRunComponent(run.characters() + start, i - start, - run.rtl(), - f, offset, f == &font.scFont())); - offset += components->last().width + letterSpacing; -// qDebug() << " appending(1) " << components->last().string << components->last().width; - } - if (numSpaces) { - add = padding/numSpaces; - padding -= add; - --numSpaces; - } - components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); - offset += wordSpacing + add + components->last().width + letterSpacing; - start = i + 1; - continue; - } else if (!letterSpacing) { -// qDebug() << i << char(run[i]) << (QChar::category(ch) == QChar::Letter_Lowercase) << -// QFontInfo(*f).pointSizeF(); - if (QChar::category(ch) == QChar::Letter_Lowercase) { - if (f == &font.scFont()) - continue; - } else { - if (f == &font.font()) - continue; - } - } - if (i - start > 0) { - components->append(TextRunComponent(run.characters() + start, i - start, - run.rtl(), - f, offset, f == &font.scFont())); - offset += components->last().width + letterSpacing; -// qDebug() << " appending(2) " << components->last().string << components->last().width; - } - if (smallCaps) - f = (QChar::category(ch) == QChar::Letter_Lowercase ? &font.scFont() : &font.font()); - start = i; - } - if (run.length() - start > 0) { - components->append(TextRunComponent(run.characters() + start, run.length() - start, - run.rtl(), - f, offset, f == &font.scFont())); - offset += components->last().width; -// qDebug() << " appending(3) " << components->last().string << components->last().width; - } - offset += letterSpacing; - } else { - int start = 0; - for (int i = 0; i < run.length(); ++i) { - if (Font::treatAsSpace(run[i])) { - if (i - start > 0) { - components->append(TextRunComponent(run.characters() + start, i - start, - run.rtl(), - f, offset)); - offset += components->last().width; - } - int add = 0; - if (numSpaces) { - add = padding/numSpaces; - padding -= add; - --numSpaces; - } - components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); - offset += add + components->last().width; - if (i) - offset += wordSpacing; - start = i + 1; - } - } - if (run.length() - start > 0) { - components->append(TextRunComponent(run.characters() + start, run.length() - start, - run.rtl(), - f, offset)); - offset += components->last().width; - } - } - return offset; -} - -void Font::drawText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const -{ - if (to < 0) - to = run.length(); - QPainter *p = ctx->platformContext(); - Color color = ctx->fillColor(); - p->setPen(QColor(color)); - - Vector<TextRunComponent, 1024> components; - int w = generateComponents(&components, *this, run); - - if (from > 0 || to < run.length()) { - FloatRect clip = selectionRectForText(run, - IntPoint(qRound(point.x()), qRound(point.y())), - QFontMetrics(m_font).height(), from, to); - QRectF rect(clip.x(), clip.y() - ascent(), clip.width(), clip.height()); - p->save(); - p->setClipRect(rect.toRect()); - } - - if (run.rtl()) { - for (int i = 0; i < components.size(); ++i) { - if (!components.at(i).isSpace()) { - p->setFont(*components.at(i).font); - QPointF pt(point.x() + w - components.at(i).offset - components.at(i).width, point.y()); - p->drawText(pt, components.at(i).string); - } - } - } else { - for (int i = 0; i < components.size(); ++i) { - if (!components.at(i).isSpace()) { - p->setFont(*components.at(i).font); - QPointF pt(point.x() + components.at(i).offset, point.y()); - p->drawText(pt, components.at(i).string); - } - } - } - if (from > 0 || to < run.length()) - p->restore(); -} - -int Font::width(const TextRun& run) const -{ - Vector<TextRunComponent, 1024> components; - int w = generateComponents(&components, *this, run); - -// qDebug() << " width=" << w; - return w; -} - -float Font::floatWidth(const TextRun& run) const -{ - return width(run); -} - -float Font::floatWidth(const TextRun& run, int /*extraCharsAvailable*/, int& charsConsumed, String& glyphName) const +QFont Font::font() const { - charsConsumed = run.length(); - glyphName = ""; - return width(run); + return primaryFont()->getQtFont(); } -int Font::offsetForPosition(const TextRun& run, int position, bool includePartialGlyphs) const -{ - Vector<TextRunComponent, 1024> components; - int w = generateComponents(&components, *this, run); - - int offset = 0; - if (run.rtl()) { - for (int i = 0; i < components.size(); ++i) { - int xe = w - components.at(i).offset; - int xs = xe - components.at(i).width; - if (position >= xs) { - QTextLayout layout(components.at(i).string, *components.at(i).font); - layout.beginLayout(); - QTextLine l = layout.createLine(); - if (!l.isValid()) - return offset; - - l.setLineWidth(INT_MAX/256); - layout.endLayout(); - - if (position - xs >= l.width()) - return offset; - int cursor = l.xToCursor(position - xs); - if (cursor > 1) - --cursor; - return offset + cursor; - } else { - offset += components.at(i).string.length() - 1; - } - } - } else { - for (int i = 0; i < components.size(); ++i) { - int xs = components.at(i).offset; - int xe = xs + components.at(i).width; - if (position <= xe) { - QTextLayout layout(components.at(i).string, *components.at(i).font); - layout.beginLayout(); - QTextLine l = layout.createLine(); - if (!l.isValid()) - return offset; - - l.setLineWidth(INT_MAX/256); - layout.endLayout(); - - if (position - xs >= l.width()) - return offset + components.at(i).string.length() - 1; - int cursor = l.xToCursor(position - xs); - if (cursor > 1) - --cursor; - return offset + cursor; - } else { - offset += components.at(i).string.length() - 1; - } - } - } - return run.length(); } -static float cursorToX(const Vector<TextRunComponent, 1024>& components, int width, bool rtl, int cursor) -{ - int start = 0; - for (int i = 0; i < components.size(); ++i) { - if (start + components.at(i).string.length() - 1 < cursor) { - start += components.at(i).string.length() - 1; - continue; - } - int xs = components.at(i).offset; - if (rtl) - xs = width - xs - components.at(i).width; - QTextLayout layout(components.at(i).string, *components.at(i).font); - layout.beginLayout(); - QTextLine l = layout.createLine(); - if (!l.isValid()) - return 0; - - l.setLineWidth(INT_MAX/256); - layout.endLayout(); - - return xs + l.cursorToX(cursor - start + 1); - } - return width; -} - -FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& pt, - int h, int from, int to) const -{ - Vector<TextRunComponent, 1024> components; - int w = generateComponents(&components, *this, run); - - if (from == 0 && to == run.length()) - return FloatRect(pt.x(), pt.y(), w, h); - - float x1 = cursorToX(components, w, run.rtl(), from); - float x2 = cursorToX(components, w, run.rtl(), to); - if (x2 < x1) - qSwap(x1, x2); - - return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h); -} #endif - -Font::~Font() -{ -} - -Font::Font(const Font& other) - : m_fontDescription(other.m_fontDescription) - , m_letterSpacing(other.m_letterSpacing) - , m_wordSpacing(other.m_wordSpacing) - , m_font(other.m_font) - , m_scFont(other.m_scFont) - , m_spaceWidth(other.m_spaceWidth) -{ -} - -Font& Font::operator=(const Font& other) -{ - m_fontDescription = other.m_fontDescription; - m_letterSpacing = other.m_letterSpacing; - m_wordSpacing = other.m_wordSpacing; - m_font = other.m_font; - m_scFont = other.m_scFont; - m_spaceWidth = other.m_spaceWidth; - return *this; -} - -bool Font::operator==(const Font& other) const -{ - return m_fontDescription == other.m_fontDescription - && m_letterSpacing == other.m_letterSpacing - && m_wordSpacing == other.m_wordSpacing - && m_font == other.m_font - && m_scFont == other.m_scFont - && m_spaceWidth == other.m_spaceWidth; -} - -void Font::update(PassRefPtr<FontSelector>) const -{ - // don't think we need this -} - - -bool Font::isFixedPitch() const -{ - return QFontInfo(m_font).fixedPitch(); -} - -// Metrics that we query the FontFallbackList for. -int Font::ascent() const -{ - return QFontMetrics(m_font).ascent(); -} - -int Font::descent() const -{ - return QFontMetrics(m_font).descent(); -} - -int Font::lineSpacing() const -{ - return QFontMetrics(m_font).lineSpacing(); -} - -int Font::lineGap() const -{ - return QFontMetrics(m_font).leading(); -} - -float Font::xHeight() const -{ - return QFontMetrics(m_font).xHeight(); -} - -unsigned Font::unitsPerEm() const -{ - return 1; // FIXME! -} - -int Font::spaceWidth() const -{ - return m_spaceWidth; -} - -} diff --git a/WebCore/platform/graphics/qt/FontQt43.cpp b/WebCore/platform/graphics/qt/FontQt43.cpp new file mode 100644 index 0000000..137b7c9 --- /dev/null +++ b/WebCore/platform/graphics/qt/FontQt43.cpp @@ -0,0 +1,356 @@ +/* + Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2008 Holger Hans Peter Freyther + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "Font.h" +#include "FontDescription.h" +#include "FontFallbackList.h" +#include "FontSelector.h" + +#include "GraphicsContext.h" +#include <QTextLayout> +#include <QPainter> +#include <QFontMetrics> +#include <QFontInfo> +#include <qalgorithms.h> +#include <qdebug.h> + +#include <limits.h> + +#if QT_VERSION < 0x040400 + +namespace WebCore { + +struct TextRunComponent { + TextRunComponent() : font(0) {} + TextRunComponent(const UChar *start, int length, bool rtl, const QFont *font, int offset, bool sc = false); + TextRunComponent(int spaces, bool rtl, const QFont *font, int offset); + + inline bool isSpace() const { return spaces != 0; } + + QString string; + const QFont *font; + int width; + int offset; + int spaces; +}; + +TextRunComponent::TextRunComponent(const UChar *start, int length, bool rtl, const QFont *f, int o, bool sc) + : string(reinterpret_cast<const QChar*>(start), length) + , font(f) + , offset(o) + , spaces(0) +{ + if (sc) + string = string.toUpper(); + string.prepend(rtl ? QChar(0x202e) : QChar(0x202d)); + width = QFontMetrics(*font).width(string); +} + +TextRunComponent::TextRunComponent(int s, bool rtl, const QFont *f, int o) + : string(s, QLatin1Char(' ')) + , font(f) + , offset(o) + , spaces(s) +{ + string.prepend(rtl ? QChar(0x202e) : QChar(0x202d)); + width = spaces * QFontMetrics(*font).width(QLatin1Char(' ')); +} + + +static int generateComponents(Vector<TextRunComponent, 1024>* components, const Font &font, const TextRun &run) +{ +// qDebug() << "generateComponents" << QString((const QChar *)run.characters(), run.length()); + int letterSpacing = font.letterSpacing(); + int wordSpacing = font.wordSpacing(); + bool smallCaps = font.fontDescription().smallCaps(); + int padding = run.padding(); + int numSpaces = 0; + if (padding) { + for (int i = 0; i < run.length(); i++) + if (Font::treatAsSpace(run[i])) + ++numSpaces; + } + + int offset = 0; + const QFont *f = &font.font(); + if (letterSpacing || smallCaps) { + // need to draw every letter on it's own + int start = 0; + if (Font::treatAsSpace(run[0])) { + int add = 0; + if (numSpaces) { + add = padding/numSpaces; + padding -= add; + --numSpaces; + } + components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); + offset += add + letterSpacing + components->last().width; + start = 1; +// qDebug() << "space at 0" << offset; + } else if (smallCaps) { + f = (QChar::category(run[0]) == QChar::Letter_Lowercase ? &font.scFont() : &font.font()); + } + for (int i = 1; i < run.length(); ++i) { + uint ch = run[i]; + if (QChar(ch).isHighSurrogate() && QChar(run[i-1]).isLowSurrogate()) + ch = QChar::surrogateToUcs4(ch, run[i-1]); + if (QChar(ch).isLowSurrogate() || QChar::category(ch) == QChar::Mark_NonSpacing) + continue; + if (Font::treatAsSpace(run[i])) { + int add = 0; +// qDebug() << " treatAsSpace:" << i << start; + if (i - start > 0) { + components->append(TextRunComponent(run.characters() + start, i - start, + run.rtl(), + f, offset, f == &font.scFont())); + offset += components->last().width + letterSpacing; +// qDebug() << " appending(1) " << components->last().string << components->last().width; + } + if (numSpaces) { + add = padding/numSpaces; + padding -= add; + --numSpaces; + } + components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); + offset += wordSpacing + add + components->last().width + letterSpacing; + start = i + 1; + continue; + } else if (!letterSpacing) { +// qDebug() << i << char(run[i]) << (QChar::category(ch) == QChar::Letter_Lowercase) << +// QFontInfo(*f).pointSizeF(); + if (QChar::category(ch) == QChar::Letter_Lowercase) { + if (f == &font.scFont()) + continue; + } else { + if (f == &font.font()) + continue; + } + } + if (i - start > 0) { + components->append(TextRunComponent(run.characters() + start, i - start, + run.rtl(), + f, offset, f == &font.scFont())); + offset += components->last().width + letterSpacing; +// qDebug() << " appending(2) " << components->last().string << components->last().width; + } + if (smallCaps) + f = (QChar::category(ch) == QChar::Letter_Lowercase ? &font.scFont() : &font.font()); + start = i; + } + if (run.length() - start > 0) { + components->append(TextRunComponent(run.characters() + start, run.length() - start, + run.rtl(), + f, offset, f == &font.scFont())); + offset += components->last().width; +// qDebug() << " appending(3) " << components->last().string << components->last().width; + } + offset += letterSpacing; + } else { + int start = 0; + for (int i = 0; i < run.length(); ++i) { + if (Font::treatAsSpace(run[i])) { + if (i - start > 0) { + components->append(TextRunComponent(run.characters() + start, i - start, + run.rtl(), + f, offset)); + offset += components->last().width; + } + int add = 0; + if (numSpaces) { + add = padding/numSpaces; + padding -= add; + --numSpaces; + } + components->append(TextRunComponent(1, run.rtl(), &font.font(), offset)); + offset += add + components->last().width; + if (i) + offset += wordSpacing; + start = i + 1; + } + } + if (run.length() - start > 0) { + components->append(TextRunComponent(run.characters() + start, run.length() - start, + run.rtl(), + f, offset)); + offset += components->last().width; + } + } + return offset; +} + +void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const +{ + if (to < 0) + to = run.length(); + + QPainter *p = ctx->platformContext(); + Color color = ctx->fillColor(); + p->setPen(QColor(color)); + + Vector<TextRunComponent, 1024> components; + int w = generateComponents(&components, *this, run); + + if (from > 0 || to < run.length()) { + FloatRect clip = selectionRectForComplexText(run, + IntPoint(qRound(point.x()), qRound(point.y())), + QFontMetrics(font()).height(), from, to); + QRectF rect(clip.x(), clip.y() - ascent(), clip.width(), clip.height()); + p->save(); + p->setClipRect(rect.toRect()); + } + + if (run.rtl()) { + for (int i = 0; i < components.size(); ++i) { + if (!components.at(i).isSpace()) { + p->setFont(*components.at(i).font); + QPointF pt(point.x() + w - components.at(i).offset - components.at(i).width, point.y()); + p->drawText(pt, components.at(i).string); + } + } + } else { + for (int i = 0; i < components.size(); ++i) { + if (!components.at(i).isSpace()) { + p->setFont(*components.at(i).font); + QPointF pt(point.x() + components.at(i).offset, point.y()); + p->drawText(pt, components.at(i).string); + } + } + } + if (from > 0 || to < run.length()) + p->restore(); +} + +float Font::floatWidthForComplexText(const TextRun& run) const +{ + Vector<TextRunComponent, 1024> components; + int w = generateComponents(&components, *this, run); + + return w; +} + +int Font::offsetForPositionForComplexText(const TextRun& run, int position, bool includePartialGlyphs) const +{ + Vector<TextRunComponent, 1024> components; + int w = generateComponents(&components, *this, run); + + int offset = 0; + if (run.rtl()) { + for (int i = 0; i < components.size(); ++i) { + int xe = w - components.at(i).offset; + int xs = xe - components.at(i).width; + if (position >= xs) { + QTextLayout layout(components.at(i).string, *components.at(i).font); + layout.beginLayout(); + QTextLine l = layout.createLine(); + if (!l.isValid()) + return offset; + + l.setLineWidth(INT_MAX/256); + layout.endLayout(); + + if (position - xs >= l.width()) + return offset; + int cursor = l.xToCursor(position - xs); + if (cursor > 1) + --cursor; + return offset + cursor; + } else { + offset += components.at(i).string.length() - 1; + } + } + } else { + for (int i = 0; i < components.size(); ++i) { + int xs = components.at(i).offset; + int xe = xs + components.at(i).width; + if (position <= xe) { + QTextLayout layout(components.at(i).string, *components.at(i).font); + layout.beginLayout(); + QTextLine l = layout.createLine(); + if (!l.isValid()) + return offset; + + l.setLineWidth(INT_MAX/256); + layout.endLayout(); + + if (position - xs >= l.width()) + return offset + components.at(i).string.length() - 1; + int cursor = l.xToCursor(position - xs); + if (cursor > 1) + --cursor; + return offset + cursor; + } else { + offset += components.at(i).string.length() - 1; + } + } + } + return run.length(); +} + +static float cursorToX(const Vector<TextRunComponent, 1024>& components, int width, bool rtl, int cursor) +{ + int start = 0; + for (int i = 0; i < components.size(); ++i) { + if (start + components.at(i).string.length() - 1 < cursor) { + start += components.at(i).string.length() - 1; + continue; + } + int xs = components.at(i).offset; + if (rtl) + xs = width - xs - components.at(i).width; + QTextLayout layout(components.at(i).string, *components.at(i).font); + layout.beginLayout(); + QTextLine l = layout.createLine(); + if (!l.isValid()) + return 0; + + l.setLineWidth(INT_MAX/256); + layout.endLayout(); + + return xs + l.cursorToX(cursor - start + 1); + } + return width; +} + +FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& pt, + int h, int from, int to) const +{ + Vector<TextRunComponent, 1024> components; + int w = generateComponents(&components, *this, run); + + if (from == 0 && to == run.length()) + return FloatRect(pt.x(), pt.y(), w, h); + + float x1 = cursorToX(components, w, run.rtl(), from); + float x2 = cursorToX(components, w, run.rtl(), to); + if (x2 < x1) + qSwap(x1, x2); + + return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h); +} + +int Font::lineGap() const +{ + return QFontMetrics(m_font).leading(); +} + +} + +#endif diff --git a/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp b/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp index d32cc63..2121206 100644 --- a/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp +++ b/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp @@ -1,5 +1,6 @@ /* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2008 Holger Hans Peter Freyther This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -24,7 +25,11 @@ namespace WebCore { -void GlyphPageTreeNode::pruneTreeCustomFontData(const FontData* fontData) +void GlyphPageTreeNode::pruneTreeCustomFontData(const FontData*) +{ +} + +void GlyphPageTreeNode::pruneTreeFontData(const WebCore::SimpleFontData*) { } diff --git a/WebCore/platform/graphics/qt/GradientQt.cpp b/WebCore/platform/graphics/qt/GradientQt.cpp index f414efa..a0edf8d 100644 --- a/WebCore/platform/graphics/qt/GradientQt.cpp +++ b/WebCore/platform/graphics/qt/GradientQt.cpp @@ -52,7 +52,7 @@ QGradient* Gradient::platformGradient() QColor stopColor; Vector<ColorStop>::iterator stopIterator = m_stops.begin(); - qreal lastStop; + qreal lastStop(0.0); const qreal lastStopDiff = 0.0000001; while (stopIterator != m_stops.end()) { stopColor.setRgbF(stopIterator->red, stopIterator->green, stopIterator->blue, stopIterator->alpha); diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp index 600d77c..2e7cdcb 100644 --- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp +++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp @@ -39,7 +39,7 @@ #include <windows.h> #endif -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "Color.h" #include "FloatConversion.h" #include "Font.h" @@ -280,7 +280,7 @@ PlatformGraphicsContext* GraphicsContext::platformContext() const return m_data->p(); } -AffineTransform GraphicsContext::getCTM() const +TransformationMatrix GraphicsContext::getCTM() const { return platformContext()->combinedMatrix(); } @@ -293,6 +293,11 @@ void GraphicsContext::savePlatformState() void GraphicsContext::restorePlatformState() { m_data->p()->restore(); + + if (!m_data->currentPath.isEmpty() && m_common->state.pathTransform.isInvertible()) { + QMatrix matrix = m_common->state.pathTransform; + m_data->currentPath = m_data->currentPath * matrix; + } } /* FIXME: DISABLED WHILE MERGING BACK FROM UNITY @@ -520,6 +525,15 @@ void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points p->restore(); } +QPen GraphicsContext::pen() +{ + if (paintingDisabled()) + return QPen(); + + QPainter *p = m_data->p(); + return p->pen(); +} + void GraphicsContext::fillPath() { if (paintingDisabled()) @@ -533,15 +547,18 @@ void GraphicsContext::fillPath() if (fillColor().alpha()) p->fillPath(path, p->brush()); break; - case PatternColorSpace: - p->fillPath(path, QBrush(m_common->state.fillPattern.get()->createPlatformPattern(getCTM()))); + case PatternColorSpace: { + TransformationMatrix affine; + p->fillPath(path, QBrush(m_common->state.fillPattern->createPlatformPattern(affine))); break; + } case GradientColorSpace: - QGradient* gradient = m_common->state.fillGradient.get()->platformGradient(); + QGradient* gradient = m_common->state.fillGradient->platformGradient(); *gradient = applySpreadMethod(*gradient, spreadMethod()); p->fillPath(path, QBrush(*gradient)); break; } + m_data->currentPath = QPainterPath(); } void GraphicsContext::strokePath() @@ -559,13 +576,14 @@ void GraphicsContext::strokePath() p->strokePath(path, pen); break; case PatternColorSpace: { - pen.setBrush(QBrush(m_common->state.strokePattern.get()->createPlatformPattern(getCTM()))); + TransformationMatrix affine; + pen.setBrush(QBrush(m_common->state.strokePattern->createPlatformPattern(affine))); p->setPen(pen); p->strokePath(path, pen); break; } case GradientColorSpace: { - QGradient* gradient = m_common->state.strokeGradient.get()->platformGradient(); + QGradient* gradient = m_common->state.strokeGradient->platformGradient(); *gradient = applySpreadMethod(*gradient, spreadMethod()); pen.setBrush(QBrush(*gradient)); p->setPen(pen); @@ -573,6 +591,7 @@ void GraphicsContext::strokePath() break; } } + m_data->currentPath = QPainterPath(); } void GraphicsContext::fillRect(const FloatRect& rect) @@ -587,13 +606,16 @@ void GraphicsContext::fillRect(const FloatRect& rect) if (fillColor().alpha()) p->fillRect(rect, p->brush()); break; - case PatternColorSpace: - p->fillRect(rect, QBrush(m_common->state.fillPattern.get()->createPlatformPattern(getCTM()))); + case PatternColorSpace: { + TransformationMatrix affine; + p->fillRect(rect, QBrush(m_common->state.fillPattern->createPlatformPattern(affine))); break; + } case GradientColorSpace: p->fillRect(rect, QBrush(*(m_common->state.fillGradient.get()->platformGradient()))); break; } + m_data->currentPath = QPainterPath(); } void GraphicsContext::fillRect(const FloatRect& rect, const Color& c) @@ -621,7 +643,9 @@ void GraphicsContext::beginPath() void GraphicsContext::addPath(const Path& path) { - m_data->currentPath = *(path.platformPath()); + QPainterPath newPath = m_data->currentPath; + newPath.addPath(*(path.platformPath())); + m_data->currentPath = newPath; } bool GraphicsContext::inTransparencyLayer() const @@ -645,6 +669,17 @@ void GraphicsContext::clip(const FloatRect& rect) else p->setClipRect(rect, Qt::IntersectClip); } +void GraphicsContext::clipPath(WindRule clipRule) +{ + if (paintingDisabled()) + return; + + QPainter *p = m_data->p(); + QPainterPath newPath = m_data->currentPath; + newPath.setFillRule(clipRule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill); + p->setClipPath(newPath); +} + /** * Focus ring handling is not handled here. Qt style in * RenderTheme handles drawing focus on widgets which @@ -823,8 +858,9 @@ void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) if (dashLength % 2) count *= 2; + float penWidth = narrowPrecisionToFloat(double(pen.widthF())); for (unsigned i = 0; i < count; i++) - pattern.append(dashes[i % dashLength] / narrowPrecisionToFloat(pen.widthF())); + pattern.append(dashes[i % dashLength] / penWidth); pen.setDashPattern(pattern); pen.setDashOffset(dashOffset); @@ -901,6 +937,12 @@ void GraphicsContext::translate(float x, float y) return; m_data->p()->translate(x, y); + + if (!m_data->currentPath.isEmpty()) { + QMatrix matrix; + m_data->currentPath = m_data->currentPath * matrix.translate(-x, -y); + m_common->state.pathTransform.translate(x, y); + } } IntPoint GraphicsContext::origin() @@ -917,6 +959,12 @@ void GraphicsContext::rotate(float radians) return; m_data->p()->rotate(180/M_PI*radians); + + if (!m_data->currentPath.isEmpty()) { + QMatrix matrix; + m_data->currentPath = m_data->currentPath * matrix.rotate(-180/M_PI*radians); + m_common->state.pathTransform.rotate(radians); + } } void GraphicsContext::scale(const FloatSize& s) @@ -925,6 +973,12 @@ void GraphicsContext::scale(const FloatSize& s) return; m_data->p()->scale(s.width(), s.height()); + + if (!m_data->currentPath.isEmpty()) { + QMatrix matrix; + m_data->currentPath = m_data->currentPath * matrix.scale(1 / s.width(), 1 / s.height()); + m_common->state.pathTransform.scale(s.width(), s.height()); + } } void GraphicsContext::clipOut(const IntRect& rect) @@ -982,12 +1036,20 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, m_data->p()->setClipPath(path, Qt::IntersectClip); } -void GraphicsContext::concatCTM(const AffineTransform& transform) +void GraphicsContext::concatCTM(const TransformationMatrix& transform) { if (paintingDisabled()) return; m_data->p()->setMatrix(transform, true); + + // Transformations to the context shouldn't transform the currentPath. + // We have to undo every change made to the context from the currentPath to avoid wrong drawings. + if (!m_data->currentPath.isEmpty() && transform.isInvertible()) { + QMatrix matrix = transform.inverse(); + m_data->currentPath = m_data->currentPath * matrix; + m_common->state.pathTransform.multiply(transform); + } } void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) @@ -995,13 +1057,6 @@ void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) notImplemented(); } -void GraphicsContext::setPlatformFont(const Font& aFont) -{ - if (paintingDisabled()) - return; - m_data->p()->setFont(aFont.font()); -} - void GraphicsContext::setPlatformStrokeColor(const Color& color) { if (paintingDisabled()) @@ -1039,7 +1094,7 @@ void GraphicsContext::setPlatformFillColor(const Color& color) m_data->p()->setBrush(QBrush(color)); } -void GraphicsContext::setUseAntialiasing(bool enable) +void GraphicsContext::setPlatformShouldAntialias(bool enable) { if (paintingDisabled()) return; @@ -1051,8 +1106,8 @@ void GraphicsContext::setUseAntialiasing(bool enable) HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) { - // painting through native HDC is only supported for plugin, where mayCreateBitmap is always TRUE - Q_ASSERT(mayCreateBitmap == TRUE); + // painting through native HDC is only supported for plugin, where mayCreateBitmap is always true + Q_ASSERT(mayCreateBitmap); if (dstRect.isEmpty()) return 0; @@ -1090,6 +1145,7 @@ HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlpha memset(bmpInfo.bmBits, 0, bufferSize); } +#if !PLATFORM(WIN_CE) // Make sure we can do world transforms. SetGraphicsMode(bitmapDC, GM_ADVANCED); @@ -1102,15 +1158,15 @@ HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlpha xform.eDx = -dstRect.x(); xform.eDy = -dstRect.y(); ::SetWorldTransform(bitmapDC, &xform); - +#endif return bitmapDC; } void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap) { - // painting through native HDC is only supported for plugin, where mayCreateBitmap is always TRUE - Q_ASSERT(mayCreateBitmap == TRUE); + // painting through native HDC is only supported for plugin, where mayCreateBitmap is always true + Q_ASSERT(mayCreateBitmap); if (hdc) { diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp index e3b00a1..394c7a7 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp @@ -178,9 +178,26 @@ ImageDecoderQt::ReadContext::IncrementalReadResult return IncrementalReadComplete; } +ImageDecoderQt* ImageDecoderQt::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) + return 0; + + QByteArray bytes = QByteArray::fromRawData(data.data(), data.size()); + QBuffer buffer(&bytes); + if (!buffer.open(QBuffer::ReadOnly)) + return 0; + + QString imageFormat = QString::fromLatin1(QImageReader::imageFormat(&buffer).toLower()); + if (imageFormat.isEmpty()) + return 0; // Image format not supported + + return new ImageDecoderQt(imageFormat); +} -// ImageDecoderQt -ImageDecoderQt::ImageDecoderQt( ) +ImageDecoderQt::ImageDecoderQt(const QString &imageFormat) + : m_imageFormat(imageFormat) { } @@ -254,7 +271,6 @@ int ImageDecoderQt::frameCount() const return m_imageList.size(); } - int ImageDecoderQt::repetitionCount() const { if (debugImageDecoderQt) @@ -262,7 +278,6 @@ int ImageDecoderQt::repetitionCount() const return m_loopCount; } - bool ImageDecoderQt::supportsAlpha() const { return hasFirstImageHeader() && m_imageList[0].m_image.hasAlphaChannel(); @@ -275,6 +290,13 @@ int ImageDecoderQt::duration(size_t index) const return m_imageList[index].m_duration; } +String ImageDecoderQt::filenameExtension() const +{ + if (debugImageDecoderQt) + qDebug() << " ImageDecoderQt::filenameExtension() returns" << m_imageFormat; + return m_imageFormat; +}; + RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index) { Q_ASSERT("use imageAtIndex instead"); diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.h b/WebCore/platform/graphics/qt/ImageDecoderQt.h index 3573dd0..a2eb6aa 100644 --- a/WebCore/platform/graphics/qt/ImageDecoderQt.h +++ b/WebCore/platform/graphics/qt/ImageDecoderQt.h @@ -38,34 +38,30 @@ namespace WebCore { class ImageDecoderQt : public ImageDecoder { - ImageDecoderQt(const ImageDecoderQt&); - ImageDecoderQt &operator=(const ImageDecoderQt&); public: - ImageDecoderQt(); + static ImageDecoderQt* create(const SharedBuffer& data); ~ImageDecoderQt(); typedef Vector<char> IncomingData; virtual void setData(const IncomingData& data, bool allDataReceived); - virtual bool isSizeAvailable() const; - virtual int frameCount() const; - - 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); + private: + ImageDecoderQt(const QString &imageFormat); + ImageDecoderQt(const ImageDecoderQt&); + ImageDecoderQt &operator=(const ImageDecoderQt&); + class ReadContext; void reset(); bool hasFirstImageHeader() const; @@ -89,6 +85,7 @@ private: ImageList m_imageList; mutable QHash<int, QPixmap> m_pixmapCache; int m_loopCount; + QString m_imageFormat; }; diff --git a/WebCore/platform/graphics/qt/ImageQt.cpp b/WebCore/platform/graphics/qt/ImageQt.cpp index 9234c69..99062f9 100644 --- a/WebCore/platform/graphics/qt/ImageQt.cpp +++ b/WebCore/platform/graphics/qt/ImageQt.cpp @@ -34,7 +34,7 @@ #include "FloatRect.h" #include "PlatformString.h" #include "GraphicsContext.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "NotImplemented.h" #include "StillImageQt.h" #include "qwebsettings.h" @@ -69,14 +69,16 @@ static QPixmap loadResourcePixmap(const char *name) namespace WebCore { -void FrameData::clear() +bool FrameData::clear(bool clearMetadata) { + if (clearMetadata) + m_haveMetadata = false; + if (m_frame) { m_frame = 0; - // NOTE: We purposefully don't reset metadata here, so that even if we - // throw away previously-decoded data, animation loops can still access - // properties like frame durations without re-decoding. + return true; } + return false; } @@ -91,7 +93,7 @@ PassRefPtr<Image> Image::loadPlatformResource(const char* name) } -void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform, +void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) { notImplemented(); @@ -136,7 +138,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, ctxt->restore(); } -void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform, +void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect) { QPixmap* framePixmap = nativeImageForCurrentFrame(); diff --git a/WebCore/platform/graphics/qt/ImageSourceQt.cpp b/WebCore/platform/graphics/qt/ImageSourceQt.cpp index 1d14f9d..d62acc3 100644 --- a/WebCore/platform/graphics/qt/ImageSourceQt.cpp +++ b/WebCore/platform/graphics/qt/ImageSourceQt.cpp @@ -29,6 +29,7 @@ #include "config.h" #include "ImageSource.h" #include "ImageDecoderQt.h" +#include "NotImplemented.h" #include "SharedBuffer.h" #include <QBuffer> @@ -36,25 +37,6 @@ #include <QImageReader> namespace WebCore { -static bool canHandleImage(const SharedBuffer& _data) -{ - // We need at least 4 bytes to figure out what kind of image we're dealing with. - if (_data.size() < 4) - return false; - - QByteArray data = QByteArray::fromRawData(_data.data(), _data.size()); - QBuffer buffer(&data); - if (!buffer.open(QBuffer::ReadOnly)) - return false; - - return !QImageReader::imageFormat(&buffer).isEmpty(); -} - -ImageDecoderQt* createDecoder(const SharedBuffer& data) { - if (!canHandleImage(data)) - return 0; - return new ImageDecoderQt(); -} ImageSource::ImageSource() : m_decoder(0) @@ -63,7 +45,7 @@ ImageSource::ImageSource() ImageSource::~ImageSource() { - delete m_decoder; + clear(true); } bool ImageSource::initialized() const @@ -78,7 +60,7 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived) // If insufficient bytes are available to determine the image type, no decoder plugin will be // made. if (!m_decoder) - m_decoder = createDecoder(*data); + m_decoder = ImageDecoderQt::create(*data); if (!m_decoder) return; @@ -86,6 +68,14 @@ void ImageSource::setData(SharedBuffer* data, bool allDataReceived) 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) @@ -162,13 +152,20 @@ bool ImageSource::frameIsCompleteAtIndex(size_t index) return (m_decoder && m_decoder->imageAtIndex(index) != 0); } -void ImageSource::clear() +void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived) { - delete m_decoder; + 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 431e68e..b1a48fb 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp @@ -84,6 +84,9 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) { // Hint to Phonon to disable overlay painting m_videoWidget->setAttribute(Qt::WA_DontShowOnScreen); +#if QT_VERSION < 0x040500 + m_videoWidget->setAttribute(Qt::WA_QuitOnClose, false); +#endif createPath(m_mediaObject, m_videoWidget); createPath(m_mediaObject, m_audioOutput); @@ -96,7 +99,6 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) connect(m_mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(stateChanged(Phonon::State, Phonon::State))); - connect(m_mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64))); connect(m_mediaObject, SIGNAL(metaDataChanged()), this, SLOT(metaDataChanged())); connect(m_mediaObject, SIGNAL(seekableChanged(bool)), this, SLOT(seekableChanged(bool))); connect(m_mediaObject, SIGNAL(hasVideoChanged(bool)), this, SLOT(hasVideoChanged(bool))); @@ -105,7 +107,6 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) connect(m_mediaObject, SIGNAL(currentSourceChanged(const Phonon::MediaSource&)), this, SLOT(currentSourceChanged(const Phonon::MediaSource&))); connect(m_mediaObject, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish())); - connect(m_mediaObject, SIGNAL(prefinishMarkReached(qint32)), this, SLOT(prefinishMarkReached(qint32))); connect(m_mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64))); } @@ -314,7 +315,7 @@ void MediaPlayerPrivate::updateStates() m_mediaObject->pause(); } } else if (phononState == Phonon::PausedState) { - m_networkState = MediaPlayer::LoadedFirstFrame; + m_networkState = MediaPlayer::Loaded; m_readyState = MediaPlayer::CanPlayThrough; } else if (phononState == Phonon::ErrorState) { if (!m_mediaObject || m_mediaObject->errorType() == Phonon::FatalError) { @@ -371,42 +372,6 @@ void MediaPlayerPrivate::setRect(const IntRect& newRect) m_videoWidget->resize(newRect.width(), newRect.height()); } - -void MediaPlayerPrivate::loadStateChanged() -{ - notImplemented(); -} - -void MediaPlayerPrivate::rateChanged() -{ - notImplemented(); -} - -void MediaPlayerPrivate::sizeChanged() -{ - notImplemented(); -} - -void MediaPlayerPrivate::timeChanged() -{ - notImplemented(); -} - -void MediaPlayerPrivate::volumeChanged() -{ - notImplemented(); -} - -void MediaPlayerPrivate::didEnd() -{ - notImplemented(); -} - -void MediaPlayerPrivate::loadingFailed() -{ - notImplemented(); -} - IntSize MediaPlayerPrivate::naturalSize() const { if (!hasVideo()) { @@ -430,17 +395,12 @@ IntSize MediaPlayerPrivate::naturalSize() const bool MediaPlayerPrivate::eventFilter(QObject* obj, QEvent* event) { - if (event->type() == QEvent::Paint) + if (event->type() == QEvent::UpdateRequest) m_player->repaint(); return QObject::eventFilter(obj, event); } -void MediaPlayerPrivate::repaint() -{ - m_player->repaint(); -} - void MediaPlayerPrivate::paint(GraphicsContext* graphicsContect, const IntRect& rect) { if (graphicsContect->paintingDisabled()) @@ -469,12 +429,6 @@ void MediaPlayerPrivate::stateChanged(Phonon::State newState, Phonon::State oldS updateStates(); } -void MediaPlayerPrivate::tick(qint64) -{ - updateStates(); - m_player->timeChanged(); -} - void MediaPlayerPrivate::metaDataChanged() { LOG(Media, "MediaPlayerPrivatePhonon::metaDataChanged()"); @@ -516,12 +470,6 @@ void MediaPlayerPrivate::aboutToFinish() LOG_MEDIAOBJECT(); } -void MediaPlayerPrivate::prefinishMarkReached(qint32) -{ - notImplemented(); - LOG_MEDIAOBJECT(); -} - void MediaPlayerPrivate::totalTimeChanged(qint64 totalTime) { LOG(Media, "MediaPlayerPrivatePhonon::totalTimeChanged(%d)", totalTime); diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h index 5eb2a09..1b20a84 100644 --- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h +++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h @@ -111,15 +111,6 @@ namespace WebCore { void setVisible(bool); void setRect(const IntRect&); - void loadStateChanged(); - void rateChanged(); - void sizeChanged(); - void timeChanged(); - void volumeChanged(); - void didEnd(); - void loadingFailed(); - - void repaint(); void paint(GraphicsContext*, const IntRect&); static void getSupportedTypes(HashSet<String>&); static bool isAvailable() { return true; } @@ -129,7 +120,6 @@ namespace WebCore { private slots: void stateChanged(Phonon::State, Phonon::State); - void tick(qint64); void metaDataChanged(); void seekableChanged(bool); void hasVideoChanged(bool); @@ -137,7 +127,6 @@ namespace WebCore { void finished(); void currentSourceChanged(const Phonon::MediaSource&); void aboutToFinish(); - void prefinishMarkReached(qint32); void totalTimeChanged(qint64); private: diff --git a/WebCore/platform/graphics/qt/PathQt.cpp b/WebCore/platform/graphics/qt/PathQt.cpp index 76f375c..bd0192c 100644 --- a/WebCore/platform/graphics/qt/PathQt.cpp +++ b/WebCore/platform/graphics/qt/PathQt.cpp @@ -29,9 +29,12 @@ #include "config.h" #include "Path.h" +#include "TransformationMatrix.h" #include "FloatRect.h" +#include "GraphicsContext.h" +#include "ImageBuffer.h" #include "PlatformString.h" -#include "AffineTransform.h" +#include "StrokeStyleApplier.h" #include <QPainterPath> #include <QMatrix> #include <QString> @@ -39,6 +42,10 @@ #define _USE_MATH_DEFINES #include <math.h> +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + namespace WebCore { Path::Path() @@ -77,6 +84,28 @@ bool Path::contains(const FloatPoint& point, WindRule rule) const return contains; } +bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const +{ + ASSERT(applier); + + // FIXME: We should try to use a 'shared Context' instead of creating a new ImageBuffer + // on each call. + std::auto_ptr<ImageBuffer> scratchImage = ImageBuffer::create(IntSize(1, 1), false); + GraphicsContext* gc = scratchImage->context(); + QPainterPathStroker stroke; + applier->strokeStyle(gc); + + QPen pen = gc->pen(); + stroke.setWidth(pen.widthF()); + stroke.setCapStyle(pen.capStyle()); + stroke.setJoinStyle(pen.joinStyle()); + stroke.setMiterLimit(pen.miterLimit()); + stroke.setDashPattern(pen.dashPattern()); + stroke.setDashOffset(pen.dashOffset()); + + return (stroke.createStroke(*platformPath())).contains(point); +} + void Path::translate(const FloatSize& size) { QMatrix matrix; @@ -89,6 +118,27 @@ FloatRect Path::boundingRect() const return m_path->boundingRect(); } +FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) +{ + // FIXME: We should try to use a 'shared Context' instead of creating a new ImageBuffer + // on each call. + std::auto_ptr<ImageBuffer> scratchImage = ImageBuffer::create(IntSize(1, 1), false); + GraphicsContext* gc = scratchImage->context(); + QPainterPathStroker stroke; + if (applier) { + applier->strokeStyle(gc); + + QPen pen = gc->pen(); + stroke.setWidth(pen.widthF()); + stroke.setCapStyle(pen.capStyle()); + stroke.setJoinStyle(pen.joinStyle()); + stroke.setMiterLimit(pen.miterLimit()); + stroke.setDashPattern(pen.dashPattern()); + stroke.setDashOffset(pen.dashOffset()); + } + return (stroke.createStroke(*platformPath())).boundingRect(); +} + void Path::moveTo(const FloatPoint& point) { m_path->moveTo(point); @@ -263,7 +313,7 @@ void Path::apply(void* info, PathApplierFunction function) const } } -void Path::transform(const AffineTransform& transform) +void Path::transform(const TransformationMatrix& transform) { if (m_path) { QMatrix mat = transform; diff --git a/WebCore/platform/graphics/qt/PatternQt.cpp b/WebCore/platform/graphics/qt/PatternQt.cpp index 883a258..5b76841 100644 --- a/WebCore/platform/graphics/qt/PatternQt.cpp +++ b/WebCore/platform/graphics/qt/PatternQt.cpp @@ -26,12 +26,12 @@ #include "config.h" #include "Pattern.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "GraphicsContext.h" namespace WebCore { -QBrush Pattern::createPlatformPattern(const AffineTransform& transform) const +QBrush Pattern::createPlatformPattern(const TransformationMatrix& transform) const { QPixmap* pixmap = tileImage()->nativeImageForCurrentFrame(); if (!pixmap) diff --git a/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp index 1ffce33..6cf4e55 100644 --- a/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp +++ b/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp @@ -1,5 +1,6 @@ /* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2008 Holger Hans Peter Freyther This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -19,37 +20,47 @@ This class provides all functionality needed for loading images, style sheets and html pages from the web. It has a memory cache for these objects. */ + #include "config.h" #include "SimpleFontData.h" -#include "SVGFontData.h" +#include <QFontMetrics> namespace WebCore { -SimpleFontData::SimpleFontData(const FontPlatformData& font, bool customFont, bool loading, SVGFontData*) - : m_font(font) - , m_isCustomFont(customFont) - , m_isLoading(loading) +void SimpleFontData::determinePitch() { + m_treatAsFixedPitch = m_font.font().fixedPitch(); } -SimpleFontData::~SimpleFontData() +bool SimpleFontData::containsCharacters(const UChar*, int length) const { + return true; } -bool SimpleFontData::containsCharacters(const UChar* characters, int length) const +void SimpleFontData::platformInit() { - return true; + QFontMetrics fm(m_font.font()); + + m_ascent = fm.ascent(); + m_descent = fm.descent(); + m_lineSpacing = fm.lineSpacing(); + m_xHeight = fm.xHeight(); + m_spaceWidth = fm.width(QLatin1Char(' ')); + m_lineGap = fm.leading(); } -const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const +void SimpleFontData::platformGlyphInit() { - return this; + m_spaceGlyph = 0; + m_adjustedSpaceWidth = m_spaceWidth; + determinePitch(); + m_missingGlyphData.fontData = this; + m_missingGlyphData.glyph = 0; } -bool SimpleFontData::isSegmented() const +void SimpleFontData::platformDestroy() { - return false; } } diff --git a/WebCore/platform/graphics/qt/StillImageQt.h b/WebCore/platform/graphics/qt/StillImageQt.h index 37b8b2c..2b2c1f7 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 incremental = false, bool preserveNearbyFrames = false) { } + virtual void destroyDecodedData(bool destroyAll = true) { } virtual unsigned decodedSize() const { return 0; } virtual IntSize size() const; diff --git a/WebCore/platform/graphics/qt/AffineTransformQt.cpp b/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp index 2793043..47abd17 100644 --- a/WebCore/platform/graphics/qt/AffineTransformQt.cpp +++ b/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp @@ -24,34 +24,34 @@ */ #include "config.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "IntRect.h" #include "FloatRect.h" namespace WebCore { -AffineTransform::AffineTransform() +TransformationMatrix::TransformationMatrix() : m_transform() { } -AffineTransform::AffineTransform(double a, double b, double c, double d, double tx, double ty) +TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double tx, double ty) : m_transform(a, b, c, d, tx, ty) { } -AffineTransform::AffineTransform(const PlatformAffineTransform& matrix) +TransformationMatrix::TransformationMatrix(const PlatformTransformationMatrix& matrix) : m_transform(matrix) { } -void AffineTransform::setMatrix(double a, double b, double c, double d, double tx, double ty) +void TransformationMatrix::setMatrix(double a, double b, double c, double d, double tx, double ty) { m_transform.setMatrix(a, b, c, d, tx, ty); } -void AffineTransform::map(double x, double y, double* x2, double* y2) const +void TransformationMatrix::map(double x, double y, double* x2, double* y2) const { qreal tx2, ty2; m_transform.map(qreal(x), qreal(y), &tx2, &ty2); @@ -59,140 +59,140 @@ void AffineTransform::map(double x, double y, double* x2, double* y2) const *y2 = ty2; } -IntRect AffineTransform::mapRect(const IntRect& rect) const +IntRect TransformationMatrix::mapRect(const IntRect& rect) const { return m_transform.mapRect(rect); } -FloatRect AffineTransform::mapRect(const FloatRect& rect) const +FloatRect TransformationMatrix::mapRect(const FloatRect& rect) const { return m_transform.mapRect(rect); } -bool AffineTransform::isIdentity() const +bool TransformationMatrix::isIdentity() const { return m_transform.isIdentity(); } -double AffineTransform::a() const +double TransformationMatrix::a() const { return m_transform.m11(); } -void AffineTransform::setA(double a) +void TransformationMatrix::setA(double a) { m_transform.setMatrix(a, b(), c(), d(), e(), f()); } -double AffineTransform::b() const +double TransformationMatrix::b() const { return m_transform.m12(); } -void AffineTransform::setB(double b) +void TransformationMatrix::setB(double b) { m_transform.setMatrix(a(), b, c(), d(), e(), f()); } -double AffineTransform::c() const +double TransformationMatrix::c() const { return m_transform.m21(); } -void AffineTransform::setC(double c) +void TransformationMatrix::setC(double c) { m_transform.setMatrix(a(), b(), c, d(), e(), f()); } -double AffineTransform::d() const +double TransformationMatrix::d() const { return m_transform.m22(); } -void AffineTransform::setD(double d) +void TransformationMatrix::setD(double d) { m_transform.setMatrix(a(), b(), c(), d, e(), f()); } -double AffineTransform::e() const +double TransformationMatrix::e() const { return m_transform.dx(); } -void AffineTransform::setE(double e) +void TransformationMatrix::setE(double e) { m_transform.setMatrix(a(), b(), c(), d(), e, f()); } -double AffineTransform::f() const +double TransformationMatrix::f() const { return m_transform.dy(); } -void AffineTransform::setF(double f) +void TransformationMatrix::setF(double f) { m_transform.setMatrix(a(), b(), c(), d(), e(), f); } -void AffineTransform::reset() +void TransformationMatrix::reset() { m_transform.reset(); } -AffineTransform& AffineTransform::scale(double sx, double sy) +TransformationMatrix& TransformationMatrix::scale(double sx, double sy) { m_transform.scale(sx, sy); return *this; } -AffineTransform& AffineTransform::rotate(double d) +TransformationMatrix& TransformationMatrix::rotate(double d) { m_transform.rotate(d); return *this; } -AffineTransform& AffineTransform::translate(double tx, double ty) +TransformationMatrix& TransformationMatrix::translate(double tx, double ty) { m_transform.translate(tx, ty); return *this; } -AffineTransform& AffineTransform::shear(double sx, double sy) +TransformationMatrix& TransformationMatrix::shear(double sx, double sy) { m_transform.shear(sx, sy); return *this; } -double AffineTransform::det() const +double TransformationMatrix::det() const { return m_transform.det(); } -AffineTransform AffineTransform::inverse() const +TransformationMatrix TransformationMatrix::inverse() const { if(!isInvertible()) - return AffineTransform(); + return TransformationMatrix(); return m_transform.inverted(); } -AffineTransform::operator QMatrix() const +TransformationMatrix::operator QMatrix() const { return m_transform; } -bool AffineTransform::operator==(const AffineTransform& other) const +bool TransformationMatrix::operator==(const TransformationMatrix& other) const { return m_transform == other.m_transform; } -AffineTransform& AffineTransform::operator*=(const AffineTransform& other) +TransformationMatrix& TransformationMatrix::operator*=(const TransformationMatrix& other) { m_transform *= other.m_transform; return *this; } -AffineTransform AffineTransform::operator*(const AffineTransform& other) +TransformationMatrix TransformationMatrix::operator*(const TransformationMatrix& other) { return m_transform * other.m_transform; } diff --git a/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h b/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h new file mode 100644 index 0000000..5d85652 --- /dev/null +++ b/WebCore/platform/graphics/skia/BitmapImageSingleFrameSkia.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2006,2007,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. + */ + +#ifndef BitmapImageSingleFrameSkia_h +#define BitmapImageSingleFrameSkia_h + +#include "Image.h" +#include "NativeImageSkia.h" + +namespace WebCore { + +// This image class can be used in places which need an Image, but have +// raw pixel data rather than undecoded image data. +// The Image is simpler than a BitmapImage, as it does not have image +// observers, animation, multiple frames, or non-decoded data. +// Therefore trimming the decoded data (destroyDecodedData()) has no effect. +// +// The difficulty with putting this in BitmapImage::create(NativeImagePtr) +// is that NativeImagePtr = NativeImageSkia, yet callers have SkBitmap. +class BitmapImageSingleFrameSkia : public Image { +public: + // Creates a new Image, by copying the pixel values out of |bitmap|. + // If creation failed, returns null. + static PassRefPtr<BitmapImageSingleFrameSkia> create(const SkBitmap&); + + virtual bool isBitmapImage() const { return true; } + + virtual IntSize size() const + { + return IntSize(m_nativeImage.width(), m_nativeImage.height()); + } + + // Do nothing, as we only have the one representation of data (decoded). + virtual void destroyDecodedData(bool destroyAll = true) { } + + virtual unsigned decodedSize() const + { + return m_nativeImage.decodedSize(); + } + + // We only have a single frame. + virtual NativeImagePtr nativeImageForCurrentFrame() + { + return &m_nativeImage; + } + +protected: + virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator); + +private: + NativeImageSkia m_nativeImage; + + // Use create(). + BitmapImageSingleFrameSkia() { } +}; + +} // namespace WebCore + +#endif // BitmapImageSingleFrameSkia_h diff --git a/WebCore/platform/graphics/skia/FloatPointSkia.cpp b/WebCore/platform/graphics/skia/FloatPointSkia.cpp new file mode 100644 index 0000000..054a772 --- /dev/null +++ b/WebCore/platform/graphics/skia/FloatPointSkia.cpp @@ -0,0 +1,51 @@ +/* + * 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 "FloatPoint.h" + +#include "SkPoint.h" +#include "SkiaUtils.h" + +namespace WebCore { + +FloatPoint::FloatPoint(const SkPoint& p) + : m_x(p.fX) + , m_y(p.fY) +{ +} + +FloatPoint::operator SkPoint() const +{ + SkPoint p = { WebCoreFloatToSkScalar(m_x), WebCoreFloatToSkScalar(m_y) }; + return p; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/skia/FloatRectSkia.cpp b/WebCore/platform/graphics/skia/FloatRectSkia.cpp new file mode 100644 index 0000000..a10371f --- /dev/null +++ b/WebCore/platform/graphics/skia/FloatRectSkia.cpp @@ -0,0 +1,50 @@ +/* + * 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 "FloatRect.h" + +#include "SkRect.h" + +namespace WebCore { + +FloatRect::FloatRect(const SkRect& r) + : m_location(r.fLeft, r.fTop) + , m_size(r.width(), r.height()) +{ +} + +FloatRect::operator SkRect() const +{ + SkRect rect = { x(), y(), right(), bottom() }; + return rect; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/skia/GradientSkia.cpp b/WebCore/platform/graphics/skia/GradientSkia.cpp new file mode 100644 index 0000000..eff7c66 --- /dev/null +++ b/WebCore/platform/graphics/skia/GradientSkia.cpp @@ -0,0 +1,164 @@ +/* + * 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 "Gradient.h" + +#include "CSSParser.h" +#include "GraphicsContext.h" + +#include "SkGradientShader.h" +#include "SkiaUtils.h" + +namespace WebCore { + +void Gradient::platformDestroy() +{ + if (m_gradient) + m_gradient->safeUnref(); + m_gradient = 0; +} + +static inline U8CPU F2B(float x) +{ + return static_cast<int>(x * 255); +} + +static SkColor makeSkColor(float a, float r, float g, float b) +{ + return SkColorSetARGB(F2B(a), F2B(r), F2B(g), F2B(b)); +} + +// Determine the total number of stops needed, including pseudo-stops at the +// ends as necessary. +static size_t totalStopsNeeded(const Gradient::ColorStop* stopData, size_t count) +{ + const Gradient::ColorStop* stop = stopData; + size_t countUsed = count; + if (count < 1 || stop->stop > 0.0) + countUsed++; + stop += count - 1; + if (count < 2 || stop->stop < 1.0) + countUsed++; + return countUsed; +} + +// Collect sorted stop position and color information into the pos and colors +// buffers, ensuring stops at both 0.0 and 1.0. The buffers must be large +// enough to hold information for all stops, including the new endpoints if +// stops at 0.0 and 1.0 aren't already included. +static void fillStops(const Gradient::ColorStop* stopData, + size_t count, SkScalar* pos, SkColor* colors) +{ + const Gradient::ColorStop* stop = stopData; + size_t start = 0; + if (count < 1) { + // A gradient with no stops must be transparent black. + pos[0] = WebCoreFloatToSkScalar(0.0); + colors[0] = makeSkColor(0.0, 0.0, 0.0, 0.0); + start = 1; + } else if (stop->stop > 0.0) { + // Copy the first stop to 0.0. The first stop position may have a slight + // rounding error, but we don't care in this float comparison, since + // 0.0 comes through cleanly and people aren't likely to want a gradient + // with a stop at (0 + epsilon). + pos[0] = WebCoreFloatToSkScalar(0.0); + colors[0] = makeSkColor(stop->alpha, stop->red, stop->green, stop->blue); + start = 1; + } + + for (size_t i = start; i < start + count; i++) { + pos[i] = WebCoreFloatToSkScalar(stop->stop); + colors[i] = makeSkColor(stop->alpha, stop->red, stop->green, stop->blue); + ++stop; + } + + // Copy the last stop to 1.0 if needed. See comment above about this float + // comparison. + if (count < 1 || (--stop)->stop < 1.0) { + pos[start + count] = WebCoreFloatToSkScalar(1.0); + colors[start + count] = colors[start + count - 1]; + } +} + +static inline bool compareStops(const Gradient::ColorStop& a, const Gradient::ColorStop& b) +{ + return a.stop < b.stop; +} + +SkShader* Gradient::platformGradient() +{ + if (m_gradient) + return m_gradient; + + // FIXME: This and compareStops() are also in Gradient.cpp and + // CSSGradientValue.cpp; probably should refactor in WebKit. + if (!m_stopsSorted) { + if (m_stops.size()) + std::stable_sort(m_stops.begin(), m_stops.end(), compareStops); + m_stopsSorted = true; + } + size_t countUsed = totalStopsNeeded(m_stops.data(), m_stops.size()); + ASSERT(countUsed >= 2); + ASSERT(countUsed >= m_stops.size()); + + // FIXME: Why is all this manual pointer math needed?! + SkAutoMalloc storage(countUsed * (sizeof(SkColor) + sizeof(SkScalar))); + SkColor* colors = (SkColor*)storage.get(); + SkScalar* pos = (SkScalar*)(colors + countUsed); + + fillStops(m_stops.data(), m_stops.size(), pos, colors); + + 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. + m_gradient = SkGradientShader::CreateRadial(m_p1, + WebCoreFloatToSkScalar(m_r1), colors, pos, + static_cast<int>(countUsed), SkShader::kClamp_TileMode); + } else { + SkPoint pts[2] = { m_p0, m_p1 }; + m_gradient = SkGradientShader::CreateLinear(pts, colors, pos, + static_cast<int>(countUsed), SkShader::kClamp_TileMode); + } + + return m_gradient; +} + +void Gradient::fill(GraphicsContext* context, const FloatRect& rect) +{ + context->setFillGradient(this); + context->fillRect(rect); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/skia/GraphicsContextPlatformPrivate.h b/WebCore/platform/graphics/skia/GraphicsContextPlatformPrivate.h new file mode 100644 index 0000000..29738f4 --- /dev/null +++ b/WebCore/platform/graphics/skia/GraphicsContextPlatformPrivate.h @@ -0,0 +1,55 @@ +/* + * 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. + */ + +#ifndef GraphicsContextPlatformPrivate_h +#define GraphicsContextPlatformPrivate_h + +#include <wtf/Noncopyable.h> + +class PlatformContextSkia; + +namespace WebCore { + +// This class just holds onto a PlatformContextSkia for GraphicsContext. +class GraphicsContextPlatformPrivate : Noncopyable { +public: + GraphicsContextPlatformPrivate(PlatformContextSkia* platformContext) + : m_context(platformContext) { } + + PlatformContextSkia* context() { return m_context; } + +private: + // Non-owning pointer to the PlatformContext. + PlatformContextSkia* m_context; +}; + +} // namespace WebCore + +#endif // GraphicsContextPlatformPrivate_h diff --git a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp new file mode 100644 index 0000000..e6c7783 --- /dev/null +++ b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp @@ -0,0 +1,1122 @@ +/* + * Copyright (c) 2006, 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 "GraphicsContext.h" + +#include "GraphicsContextPlatformPrivate.h" +#include "GraphicsContextPrivate.h" +#include "Color.h" +#include "FloatRect.h" +#include "Gradient.h" +#include "IntRect.h" +#include "NativeImageSkia.h" +#include "NotImplemented.h" +#include "PlatformContextSkia.h" +#include "TransformationMatrix.h" + +#include "SkBitmap.h" +#include "SkBlurDrawLooper.h" +#include "SkCornerPathEffect.h" +#include "skia/ext/platform_canvas.h" +#include "SkiaUtils.h" +#include "SkShader.h" + +#include <math.h> +#include <wtf/Assertions.h> +#include <wtf/MathExtras.h> + +using namespace std; + +namespace WebCore { + +namespace { + +// "Seatbelt" functions ------------------------------------------------------ +// +// These functions check certain graphics primitives for being "safe". +// Skia has historically crashed when sent crazy data. These functions do +// additional checking to prevent crashes. +// +// Ideally, all of these would be fixed in the graphics layer and we would not +// have to do any checking. You can uncomment the ENSURE_VALUE_SAFETY_FOR_SKIA +// flag to check the graphics layer. +#define ENSURE_VALUE_SAFETY_FOR_SKIA + +static bool isCoordinateSkiaSafe(float coord) +{ +#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA + // First check for valid floats. +#if defined(_MSC_VER) + if (!_finite(coord)) +#else + if (!finite(coord)) +#endif + return false; + + // Skia uses 16.16 fixed point and 26.6 fixed point in various places. If + // the transformed point exceeds 15 bits, we just declare that it's + // unreasonable to catch both of these cases. + static const int maxPointMagnitude = 32767; + if (coord > maxPointMagnitude || coord < -maxPointMagnitude) + return false; + + return true; +#else + return true; +#endif +} + +static bool isPointSkiaSafe(const SkMatrix& transform, const SkPoint& pt) +{ +#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA + // Now check for points that will overflow. We check the *transformed* + // points since this is what will be rasterized. + SkPoint xPt; + transform.mapPoints(&xPt, &pt, 1); + return isCoordinateSkiaSafe(xPt.fX) && isCoordinateSkiaSafe(xPt.fY); +#else + return true; +#endif +} + +static bool isRectSkiaSafe(const SkMatrix& transform, const SkRect& rc) +{ +#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA + SkPoint topleft = {rc.fLeft, rc.fTop}; + SkPoint bottomright = {rc.fRight, rc.fBottom}; + return isPointSkiaSafe(transform, topleft) && isPointSkiaSafe(transform, bottomright); +#else + return true; +#endif +} + +bool isPathSkiaSafe(const SkMatrix& transform, const SkPath& path) +{ +#ifdef ENSURE_VALUE_SAFETY_FOR_SKIA + SkPoint current_points[4]; + SkPath::Iter iter(path, false); + for (SkPath::Verb verb = iter.next(current_points); + verb != SkPath::kDone_Verb; + verb = iter.next(current_points)) { + switch (verb) { + case SkPath::kMove_Verb: + // This move will be duplicated in the next verb, so we can ignore. + break; + case SkPath::kLine_Verb: + // iter.next returns 2 points. + if (!isPointSkiaSafe(transform, current_points[0]) + || !isPointSkiaSafe(transform, current_points[1])) + return false; + break; + case SkPath::kQuad_Verb: + // iter.next returns 3 points. + if (!isPointSkiaSafe(transform, current_points[0]) + || !isPointSkiaSafe(transform, current_points[1]) + || !isPointSkiaSafe(transform, current_points[2])) + return false; + break; + case SkPath::kCubic_Verb: + // iter.next returns 4 points. + if (!isPointSkiaSafe(transform, current_points[0]) + || !isPointSkiaSafe(transform, current_points[1]) + || !isPointSkiaSafe(transform, current_points[2]) + || !isPointSkiaSafe(transform, current_points[3])) + return false; + break; + case SkPath::kClose_Verb: + case SkPath::kDone_Verb: + default: + break; + } + } + return true; +#else + return true; +#endif +} + +// Local helper functions ------------------------------------------------------ + +void addCornerArc(SkPath* path, const SkRect& rect, const IntSize& size, int startAngle) +{ + SkIRect ir; + int rx = SkMin32(SkScalarRound(rect.width()), size.width()); + int ry = SkMin32(SkScalarRound(rect.height()), size.height()); + + ir.set(-rx, -ry, rx, ry); + switch (startAngle) { + case 0: + ir.offset(rect.fRight - ir.fRight, rect.fBottom - ir.fBottom); + break; + case 90: + ir.offset(rect.fLeft - ir.fLeft, rect.fBottom - ir.fBottom); + break; + case 180: + ir.offset(rect.fLeft - ir.fLeft, rect.fTop - ir.fTop); + break; + case 270: + ir.offset(rect.fRight - ir.fRight, rect.fTop - ir.fTop); + break; + default: + ASSERT(0); + } + + SkRect r; + r.set(ir); + 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 +// no painting. +GraphicsContext::GraphicsContext(PlatformGraphicsContext* gc) + : m_common(createGraphicsContextPrivate()) + , m_data(new GraphicsContextPlatformPrivate(gc)) +{ + setPaintingDisabled(!gc || !platformContext()->canvas()); +} + +GraphicsContext::~GraphicsContext() +{ + delete m_data; + this->destroyGraphicsContextPrivate(m_common); +} + +PlatformGraphicsContext* GraphicsContext::platformContext() const +{ + ASSERT(!paintingDisabled()); + return m_data->context(); +} + +// State saving ---------------------------------------------------------------- + +void GraphicsContext::savePlatformState() +{ + if (paintingDisabled()) + return; + + // Save our private State. + platformContext()->save(); +} + +void GraphicsContext::restorePlatformState() +{ + if (paintingDisabled()) + return; + + // Restore our private State. + platformContext()->restore(); +} + +void GraphicsContext::beginTransparencyLayer(float opacity) +{ + if (paintingDisabled()) + return; + + // We need the "alpha" layer flag here because the base layer is opaque + // (the surface of the page) but layers on top may have transparent parts. + // Without explicitly setting the alpha flag, the layer will inherit the + // opaque setting of the base and some things won't work properly. + platformContext()->canvas()->saveLayerAlpha( + 0, + static_cast<unsigned char>(opacity * 255), + static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | + SkCanvas::kFullColorLayer_SaveFlag)); +} + +void GraphicsContext::endTransparencyLayer() +{ + if (paintingDisabled()) + return; + +#if PLATFORM(WIN_OS) + platformContext()->canvas()->getTopPlatformDevice(). + fixupAlphaBeforeCompositing(); +#endif + platformContext()->canvas()->restore(); +} + +// Graphics primitives --------------------------------------------------------- + +void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness) +{ + if (paintingDisabled()) + return; + + SkRect r(rect); + if (!isRectSkiaSafe(getCTM(), r)) + return; + + SkPath path; + 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)); + path.addOval(r, SkPath::kCCW_Direction); + } + platformContext()->canvas()->clipPath(path); +} + +void GraphicsContext::addPath(const Path& path) +{ + if (paintingDisabled()) + return; + platformContext()->addPath(*path.platformPath()); +} + +void GraphicsContext::beginPath() +{ + if (paintingDisabled()) + return; + platformContext()->beginPath(); +} + +void GraphicsContext::clearPlatformShadow() +{ + if (paintingDisabled()) + return; + platformContext()->setDrawLooper(0); +} + +void GraphicsContext::clearRect(const FloatRect& rect) +{ + if (paintingDisabled()) + return; + + SkRect r = rect; + if (!isRectSkiaSafe(getCTM(), r)) + ClipRectToCanvas(*platformContext()->canvas(), r, &r); + + SkPaint paint; + platformContext()->setupPaintForFilling(&paint); + paint.setPorterDuffXfermode(SkPorterDuff::kClear_Mode); + platformContext()->canvas()->drawRect(r, paint); +} + +void GraphicsContext::clip(const FloatRect& rect) +{ + if (paintingDisabled()) + return; + + SkRect r(rect); + if (!isRectSkiaSafe(getCTM(), r)) + return; + + platformContext()->canvas()->clipRect(r); +} + +void GraphicsContext::clip(const Path& path) +{ + if (paintingDisabled()) + return; + + const SkPath& p = *path.platformPath(); + if (!isPathSkiaSafe(getCTM(), p)) + return; + + platformContext()->canvas()->clipPath(p); +} + +void GraphicsContext::clipOut(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + SkRect r(rect); + if (!isRectSkiaSafe(getCTM(), r)) + return; + + platformContext()->canvas()->clipRect(r, SkRegion::kDifference_Op); +} + +void GraphicsContext::clipOut(const Path& p) +{ + if (paintingDisabled()) + return; + + const SkPath& path = *p.platformPath(); + if (!isPathSkiaSafe(getCTM(), path)) + return; + + platformContext()->canvas()->clipPath(path, SkRegion::kDifference_Op); +} + +void GraphicsContext::clipOutEllipseInRect(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + SkRect oval(rect); + if (!isRectSkiaSafe(getCTM(), oval)) + return; + + SkPath path; + path.addOval(oval, SkPath::kCCW_Direction); + platformContext()->canvas()->clipPath(path, SkRegion::kDifference_Op); +} + +void GraphicsContext::clipPath(WindRule clipRule) +{ + if (paintingDisabled()) + return; + + const SkPath* oldPath = platformContext()->currentPath(); + SkPath path(*oldPath); + path.setFillType(clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType); + platformContext()->canvas()->clipPath(path); +} + +void GraphicsContext::clipToImageBuffer(const FloatRect& rect, + const ImageBuffer* imageBuffer) +{ + if (paintingDisabled()) + return; + + // FIXME: This is needed for image masking and complex text fills. + notImplemented(); +} + +void GraphicsContext::concatCTM(const TransformationMatrix& xform) +{ + if (paintingDisabled()) + return; + platformContext()->canvas()->concat(xform); +} + +void GraphicsContext::drawConvexPolygon(size_t numPoints, + const FloatPoint* points, + bool shouldAntialias) +{ + if (paintingDisabled()) + return; + + if (numPoints <= 1) + return; + + SkPath path; + + path.incReserve(numPoints); + path.moveTo(WebCoreFloatToSkScalar(points[0].x()), + WebCoreFloatToSkScalar(points[0].y())); + for (size_t i = 1; i < numPoints; i++) { + path.lineTo(WebCoreFloatToSkScalar(points[i].x()), + WebCoreFloatToSkScalar(points[i].y())); + } + + if (!isPathSkiaSafe(getCTM(), path)) + return; + + SkPaint paint; + if (fillColor().alpha() > 0) { + platformContext()->setupPaintForFilling(&paint); + platformContext()->canvas()->drawPath(path, paint); + } + + if (strokeStyle() != NoStroke) { + paint.reset(); + platformContext()->setupPaintForStroking(&paint, 0, 0); + platformContext()->canvas()->drawPath(path, paint); + } +} + +// This method is only used to draw the little circles used in lists. +void GraphicsContext::drawEllipse(const IntRect& elipseRect) +{ + if (paintingDisabled()) + return; + + SkRect rect = elipseRect; + if (!isRectSkiaSafe(getCTM(), rect)) + return; + + SkPaint paint; + if (fillColor().alpha() > 0) { + platformContext()->setupPaintForFilling(&paint); + platformContext()->canvas()->drawOval(rect, paint); + } + + if (strokeStyle() != NoStroke) { + paint.reset(); + platformContext()->setupPaintForStroking(&paint, &rect, 0); + platformContext()->canvas()->drawOval(rect, paint); + } +} + +void GraphicsContext::drawFocusRing(const Color& color) +{ + if (paintingDisabled()) + return; + + const Vector<IntRect>& rects = focusRingRects(); + unsigned rectCount = rects.size(); + if (0 == rectCount) + return; + + SkRegion focusRingRegion; + const SkScalar focusRingOutset = WebCoreFloatToSkScalar(0.5); + for (unsigned i = 0; i < rectCount; i++) { + SkIRect r = rects[i]; + r.inset(-focusRingOutset, -focusRingOutset); + focusRingRegion.op(r, SkRegion::kUnion_Op); + } + + SkPath path; + SkPaint paint; + paint.setAntiAlias(true); + paint.setStyle(SkPaint::kStroke_Style); + + paint.setColor(focusRingColor().rgb()); + paint.setStrokeWidth(focusRingOutset * 2); + paint.setPathEffect(new SkCornerPathEffect(focusRingOutset * 2))->unref(); + focusRingRegion.getBoundaryPath(&path); + platformContext()->canvas()->drawPath(path, paint); +} + +// This is only used to draw borders. +void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) +{ + if (paintingDisabled()) + return; + + StrokeStyle penStyle = strokeStyle(); + if (penStyle == NoStroke) + return; + + SkPaint paint; + SkPoint pts[2] = { (SkPoint)point1, (SkPoint)point2 }; + if (!isPointSkiaSafe(getCTM(), pts[0]) || !isPointSkiaSafe(getCTM(), pts[1])) + return; + + // 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); + int width = roundf( + platformContext()->setupPaintForStroking(&paint, 0, length)); + + // "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. + bool isVerticalLine = pts[0].fX == pts[1].fX; + + 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); +} + +void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& pt, + int width, + bool grammar) +{ + if (paintingDisabled()) + return; + + // Create the pattern we'll use to draw the underline. + static SkBitmap* misspellBitmap = 0; + if (!misspellBitmap) { + // We use a 2-pixel-high misspelling indicator because that seems to be + // what WebKit is designed for, and how much room there is in a typical + // page for it. + const int rowPixels = 32; // Must be multiple of 4 for pattern below. + const int colPixels = 2; + misspellBitmap = new SkBitmap; + misspellBitmap->setConfig(SkBitmap::kARGB_8888_Config, + rowPixels, colPixels); + misspellBitmap->allocPixels(); + + misspellBitmap->eraseARGB(0, 0, 0, 0); + const uint32_t lineColor = 0xFFFF0000; // Opaque red. + const uint32_t antiColor = 0x60600000; // Semitransparent red. + + // Pattern: X o o X o o X + // o X o o X o + uint32_t* row1 = misspellBitmap->getAddr32(0, 0); + uint32_t* row2 = misspellBitmap->getAddr32(0, 1); + for (int x = 0; x < rowPixels; x++) { + switch (x % 4) { + case 0: + row1[x] = lineColor; + break; + case 1: + row1[x] = antiColor; + row2[x] = antiColor; + break; + case 2: + row2[x] = lineColor; + break; + case 3: + row1[x] = antiColor; + row2[x] = antiColor; + break; + } + } + } + + // Offset it vertically by 1 so that there's some space under the text. + SkScalar originX = SkIntToScalar(pt.x()); + SkScalar originY = SkIntToScalar(pt.y()) + 1; + + // Make a shader for the bitmap with an origin of the box we'll draw. This + // shader is refcounted and will have an initial refcount of 1. + SkShader* shader = SkShader::CreateBitmapShader( + *misspellBitmap, SkShader::kRepeat_TileMode, + SkShader::kRepeat_TileMode); + SkMatrix matrix; + matrix.reset(); + matrix.postTranslate(originX, originY); + shader->setLocalMatrix(matrix); + + // Assign the shader to the paint & release our reference. The paint will + // now own the shader and the shader will be destroyed when the paint goes + // out of scope. + SkPaint paint; + paint.setShader(shader); + shader->unref(); + + SkRect rect; + rect.set(originX, + originY, + originX + SkIntToScalar(width), + originY + SkIntToScalar(misspellBitmap->height())); + platformContext()->canvas()->drawRect(rect, paint); +} + +void GraphicsContext::drawLineForText(const IntPoint& pt, + int width, + bool printing) +{ + if (paintingDisabled()) + return; + + int thickness = SkMax32(static_cast<int>(strokeThickness()), 1); + SkRect r; + r.fLeft = SkIntToScalar(pt.x()); + r.fTop = SkIntToScalar(pt.y()); + r.fRight = r.fLeft + SkIntToScalar(width); + r.fBottom = r.fTop + SkIntToScalar(thickness); + + SkPaint paint; + paint.setColor(strokeColor().rgb()); + platformContext()->canvas()->drawRect(r, paint); +} + +// Draws a filled rectangle with a stroked border. +void GraphicsContext::drawRect(const IntRect& rect) +{ + if (paintingDisabled()) + return; + + SkRect r = rect; + if (!isRectSkiaSafe(getCTM(), r)) + // See the fillRect below. + ClipRectToCanvas(*platformContext()->canvas(), r, &r); + + platformContext()->drawRect(r); +} + +void GraphicsContext::fillPath() +{ + if (paintingDisabled()) + return; + + const SkPath& path = *platformContext()->currentPath(); + if (!isPathSkiaSafe(getCTM(), path)) + return; + + const GraphicsContextState& state = m_common->state; + ColorSpace colorSpace = state.fillColorSpace; + + if (colorSpace == SolidColorSpace && !fillColor().alpha()) + return; + + platformContext()->setFillRule(state.fillRule == RULE_EVENODD ? + SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType); + + SkPaint paint; + platformContext()->setupPaintForFilling(&paint); + + if (colorSpace == PatternColorSpace) { + SkShader* pat = state.fillPattern->createPlatformPattern(getCTM()); + paint.setShader(pat); + pat->unref(); + } else if (colorSpace == GradientColorSpace) + paint.setShader(state.fillGradient->platformGradient()); + + platformContext()->canvas()->drawPath(path, paint); +} + +void GraphicsContext::fillRect(const FloatRect& rect) +{ + if (paintingDisabled()) + return; + + SkRect r = rect; + if (!isRectSkiaSafe(getCTM(), r)) + // See the other version of fillRect below. + ClipRectToCanvas(*platformContext()->canvas(), r, &r); + + const GraphicsContextState& state = m_common->state; + ColorSpace colorSpace = state.fillColorSpace; + + if (colorSpace == SolidColorSpace && !fillColor().alpha()) + return; + + SkPaint paint; + platformContext()->setupPaintForFilling(&paint); + + if (colorSpace == PatternColorSpace) { + SkShader* pat = state.fillPattern->createPlatformPattern(getCTM()); + paint.setShader(pat); + pat->unref(); + } else if (colorSpace == GradientColorSpace) + paint.setShader(state.fillGradient->platformGradient()); + + platformContext()->canvas()->drawRect(r, paint); +} + +void GraphicsContext::fillRect(const FloatRect& rect, const Color& color) +{ + if (paintingDisabled()) + return; + + if (!color.alpha()) + return; + + SkRect r = rect; + if (!isRectSkiaSafe(getCTM(), r)) { + // Special case when the rectangle overflows fixed point. This is a + // workaround to fix bug 1212844. When the input rectangle is very + // large, it can overflow Skia's internal fixed point rect. This + // should be fixable in Skia (since the output bitmap isn't that + // large), but until that is fixed, we try to handle it ourselves. + // + // We manually clip the rectangle to the current clip rect. This + // will prevent overflow. The rectangle will be transformed to the + // canvas' coordinate space before it is converted to fixed point + // so we are guaranteed not to overflow after doing this. + ClipRectToCanvas(*platformContext()->canvas(), r, &r); + } + + SkPaint paint; + platformContext()->setupPaintCommon(&paint); + paint.setColor(color.rgb()); + platformContext()->canvas()->drawRect(r, paint); +} + +void GraphicsContext::fillRoundedRect(const IntRect& rect, + const IntSize& topLeft, + const IntSize& topRight, + const IntSize& bottomLeft, + const IntSize& bottomRight, + const Color& color) +{ + if (paintingDisabled()) + return; + + SkRect r = rect; + if (!isRectSkiaSafe(getCTM(), r)) + // See fillRect(). + ClipRectToCanvas(*platformContext()->canvas(), r, &r); + + SkPath path; + addCornerArc(&path, r, topRight, 270); + addCornerArc(&path, r, bottomRight, 0); + addCornerArc(&path, r, bottomLeft, 90); + addCornerArc(&path, r, topLeft, 180); + + SkPaint paint; + platformContext()->setupPaintForFilling(&paint); + platformContext()->canvas()->drawPath(path, paint); + return fillRect(rect, color); +} + +TransformationMatrix GraphicsContext::getCTM() const +{ + return platformContext()->canvas()->getTotalMatrix(); +} + +FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect) +{ + // This logic is copied from GraphicsContextCG, eseidel 5/05/08 + + // 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 we get the affine transform matrix and + // extract the scale. + + const SkMatrix& deviceMatrix = platformContext()->canvas()->getTotalMatrix(); + if (deviceMatrix.isIdentity()) + return rect; + + float deviceScaleX = sqrtf(square(deviceMatrix.getScaleX()) + + square(deviceMatrix.getSkewY())); + float deviceScaleY = sqrtf(square(deviceMatrix.getSkewX()) + + square(deviceMatrix.getScaleY())); + + FloatPoint deviceOrigin(rect.x() * deviceScaleX, rect.y() * deviceScaleY); + FloatPoint deviceLowerRight((rect.x() + rect.width()) * deviceScaleX, + (rect.y() + rect.height()) * deviceScaleY); + + deviceOrigin.setX(roundf(deviceOrigin.x())); + deviceOrigin.setY(roundf(deviceOrigin.y())); + deviceLowerRight.setX(roundf(deviceLowerRight.x())); + 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) + deviceLowerRight.move(0, 1); + if (deviceOrigin.x() == deviceLowerRight.x() && rect.width() != 0) + deviceLowerRight.move(1, 0); + + FloatPoint roundedOrigin(deviceOrigin.x() / deviceScaleX, + deviceOrigin.y() / deviceScaleY); + FloatPoint roundedLowerRight(deviceLowerRight.x() / deviceScaleX, + deviceLowerRight.y() / deviceScaleY); + return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin); +} + +void GraphicsContext::scale(const FloatSize& size) +{ + if (paintingDisabled()) + return; + platformContext()->canvas()->scale(WebCoreFloatToSkScalar(size.width()), + WebCoreFloatToSkScalar(size.height())); +} + +void GraphicsContext::setAlpha(float alpha) +{ + if (paintingDisabled()) + return; + platformContext()->setAlpha(alpha); +} + +void GraphicsContext::setCompositeOperation(CompositeOperator op) +{ + if (paintingDisabled()) + return; + platformContext()->setPorterDuffMode(WebCoreCompositeToSkiaComposite(op)); +} + +void GraphicsContext::setImageInterpolationQuality(InterpolationQuality) +{ + notImplemented(); +} + +void GraphicsContext::setLineCap(LineCap cap) +{ + if (paintingDisabled()) + return; + switch (cap) { + case ButtCap: + platformContext()->setLineCap(SkPaint::kButt_Cap); + break; + case RoundCap: + platformContext()->setLineCap(SkPaint::kRound_Cap); + break; + case SquareCap: + platformContext()->setLineCap(SkPaint::kSquare_Cap); + break; + default: + ASSERT(0); + break; + } +} + +void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) +{ + if (paintingDisabled()) + return; + + // FIXME: This is lifted directly off SkiaSupport, lines 49-74 + // so it is not guaranteed to work correctly. + size_t dashLength = dashes.size(); + if (!dashLength) + return; + + size_t count = (dashLength % 2) == 0 ? dashLength : dashLength * 2; + SkScalar* intervals = new SkScalar[count]; + + for (unsigned int i = 0; i < count; i++) + intervals[i] = dashes[i % dashLength]; + + platformContext()->setDashPathEffect(new SkDashPathEffect(intervals, count, dashOffset)); + + delete[] intervals; +} + +void GraphicsContext::setLineJoin(LineJoin join) +{ + if (paintingDisabled()) + return; + switch (join) { + case MiterJoin: + platformContext()->setLineJoin(SkPaint::kMiter_Join); + break; + case RoundJoin: + platformContext()->setLineJoin(SkPaint::kRound_Join); + break; + case BevelJoin: + platformContext()->setLineJoin(SkPaint::kBevel_Join); + break; + default: + ASSERT(0); + break; + } +} + +void GraphicsContext::setMiterLimit(float limit) +{ + if (paintingDisabled()) + return; + platformContext()->setMiterLimit(limit); +} + +void GraphicsContext::setPlatformFillColor(const Color& color) +{ + if (paintingDisabled()) + return; + platformContext()->setFillColor(color.rgb()); +} + +void GraphicsContext::setPlatformShadow(const IntSize& size, + int blurInt, + const Color& color) +{ + if (paintingDisabled()) + return; + + double width = size.width(); + double height = size.height(); + double blur = blurInt; + + // TODO(tc): This still does not address the issue that shadows + // within canvas elements should ignore transforms. + if (m_common->state.shadowsIgnoreTransforms) { + // Currently only the GraphicsContext associated with the + // CanvasRenderingContext for HTMLCanvasElement have shadows ignore + // Transforms. So with this flag set, we know this state is associated + // with a CanvasRenderingContext. + // CG uses natural orientation for Y axis, but the HTML5 canvas spec + // does not. + // So we now flip the height since it was flipped in + // CanvasRenderingContext in order to work with CG. + height = -height; + } + + SkColor c; + if (color.isValid()) + c = color.rgb(); + else + c = SkColorSetARGB(0xFF/3, 0, 0, 0); // "std" apple shadow color. + + // TODO(tc): Should we have a max value for the blur? CG clamps at 1000.0 + // for perf reasons. + SkDrawLooper* dl = new SkBlurDrawLooper(blur / 2, width, height, c); + platformContext()->setDrawLooper(dl); + dl->unref(); +} + +void GraphicsContext::setPlatformStrokeColor(const Color& strokecolor) +{ + if (paintingDisabled()) + return; + + platformContext()->setStrokeColor(strokecolor.rgb()); +} + +void GraphicsContext::setPlatformStrokeStyle(const StrokeStyle& stroke) +{ + if (paintingDisabled()) + return; + + platformContext()->setStrokeStyle(stroke); +} + +void GraphicsContext::setPlatformStrokeThickness(float thickness) +{ + if (paintingDisabled()) + return; + + platformContext()->setStrokeThickness(thickness); +} + +void GraphicsContext::setPlatformTextDrawingMode(int mode) +{ + if (paintingDisabled()) + return; + + platformContext()->setTextDrawingMode(mode); +} + +void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect) +{ +} + +void GraphicsContext::setPlatformShouldAntialias(bool enable) +{ + if (paintingDisabled()) + return; + + platformContext()->setUseAntialiasing(enable); +} + +void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan) +{ + if (paintingDisabled()) + return; + + SkPaint paint; + SkRect oval = r; + if (strokeStyle() == NoStroke) { + // Stroke using the fill color. + // TODO(brettw) is this really correct? It seems unreasonable. + platformContext()->setupPaintForFilling(&paint); + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(WebCoreFloatToSkScalar(strokeThickness())); + } else + platformContext()->setupPaintForStroking(&paint, 0, 0); + + // We do this before converting to scalar, so we don't overflow SkFixed. + startAngle = fastMod(startAngle, 360); + angleSpan = fastMod(angleSpan, 360); + + SkPath path; + path.addArc(oval, SkIntToScalar(-startAngle), SkIntToScalar(-angleSpan)); + if (!isPathSkiaSafe(getCTM(), path)) + return; + platformContext()->canvas()->drawPath(path, paint); +} + +void GraphicsContext::strokePath() +{ + if (paintingDisabled()) + return; + + const SkPath& path = *platformContext()->currentPath(); + if (!isPathSkiaSafe(getCTM(), path)) + return; + + const GraphicsContextState& state = m_common->state; + ColorSpace colorSpace = state.strokeColorSpace; + + if (colorSpace == SolidColorSpace && !strokeColor().alpha()) + return; + + SkPaint paint; + platformContext()->setupPaintForStroking(&paint, 0, 0); + + if (colorSpace == PatternColorSpace) { + SkShader* pat = state.strokePattern->createPlatformPattern(getCTM()); + paint.setShader(pat); + pat->unref(); + } else if (colorSpace == GradientColorSpace) + paint.setShader(state.strokeGradient->platformGradient()); + + platformContext()->canvas()->drawPath(path, paint); +} + +void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) +{ + if (paintingDisabled()) + return; + + if (!isRectSkiaSafe(getCTM(), rect)) + return; + + const GraphicsContextState& state = m_common->state; + ColorSpace colorSpace = state.strokeColorSpace; + + if (colorSpace == SolidColorSpace && !strokeColor().alpha()) + return; + + SkPaint paint; + platformContext()->setupPaintForStroking(&paint, 0, 0); + paint.setStrokeWidth(WebCoreFloatToSkScalar(lineWidth)); + + if (colorSpace == PatternColorSpace) { + SkShader* pat = state.strokePattern->createPlatformPattern(getCTM()); + paint.setShader(pat); + pat->unref(); + } else if (colorSpace == GradientColorSpace) + paint.setShader(state.strokeGradient->platformGradient()); + + platformContext()->canvas()->drawRect(rect, paint); +} + +void GraphicsContext::rotate(float angleInRadians) +{ + if (paintingDisabled()) + return; + + platformContext()->canvas()->rotate(WebCoreFloatToSkScalar( + angleInRadians * (180.0f / 3.14159265f))); +} + +void GraphicsContext::translate(float w, float h) +{ + if (paintingDisabled()) + return; + + platformContext()->canvas()->translate(WebCoreFloatToSkScalar(w), + WebCoreFloatToSkScalar(h)); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/skia/ImageBufferSkia.cpp b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp new file mode 100644 index 0000000..fdfcb85 --- /dev/null +++ b/WebCore/platform/graphics/skia/ImageBufferSkia.cpp @@ -0,0 +1,210 @@ +/* + * 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 "ImageBuffer.h" + +#include "BitmapImage.h" +#include "BitmapImageSingleFrameSkia.h" +#include "GraphicsContext.h" +#include "ImageData.h" +#include "NotImplemented.h" +#include "PlatformContextSkia.h" +#include "SkiaUtils.h" + +using namespace std; + +namespace WebCore { + +// We pass a technically-uninitialized canvas to the platform context here since +// the canvas initialization completes in ImageBuffer::ImageBuffer. But +// PlatformContext doesn't actually need to use the object, and this makes all +// the ownership easier to manage. +ImageBufferData::ImageBufferData(const IntSize& size) + : m_platformContext(0) // Canvas is set in ImageBuffer constructor. +{ +} + +ImageBuffer::ImageBuffer(const IntSize& size, bool grayScale, bool& success) + : m_data(size) + , m_size(size) +{ + if (!m_data.m_canvas.initialize(size.width(), size.height(), false)) { + success = false; + return; + } + + m_data.m_platformContext.setCanvas(&m_data.m_canvas); + m_context.set(new GraphicsContext(&m_data.m_platformContext)); + + // Make the background transparent. It would be nice if this wasn't + // required, but the canvas is currently filled with the magic transparency + // color. Can we have another way to manage this? + m_data.m_canvas.drawARGB(0, 0, 0, 0, SkPorterDuff::kClear_Mode); + success = true; +} + +ImageBuffer::~ImageBuffer() +{ +} + +GraphicsContext* ImageBuffer::context() const +{ + return m_context.get(); +} + +Image* ImageBuffer::image() const +{ + if (!m_image) { + // This creates a COPY of the image and will cache that copy. This means + // that if subsequent operations take place on the context, neither the + // currently-returned image, nor the results of future image() calls, + // will contain that operation. + // + // This seems silly, but is the way the CG port works: image() is + // intended to be used only when rendering is "complete." + m_image = BitmapImageSingleFrameSkia::create( + *m_data.m_platformContext.bitmap()); + } + return m_image.get(); +} + +PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const +{ + ASSERT(context()); + + RefPtr<ImageData> result = ImageData::create(rect.width(), rect.height()); + unsigned char* data = result->data()->data(); + + if (rect.x() < 0 || rect.y() < 0 || + (rect.x() + rect.width()) > m_size.width() || + (rect.y() + rect.height()) > m_size.height()) + memset(data, 0, result->data()->length()); + + int originX = rect.x(); + int destX = 0; + if (originX < 0) { + destX = -originX; + originX = 0; + } + int endX = rect.x() + rect.width(); + if (endX > m_size.width()) + endX = m_size.width(); + int numColumns = endX - originX; + + int originY = rect.y(); + int destY = 0; + if (originY < 0) { + destY = -originY; + originY = 0; + } + int endY = rect.y() + rect.height(); + if (endY > m_size.height()) + endY = m_size.height(); + int numRows = endY - originY; + + const SkBitmap& bitmap = *context()->platformContext()->bitmap(); + ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); + SkAutoLockPixels bitmapLock(bitmap); + + unsigned destBytesPerRow = 4 * rect.width(); + unsigned char* destRow = data + destY * destBytesPerRow + destX * 4; + + 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); + } + destRow += destBytesPerRow; + } + + return result; +} + +void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, + const IntPoint& destPoint) +{ + ASSERT(sourceRect.width() > 0); + ASSERT(sourceRect.height() > 0); + + int originX = sourceRect.x(); + int destX = destPoint.x() + sourceRect.x(); + ASSERT(destX >= 0); + ASSERT(destX < m_size.width()); + ASSERT(originX >= 0); + ASSERT(originX < sourceRect.right()); + + int endX = destPoint.x() + sourceRect.right(); + ASSERT(endX <= m_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(originY >= 0); + ASSERT(originY < sourceRect.bottom()); + + int endY = destPoint.y() + sourceRect.bottom(); + ASSERT(endY <= m_size.height()); + int numRows = endY - destY; + + const SkBitmap& bitmap = *context()->platformContext()->bitmap(); + ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); + SkAutoLockPixels bitmapLock(bitmap); + + unsigned srcBytesPerRow = 4 * source->width(); + + const unsigned char* srcRow = source->data()->data() + originY * srcBytesPerRow + originX * 4; + + for (int y = 0; y < numRows; ++y) { + 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]); + } + srcRow += srcBytesPerRow; + } +} + +String ImageBuffer::toDataURL(const String&) const +{ + notImplemented(); + return String(); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/skia/ImageSkia.cpp b/WebCore/platform/graphics/skia/ImageSkia.cpp new file mode 100644 index 0000000..1123fe9 --- /dev/null +++ b/WebCore/platform/graphics/skia/ImageSkia.cpp @@ -0,0 +1,462 @@ +/* + * 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 "BitmapImage.h" +#include "BitmapImageSingleFrameSkia.h" +#include "ChromiumBridge.h" +#include "FloatConversion.h" +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "Logging.h" +#include "NativeImageSkia.h" +#include "NotImplemented.h" +#include "PlatformContextSkia.h" +#include "PlatformString.h" +#include "SkiaUtils.h" +#include "SkShader.h" +#include "TransformationMatrix.h" + +#include "skia/ext/image_operations.h" +#include "skia/ext/platform_canvas.h" + +namespace WebCore { + +// Used by computeResamplingMode to tell how bitmaps should be resampled. +enum ResamplingMode { + // Nearest neighbor resampling. Used when we detect that the page is + // trying to make a pattern by stretching a small bitmap very large. + RESAMPLE_NONE, + + // Default skia resampling. Used for large growing of images where high + // quality resampling doesn't get us very much except a slowdown. + RESAMPLE_LINEAR, + + // High quality resampling. + RESAMPLE_AWESOME, +}; + +static ResamplingMode computeResamplingMode(const NativeImageSkia& bitmap, int srcWidth, int srcHeight, float destWidth, float destHeight) +{ + int destIWidth = static_cast<int>(destWidth); + int destIHeight = static_cast<int>(destHeight); + + // The percent change below which we will not resample. This usually means + // an off-by-one error on the web page, and just doing nearest neighbor + // sampling is usually good enough. + const float kFractionalChangeThreshold = 0.025f; + + // Images smaller than this in either direction are considered "small" and + // are not resampled ever (see below). + const int kSmallImageSizeThreshold = 8; + + // The amount an image can be stretched in a single direction before we + // say that it is being stretched so much that it must be a line or + // background that doesn't need resampling. + const float kLargeStretch = 3.0f; + + // Figure out if we should resample this image. We try to prune out some + // common cases where resampling won't give us anything, since it is much + // slower than drawing stretched. + if (srcWidth == destIWidth && srcHeight == destIHeight) { + // We don't need to resample if the source and destination are the same. + return RESAMPLE_NONE; + } + + if (srcWidth <= kSmallImageSizeThreshold + || srcHeight <= kSmallImageSizeThreshold + || destWidth <= kSmallImageSizeThreshold + || destHeight <= kSmallImageSizeThreshold) { + // Never resample small images. These are often used for borders and + // rules (think 1x1 images used to make lines). + return RESAMPLE_NONE; + } + + if (srcHeight * kLargeStretch <= destHeight || srcWidth * kLargeStretch <= destWidth) { + // Large image detected. + + // Don't resample if it is being stretched a lot in only one direction. + // This is trying to catch cases where somebody has created a border + // (which might be large) and then is stretching it to fill some part + // of the page. + if (srcWidth == destWidth || srcHeight == destHeight) + return RESAMPLE_NONE; + + // The image is growing a lot and in more than one direction. Resampling + // is slow and doesn't give us very much when growing a lot. + return RESAMPLE_LINEAR; + } + + if ((fabs(destWidth - srcWidth) / srcWidth < kFractionalChangeThreshold) + && (fabs(destHeight - srcHeight) / srcHeight < kFractionalChangeThreshold)) { + // It is disappointingly common on the web for image sizes to be off by + // one or two pixels. We don't bother resampling if the size difference + // is a small fraction of the original size. + return RESAMPLE_NONE; + } + + // When the image is not yet done loading, use linear. We don't cache the + // partially resampled images, and as they come in incrementally, it causes + // us to have to resample the whole thing every time. + if (!bitmap.isDataComplete()) + return RESAMPLE_LINEAR; + + // Everything else gets resampled. + return RESAMPLE_AWESOME; +} + +// Draws the given bitmap to the given canvas. The subset of the source bitmap +// identified by src_rect is drawn to the given destination rect. The bitmap +// will be resampled to resample_width * resample_height (this is the size of +// the whole image, not the subset). See shouldResampleBitmap for more. +// +// This does a lot of computation to resample only the portion of the bitmap +// that will only be drawn. This is critical for performance since when we are +// scrolling, for example, we are only drawing a small strip of the image. +// Resampling the whole image every time is very slow, so this speeds up things +// dramatically. +static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeImageSkia& bitmap, const SkIRect& srcIRect, const SkRect& destRect) +{ + // First get the subset we need. This is efficient and does not copy pixels. + SkBitmap subset; + bitmap.extractSubset(&subset, srcIRect); + SkRect srcRect; + srcRect.set(srcIRect); + + // Whether we're doing a subset or using the full source image. + bool srcIsFull = srcIRect.fLeft == 0 && srcIRect.fTop == 0 + && srcIRect.width() == bitmap.width() + && srcIRect.height() == bitmap.height(); + + // 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()); + + if (srcIsFull && bitmap.hasResizedBitmap(destRectRounded.width(), destRectRounded.height())) { + // Yay, this bitmap frame already has a resized version. + SkBitmap resampled = bitmap.resizedBitmap(destRectRounded.width(), destRectRounded.height()); + canvas.drawBitmapRect(resampled, 0, destRect, &paint); + return; + } + + // Compute the visible portion of our rect. + SkRect destBitmapSubsetSk; + ClipRectToCanvas(canvas, destRect, &destBitmapSubsetSk); + destBitmapSubsetSk.offset(-destRect.fLeft, -destRect.fTop); + + // The matrix inverting, etc. could have introduced rounding error which + // causes the bounds to be outside of the resized bitmap. We round outward + // so we always lean toward it being larger rather than smaller than we + // need, and then clamp to the bitmap bounds so we don't get any invalid + // data. + SkIRect destBitmapSubsetSkI; + destBitmapSubsetSk.roundOut(&destBitmapSubsetSkI); + if (!destBitmapSubsetSkI.intersect(resizedImageRect)) + return; // Resized image does not intersect. + + if (srcIsFull && bitmap.shouldCacheResampling( + resizedImageRect.width(), + resizedImageRect.height(), + destBitmapSubsetSkI.width(), + destBitmapSubsetSkI.height())) { + // We're supposed to resize the entire image and cache it, even though + // we don't need all of it. + SkBitmap resampled = bitmap.resizedBitmap(destRectRounded.width(), + destRectRounded.height()); + canvas.drawBitmapRect(resampled, 0, destRect, &paint); + } 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); + + // 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 }; + + canvas.drawBitmapRect(resampled, 0, offsetDestRect, &paint); + } +} + +static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, const SkIRect& srcRect, const SkRect& destRect, const SkPorterDuff::Mode& compOp) +{ + SkPaint paint; + paint.setPorterDuffXfermode(compOp); + + skia::PlatformCanvas* canvas = platformContext->canvas(); + + ResamplingMode resampling = platformContext->isPrinting() ? RESAMPLE_NONE : + computeResamplingMode(bitmap, srcRect.width(), srcRect.height(), + SkScalarToFloat(destRect.width()), + SkScalarToFloat(destRect.height())); + if (resampling == RESAMPLE_AWESOME) { + paint.setFilterBitmap(false); + drawResampledBitmap(*canvas, paint, bitmap, srcRect, destRect); + } else { + // No resampling necessary, we can just draw the bitmap. We want to + // filter it if we decided to do linear interpolation above, or if there + // is something interesting going on with the matrix (like a rotation). + // Note: for serialization, we will want to subset the bitmap first so + // we don't send extra pixels. + paint.setFilterBitmap(resampling == RESAMPLE_LINEAR); + canvas->drawBitmapRect(bitmap, &srcRect, destRect, &paint); + } +} + +// Transforms the given dimensions with the given matrix. Used to see how big +// images will be once transformed. +static void TransformDimensions(const SkMatrix& matrix, float srcWidth, float srcHeight, float* destWidth, float* destHeight) { + // Transform 3 points to see how long each side of the bitmap will be. + SkPoint src_points[3]; // (0, 0), (width, 0), (0, height). + src_points[0].set(0, 0); + src_points[1].set(SkFloatToScalar(srcWidth), 0); + src_points[2].set(0, SkFloatToScalar(srcHeight)); + + // Now measure the length of the two transformed vectors relative to the + // transformed origin to see how big the bitmap will be. Note: for skews, + // this isn't the best thing, but we don't have skews. + SkPoint dest_points[3]; + matrix.mapPoints(dest_points, src_points, 3); + *destWidth = SkScalarToFloat((dest_points[1] - dest_points[0]).length()); + *destHeight = SkScalarToFloat((dest_points[2] - dest_points[0]).length()); +} + +// A helper method for translating negative width and height values. +static FloatRect normalizeRect(const FloatRect& rect) +{ + FloatRect norm = rect; + if (norm.width() < 0) { + norm.setX(norm.x() + norm.width()); + norm.setWidth(-norm.width()); + } + if (norm.height() < 0) { + norm.setY(norm.y() + norm.height()); + norm.setHeight(-norm.height()); + } + return norm; +} + +bool FrameData::clear(bool clearMetadata) +{ + if (clearMetadata) + m_haveMetadata = false; + + if (m_frame) { + // ImageSource::createFrameAtIndex() allocated |m_frame| and passed + // ownership to BitmapImage; we must delete it here. + delete m_frame; + m_frame = 0; + return true; + } + return false; +} + +PassRefPtr<Image> Image::loadPlatformResource(const char *name) +{ + return ChromiumBridge::loadPlatformImageResource(name); +} + +void Image::drawPattern(GraphicsContext* context, + const FloatRect& floatSrcRect, + const TransformationMatrix& patternTransform, + const FloatPoint& phase, + CompositeOperator compositeOp, + const FloatRect& destRect) +{ + if (destRect.isEmpty() || floatSrcRect.isEmpty()) + return; // nothing to draw + + NativeImageSkia* bitmap = nativeImageForCurrentFrame(); + if (!bitmap) + return; + + // This is a very inexpensive operation. It will generate a new bitmap but + // it will internally reference the old bitmap's pixels, adjusting the row + // stride so the extra pixels appear as padding to the subsetted bitmap. + SkBitmap srcSubset; + SkIRect srcRect = enclosingIntRect(floatSrcRect); + bitmap->extractSubset(&srcSubset, srcRect); + + SkBitmap resampled; + SkShader* shader; + + // Figure out what size the bitmap will be in the destination. The + // destination rect is the bounds of the pattern, we need to use the + // matrix to see how bit it will be. + float destBitmapWidth, destBitmapHeight; + TransformDimensions(patternTransform, srcRect.width(), srcRect.height(), + &destBitmapWidth, &destBitmapHeight); + + // Compute the resampling mode. + ResamplingMode resampling; + if (context->platformContext()->isPrinting()) + resampling = RESAMPLE_LINEAR; + else { + resampling = computeResamplingMode(*bitmap, + srcRect.width(), srcRect.height(), + destBitmapWidth, destBitmapHeight); + } + + // Load the transform WebKit requested. + SkMatrix matrix(patternTransform); + + if (resampling == RESAMPLE_AWESOME) { + // Do nice resampling. + SkBitmap resampled = skia::ImageOperations::Resize(srcSubset, + skia::ImageOperations::RESIZE_LANCZOS3, + static_cast<int>(destBitmapWidth), + static_cast<int>(destBitmapHeight)); + shader = SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); + + // Since we just resized the bitmap, we need to undo the scale set in + // the image transform. + matrix.setScaleX(SkIntToScalar(1)); + matrix.setScaleY(SkIntToScalar(1)); + } else { + // No need to do nice resampling. + shader = SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); + } + + // We also need to translate it such that the origin of the pattern is the + // origin of the destination rect, which is what WebKit expects. Skia uses + // the coordinate system origin as the base for the patter. If WebKit wants + // a shifted image, it will shift it from there using the patternTransform. + float adjustedX = phase.x() + floatSrcRect.x() * + narrowPrecisionToFloat(patternTransform.a()); + float adjustedY = phase.y() + floatSrcRect.y() * + narrowPrecisionToFloat(patternTransform.d()); + matrix.postTranslate(SkFloatToScalar(adjustedX), + SkFloatToScalar(adjustedY)); + shader->setLocalMatrix(matrix); + + SkPaint paint; + paint.setShader(shader)->unref(); + paint.setPorterDuffXfermode(WebCoreCompositeToSkiaComposite(compositeOp)); + paint.setFilterBitmap(resampling == RESAMPLE_LINEAR); + + context->platformContext()->paintSkPaint(destRect, paint); +} + +// ================================================ +// BitmapImage Class +// ================================================ + +// FIXME: These should go to BitmapImageSkia.cpp + +void BitmapImage::initPlatformData() +{ + // This is not used. On Mac, the "platform" data is a cache of some OS + // specific versions of the image that are created is some cases. These + // aren't normally used, it is equivalent to getHBITMAP on Windows, and + // the platform data is the cache. +} + +void BitmapImage::invalidatePlatformData() +{ + // See initPlatformData above. +} + +void BitmapImage::checkForSolidColor() +{ +} + +void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, + const FloatRect& srcRect, CompositeOperator compositeOp) +{ + if (!m_source.initialized()) + return; + + // Spin the animation to the correct frame before we try to draw it, so we + // don't draw an old frame and then immediately need to draw a newer one, + // causing flicker and wasting CPU. + startAnimation(); + + const NativeImageSkia* bm = nativeImageForCurrentFrame(); + if (!bm) + return; // It's too early and we don't have an image yet. + + FloatRect normDstRect = normalizeRect(dstRect); + FloatRect normSrcRect = normalizeRect(srcRect); + + if (normSrcRect.isEmpty() || normDstRect.isEmpty()) + return; // Nothing to draw. + + paintSkBitmap(ctxt->platformContext(), + *bm, + enclosingIntRect(normSrcRect), + enclosingIntRect(normDstRect), + WebCoreCompositeToSkiaComposite(compositeOp)); +} + +// FIXME: These should go into BitmapImageSingleFrameSkia.cpp + +void BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt, + const FloatRect& dstRect, + const FloatRect& srcRect, + CompositeOperator compositeOp) +{ + FloatRect normDstRect = normalizeRect(dstRect); + FloatRect normSrcRect = normalizeRect(srcRect); + + if (normSrcRect.isEmpty() || normDstRect.isEmpty()) + return; // Nothing to draw. + + paintSkBitmap(ctxt->platformContext(), + m_nativeImage, + enclosingIntRect(normSrcRect), + enclosingIntRect(normDstRect), + WebCoreCompositeToSkiaComposite(compositeOp)); +} + +PassRefPtr<BitmapImageSingleFrameSkia> BitmapImageSingleFrameSkia::create(const SkBitmap& bitmap) +{ + RefPtr<BitmapImageSingleFrameSkia> image(adoptRef(new BitmapImageSingleFrameSkia())); + if (!bitmap.copyTo(&image->m_nativeImage, bitmap.config())) + return 0; + return image.release(); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/skia/ImageSourceSkia.cpp b/WebCore/platform/graphics/skia/ImageSourceSkia.cpp new file mode 100644 index 0000000..f77620b --- /dev/null +++ b/WebCore/platform/graphics/skia/ImageSourceSkia.cpp @@ -0,0 +1,247 @@ +/* + * 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 "ImageSourceSkia.h" +#include "SharedBuffer.h" + +#include "GIFImageDecoder.h" +#include "JPEGImageDecoder.h" +#include "PNGImageDecoder.h" +#include "BMPImageDecoder.h" +#include "XBMImageDecoder.h" +#include "ICOImageDecoder.h" + +#include "SkBitmap.h" + +namespace WebCore { + +ImageDecoder* createDecoder(const Vector<char>& data, const IntSize& preferredIconSize) +{ + // 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(preferredIconSize); + + // 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) +{ + // TODO(darin): Figure out what to do with the |data| and |allDataReceived| params. + + if (destroyAll) { + delete m_decoder; + m_decoder = 0; + return; + } + + if (m_decoder) + m_decoder->clearFrameBufferCache(clearBeforeFrame); +} + +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(), IntSize()); + + // 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) const +{ + // TODO(brettw) do we need anything here? + return size(); +} + +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. This pointer will be owned by the BitmapImage + // and freed in FrameData::clear(). + return new NativeImageSkia(buffer->bitmap()); +} + +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(); +} + +void ImageSourceSkia::setData(SharedBuffer* data, + bool allDataReceived, + const IntSize& preferredIconSize) +{ + if (!m_decoder) + m_decoder = createDecoder(data->buffer(), preferredIconSize); + + ImageSource::setData(data, allDataReceived); +} + +String ImageSource::filenameExtension() const +{ + return m_decoder ? m_decoder->filenameExtension() : String(); +} + +} diff --git a/WebCore/platform/graphics/skia/ImageSourceSkia.h b/WebCore/platform/graphics/skia/ImageSourceSkia.h new file mode 100644 index 0000000..9cb4a95 --- /dev/null +++ b/WebCore/platform/graphics/skia/ImageSourceSkia.h @@ -0,0 +1,60 @@ +/* + * 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 "ImageSource.h" + +namespace WebCore { + +class ImageSourceSkia : public ImageSource { +public: + // FIXME: This class is a hack to support Chromium's ICO decoder + // Currently our ICO decoder decodes all data during setData() instead of + // being lazy. In addition, it only decodes one frame (closest to the size + // passed to the decoder during createDecoder, called from setData) and + // discards all other data in the file. + // + // To fix this will require fixing the ICO decoder to be lazy, or to decode + // all frames. Apple's decoders (ImageIO) decode all frames, and return + // them all sorted in decreasing size. WebCore always draws the first frame. + // + // This is a special-purpose routine for the favicon decoder, which is used + // to specify a particular icon size for the ICOImageDecoder to prefer + // decoding. Note that not all favicons are ICOs, so this won't + // necessarily do anything differently than ImageSource::setData(). + // + // Passing an empty IntSize for |preferredIconSize| here is exactly + // equivalent to just calling ImageSource::setData(). See also comments in + // ICOImageDecoder.cpp. + void setData(SharedBuffer* data, + bool allDataReceived, + const IntSize& preferredIconSize); +}; + +} diff --git a/WebCore/platform/graphics/skia/IntPointSkia.cpp b/WebCore/platform/graphics/skia/IntPointSkia.cpp new file mode 100644 index 0000000..fd9a6fd --- /dev/null +++ b/WebCore/platform/graphics/skia/IntPointSkia.cpp @@ -0,0 +1,56 @@ +/* + * 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 "IntPoint.h" + +#include "SkPoint.h" + +namespace WebCore { + +IntPoint::IntPoint(const SkIPoint& p) + : m_x(p.fX) + , m_y(p.fY) +{ +} + +IntPoint::operator SkIPoint() const +{ + SkIPoint p = { m_x, m_y }; + return p; +} + +IntPoint::operator SkPoint() const +{ + SkPoint p = { SkIntToScalar(m_x), SkIntToScalar(m_y) }; + return p; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/skia/IntRectSkia.cpp b/WebCore/platform/graphics/skia/IntRectSkia.cpp new file mode 100644 index 0000000..ea138ee --- /dev/null +++ b/WebCore/platform/graphics/skia/IntRectSkia.cpp @@ -0,0 +1,57 @@ +/* + * 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 "IntRect.h" + +#include "SkRect.h" + +namespace WebCore { + +IntRect::operator SkIRect() const +{ + SkIRect rect = { x(), y(), right(), bottom() }; + return rect; +} + +IntRect::operator SkRect() const +{ + SkRect rect; + rect.set(SkIntToScalar(x()), SkIntToScalar(y()), SkIntToScalar(right()), SkIntToScalar(bottom())); + return rect; +} + +IntRect::IntRect(const SkIRect& r) + : m_location(r.fLeft, r.fTop) + , m_size(r.width(), r.height()) +{ +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/skia/NativeImageSkia.cpp b/WebCore/platform/graphics/skia/NativeImageSkia.cpp new file mode 100644 index 0000000..e59d1e2 --- /dev/null +++ b/WebCore/platform/graphics/skia/NativeImageSkia.cpp @@ -0,0 +1,109 @@ +/* + * 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 "skia/ext/image_operations.h" + +#include "NativeImageSkia.h" +#include "SkiaUtils.h" + +NativeImageSkia::NativeImageSkia() + : m_isDataComplete(false), + m_lastRequestSize(0, 0), + m_resizeRequests(0) +{ +} + +int NativeImageSkia::decodedSize() const +{ + return getSize() + m_resizedImage.getSize(); +} + +bool NativeImageSkia::hasResizedBitmap(int w, int h) const +{ + if (m_lastRequestSize.width() == w && m_lastRequestSize.height() == h) + m_resizeRequests++; + else { + m_lastRequestSize = WebCore::IntSize(w, h); + m_resizeRequests = 0; + } + + return m_resizedImage.width() == w && m_resizedImage.height() == h; +} + +// FIXME: don't cache when image is in-progress. + +SkBitmap NativeImageSkia::resizedBitmap(int w, int h) const +{ + if (m_resizedImage.width() != w || m_resizedImage.height() != h) + m_resizedImage = skia::ImageOperations::Resize(*this, skia::ImageOperations::RESIZE_LANCZOS3, w, h); + + return m_resizedImage; +} + +bool NativeImageSkia::shouldCacheResampling(int destWidth, + int destHeight, + int destSubsetWidth, + int destSubsetHeight) const +{ + // We can not cache incomplete frames. This might be a good optimization in + // the future, were we know how much of the frame has been decoded, so when + // we incrementally draw more of the image, we only have to resample the + // parts that are changed. + if (!m_isDataComplete) + return false; + + // If the destination bitmap is small, we'll always allow caching, since + // there is not very much penalty for computing it and it may come in handy. + static const int kSmallBitmapSize = 4096; + if (destWidth * destHeight <= kSmallBitmapSize) + return true; + + // If "too many" requests have been made for this bitmap, we assume that + // many more will be made as well, and we'll go ahead and cache it. + static const int kManyRequestThreshold = 4; + if (m_lastRequestSize.width() == destWidth && + m_lastRequestSize.height() == destHeight) { + if (m_resizeRequests >= kManyRequestThreshold) + return true; + } else { + // When a different size is being requested, count this as a query + // (hasResizedBitmap) and reset the counter. + m_lastRequestSize = WebCore::IntSize(destWidth, destHeight); + m_resizeRequests = 0; + } + + // Otherwise, use the heuristic that if more than 1/4 of the image is + // requested, it's worth caching. + int destSize = destWidth * destHeight; + int destSubsetSize = destSubsetWidth * destSubsetHeight; + return destSize / 4 < destSubsetSize; +} diff --git a/WebCore/platform/graphics/skia/NativeImageSkia.h b/WebCore/platform/graphics/skia/NativeImageSkia.h new file mode 100644 index 0000000..5947238 --- /dev/null +++ b/WebCore/platform/graphics/skia/NativeImageSkia.h @@ -0,0 +1,104 @@ +/* + * 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. + */ + +#ifndef NativeImageSkia_h +#define NativeImageSkia_h + +#include "SkBitmap.h" +#include "IntSize.h" + +// This object is used as the "native image" in our port. When WebKit uses +// "NativeImagePtr", it is a pointer to this type. It is an SkBitmap, but also +// stores a cached resized image. +class NativeImageSkia : public SkBitmap { +public: + NativeImageSkia(); + + // Returns the number of bytes of image data. This includes the cached + // resized version if there is one. + int decodedSize() const; + + // Sets the data complete flag. This is called by the image decoder when + // all data is complete, and used by us to know whether we can cache + // resized images. + void setDataComplete() { m_isDataComplete = true; } + + // Returns true if the entire image has been decoded. + bool isDataComplete() const { return m_isDataComplete; } + + // We can keep a resized version of the bitmap cached on this object. + // This function will return true if there is a cached version of the + // given image subset with the given dimensions. + bool hasResizedBitmap(int width, int height) const; + + // This will return an existing resized image, or generate a new one of + // the specified size and store it in the cache. Subsetted images can not + // be cached unless the subset is the entire bitmap. + SkBitmap resizedBitmap(int width, int height) const; + + // Returns true if the given resize operation should either resize the whole + // image and cache it, or resize just the part it needs and throw the result + // away. + // + // On the one hand, if only a small subset is desired, then we will waste a + // lot of time resampling the entire thing, so we only want to do exactly + // what's required. On the other hand, resampling the entire bitmap is + // better if we're going to be using it more than once (like a bitmap + // scrolling on and off the screen. Since we only cache when doing the + // entire thing, it's best to just do it up front. + bool shouldCacheResampling(int destWidth, + int destHeight, + int destSubsetWidth, + int destSubsetHeight) const; + +private: + // Set to true when the data is complete. Before the entire image has + // loaded, we do not want to cache a resize. + bool m_isDataComplete; + + // The cached bitmap. This will be empty() if there is no cached image. + mutable SkBitmap m_resizedImage; + + // References how many times that the image size has been requested for + // the last size. + // + // Every time we get a request, if it matches the m_lastRequestSize, we'll + // increment the counter, and if not, we'll reset the counter and save the + // size. + // + // This allows us to see if many requests have been made for the same + // resized image, we know that we should probably cache it, even if all of + // those requests individually are small and would not otherwise be cached. + mutable WebCore::IntSize m_lastRequestSize; + mutable int m_resizeRequests; +}; + +#endif // NativeImageSkia_h + diff --git a/WebCore/platform/graphics/skia/PathSkia.cpp b/WebCore/platform/graphics/skia/PathSkia.cpp new file mode 100644 index 0000000..ca99322 --- /dev/null +++ b/WebCore/platform/graphics/skia/PathSkia.cpp @@ -0,0 +1,316 @@ +// 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 "Path.h" + +#include "FloatRect.h" +#include "ImageBuffer.h" +#include "StrokeStyleApplier.h" + +#include "SkPath.h" +#include "SkRegion.h" +#include "SkiaUtils.h" + +#include <wtf/MathExtras.h> + +namespace WebCore { + +Path::Path() +{ + m_path = new SkPath; +} + +Path::Path(const Path& other) +{ + m_path = new SkPath(*other.m_path); +} + +Path::~Path() +{ + delete m_path; +} + +Path& Path::operator=(const Path& other) +{ + *m_path = *other.m_path; + return *this; +} + +bool Path::isEmpty() const +{ + return m_path->isEmpty(); +} + +bool Path::contains(const FloatPoint& point, WindRule rule) const +{ + return SkPathContainsPoint(m_path, point, + rule == RULE_NONZERO ? SkPath::kWinding_FillType : SkPath::kEvenOdd_FillType); +} + +void Path::translate(const FloatSize& size) +{ + m_path->offset(WebCoreFloatToSkScalar(size.width()), WebCoreFloatToSkScalar(size.height())); +} + +FloatRect Path::boundingRect() const +{ + SkRect rect; + m_path->computeBounds(&rect, SkPath::kExact_BoundsType); + return rect; +} + +void Path::moveTo(const FloatPoint& point) +{ + m_path->moveTo(point); +} + +void Path::addLineTo(const FloatPoint& point) +{ + m_path->lineTo(point); +} + +void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& ep) +{ + m_path->quadTo(cp, ep); +} + +void Path::addBezierCurveTo(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& ep) +{ + m_path->cubicTo(p1, p2, ep); +} + +void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius) +{ + m_path->arcTo(p1, p2, WebCoreFloatToSkScalar(radius)); +} + +void Path::closeSubpath() +{ + m_path->close(); +} + +void Path::addArc(const FloatPoint& p, float r, float sa, float ea, bool anticlockwise) { + SkScalar cx = WebCoreFloatToSkScalar(p.x()); + SkScalar cy = WebCoreFloatToSkScalar(p.y()); + SkScalar radius = WebCoreFloatToSkScalar(r); + + SkRect oval; + oval.set(cx - radius, cy - radius, cx + radius, cy + radius); + + float sweep = ea - sa; + // check for a circle + if (sweep >= 2 * piFloat || sweep <= -2 * piFloat) + m_path->addOval(oval); + else { + SkScalar startDegrees = WebCoreFloatToSkScalar(sa * 180 / piFloat); + SkScalar sweepDegrees = WebCoreFloatToSkScalar(sweep * 180 / piFloat); + + // Counterclockwise arcs should be drawn with negative sweeps, while + // clockwise arcs should be drawn with positive sweeps. Check to see + // if the situation is reversed and correct it by adding or subtracting + // a full circle + if (anticlockwise && sweepDegrees > 0) { + sweepDegrees -= SkIntToScalar(360); + } else if (!anticlockwise && sweepDegrees < 0) { + sweepDegrees += SkIntToScalar(360); + } + + m_path->arcTo(oval, startDegrees, sweepDegrees, false); + } +} + +void Path::addRect(const FloatRect& rect) +{ + m_path->addRect(rect); +} + +void Path::addEllipse(const FloatRect& rect) +{ + m_path->addOval(rect); +} + +void Path::clear() +{ + m_path->reset(); +} + +static FloatPoint* convertPathPoints(FloatPoint dst[], const SkPoint src[], int count) +{ + for (int i = 0; i < count; i++) { + dst[i].setX(SkScalarToFloat(src[i].fX)); + dst[i].setY(SkScalarToFloat(src[i].fY)); + } + return dst; +} + +void Path::apply(void* info, PathApplierFunction function) const +{ + SkPath::Iter iter(*m_path, false); + SkPoint pts[4]; + PathElement pathElement; + FloatPoint pathPoints[3]; + + for (;;) { + switch (iter.next(pts)) { + case SkPath::kMove_Verb: + pathElement.type = PathElementMoveToPoint; + pathElement.points = convertPathPoints(pathPoints, &pts[0], 1); + break; + case SkPath::kLine_Verb: + pathElement.type = PathElementAddLineToPoint; + pathElement.points = convertPathPoints(pathPoints, &pts[1], 1); + break; + case SkPath::kQuad_Verb: + pathElement.type = PathElementAddQuadCurveToPoint; + pathElement.points = convertPathPoints(pathPoints, &pts[1], 2); + break; + case SkPath::kCubic_Verb: + pathElement.type = PathElementAddCurveToPoint; + pathElement.points = convertPathPoints(pathPoints, &pts[1], 3); + break; + case SkPath::kClose_Verb: + pathElement.type = PathElementCloseSubpath; + pathElement.points = convertPathPoints(pathPoints, 0, 0); + break; + case SkPath::kDone_Verb: + return; + } + function(info, &pathElement); + } +} + +void Path::transform(const TransformationMatrix& xform) +{ + m_path->transform(xform); +} + +String Path::debugString() const +{ + String result; + + SkPath::Iter iter(*m_path, false); + SkPoint pts[4]; + + int numPoints = m_path->getPoints(0, 0); + SkPath::Verb verb; + + do { + verb = iter.next(pts); + switch (verb) { + case SkPath::kMove_Verb: + result += String::format("M%.2f,%.2f ", pts[0].fX, pts[0].fY); + numPoints -= 1; + break; + case SkPath::kLine_Verb: + if (!iter.isCloseLine()) { + result += String::format("L%.2f,%.2f ", pts[1].fX, pts[1].fY); + numPoints -= 1; + } + break; + case SkPath::kQuad_Verb: + result += String::format("Q%.2f,%.2f,%.2f,%.2f ", + pts[1].fX, pts[1].fY, + pts[2].fX, pts[2].fY); + numPoints -= 2; + break; + case SkPath::kCubic_Verb: + result += String::format("C%.2f,%.2f,%.2f,%.2f,%.2f,%.2f ", + pts[1].fX, pts[1].fY, + pts[2].fX, pts[2].fY, + pts[3].fX, pts[3].fY); + numPoints -= 3; + break; + case SkPath::kClose_Verb: + result += "Z "; + break; + case SkPath::kDone_Verb: + break; + } + } while (verb != SkPath::kDone_Verb); + + // If you have a path that ends with an M, Skia will not iterate the + // trailing M. That's nice of it, but Apple's paths output the trailing M + // and we want out layout dumps to look like theirs + if (numPoints) { + ASSERT(numPoints==1); + m_path->getLastPt(pts); + result += String::format("M%.2f,%.2f ", pts[0].fX, pts[0].fY); + } + + return result.stripWhiteSpace(); +} + +// Computes the bounding box for the stroke and style currently selected into +// the given bounding box. This also takes into account the stroke width. +static FloatRect boundingBoxForCurrentStroke(const GraphicsContext* context) +{ + SkPaint paint; + context->platformContext()->setupPaintForStroking(&paint, 0, 0); + SkPath boundingPath; + paint.getFillPath(context->platformContext()->currentPath(), &boundingPath); + SkRect r; + boundingPath.computeBounds(&r, SkPath::kExact_BoundsType); + return r; +} + +FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) +{ + GraphicsContext* scratch = scratchContext(); + scratch->save(); + scratch->beginPath(); + scratch->addPath(*this); + + if (applier) + applier->strokeStyle(scratch); + + FloatRect r = boundingBoxForCurrentStroke(scratch); + scratch->restore(); + return r; +} + +bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const +{ + ASSERT(applier); + GraphicsContext* scratch = scratchContext(); + scratch->save(); + + applier->strokeStyle(scratch); + + SkPaint paint; + scratch->platformContext()->setupPaintForStroking(&paint, 0, 0); + SkPath strokePath; + paint.getFillPath(*platformPath(), &strokePath); + bool contains = SkPathContainsPoint(&strokePath, point, + SkPath::kWinding_FillType); + + scratch->restore(); + return contains; +} +} // namespace WebCore diff --git a/WebCore/platform/graphics/skia/PatternSkia.cpp b/WebCore/platform/graphics/skia/PatternSkia.cpp new file mode 100644 index 0000000..be8eb8a --- /dev/null +++ b/WebCore/platform/graphics/skia/PatternSkia.cpp @@ -0,0 +1,77 @@ +/* + * 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: + * + * 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 "Pattern.h" + +#include "Image.h" +#include "NativeImageSkia.h" +#include "TransformationMatrix.h" + +#include "SkShader.h" +#include "SkCanvas.h" + +namespace WebCore { + +PlatformPatternPtr Pattern::createPlatformPattern(const TransformationMatrix& patternTransform) const +{ + // Note: patternTransform is ignored since it seems to be applied elsewhere + // (when the pattern is used?). Applying it to the pattern (i.e. + // shader->setLocalMatrix) results in a double transformation. This can be + // seen, for instance, as an extra offset in: + // LayoutTests/fast/canvas/patternfill-repeat.html + // and expanded scale and skew in: + // LayoutTests/svg/W3C-SVG-1.1/pservers-grad-06-b.svg + + SkBitmap* bm = m_tileImage->nativeImageForCurrentFrame(); + if (m_repeatX && m_repeatY) + return SkShader::CreateBitmapShader(*bm, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); + + // Skia does not have a "draw the tile only once" option. Clamp_TileMode + // repeats the last line of the image after drawing one tile. To avoid + // filling the space with arbitrary pixels, this workaround forces the + // image to have a line of transparent pixels on the "repeated" edge(s), + // thus causing extra space to be transparent filled. + SkShader::TileMode tileModeX = m_repeatX ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode; + SkShader::TileMode tileModeY = m_repeatY ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode; + int expandW = m_repeatX ? 0 : 1; + int expandH = m_repeatY ? 0 : 1; + + // Create a transparent bitmap 1 pixel wider and/or taller than the + // original, then copy the orignal into it. + // FIXME: Is there a better way to pad (not scale) an image in skia? + SkBitmap bm2; + bm2.setConfig(bm->config(), bm->width() + expandW, bm->height() + expandH); + bm2.allocPixels(); + bm2.eraseARGB(0x00, 0x00, 0x00, 0x00); + SkCanvas canvas(bm2); + canvas.drawBitmap(*bm, 0, 0); + return SkShader::CreateBitmapShader(bm2, tileModeX, tileModeY); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp new file mode 100644 index 0000000..60dbbe0 --- /dev/null +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp @@ -0,0 +1,427 @@ +/* + * 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 "GraphicsContext.h" +#include "NativeImageSkia.h" +#include "PlatformContextSkia.h" +#include "SkiaUtils.h" + +#include "skia/ext/image_operations.h" +#include "skia/ext/platform_canvas.h" + +#include "SkBitmap.h" +#include "SkColorPriv.h" +#include "SkShader.h" +#include "SkDashPathEffect.h" + +#include <wtf/MathExtras.h> + +#if defined(__linux__) +#include "GdkSkia.h" +#endif + +// State ----------------------------------------------------------------------- + +// Encapsulates the additional painting state information we store for each +// pushed graphics state. +struct PlatformContextSkia::State { + State(); + State(const State&); + ~State(); + + // Common shader state. + float m_alpha; + SkPorterDuff::Mode m_porterDuffMode; + SkShader* m_gradient; + SkShader* m_pattern; + bool m_useAntialiasing; + SkDrawLooper* m_looper; + + // Fill. + SkColor m_fillColor; + + // Stroke. + WebCore::StrokeStyle m_strokeStyle; + SkColor m_strokeColor; + float m_strokeThickness; + int m_dashRatio; // Ratio of the length of a dash to its width. + float m_miterLimit; + SkPaint::Cap m_lineCap; + SkPaint::Join m_lineJoin; + SkDashPathEffect* m_dash; + + // Text. (See cTextFill & friends in GraphicsContext.h.) + int m_textDrawingMode; + + // Helper function for applying the state's alpha value to the given input + // color to produce a new output color. + SkColor applyAlpha(SkColor) const; + +private: + // Not supported. + void operator=(const State&); +}; + +// Note: Keep theses default values in sync with GraphicsContextState. +PlatformContextSkia::State::State() + : m_alpha(1) + , m_porterDuffMode(SkPorterDuff::kSrcOver_Mode) + , m_gradient(0) + , m_pattern(0) + , m_useAntialiasing(true) + , m_looper(0) + , m_fillColor(0xFF000000) + , m_strokeStyle(WebCore::SolidStroke) + , m_strokeColor(WebCore::Color::black) + , m_strokeThickness(0) + , m_dashRatio(3) + , m_miterLimit(4) + , m_lineCap(SkPaint::kDefault_Cap) + , m_lineJoin(SkPaint::kDefault_Join) + , m_dash(0) + , m_textDrawingMode(WebCore::cTextFill) +{ +} + +PlatformContextSkia::State::State(const State& other) +{ + memcpy(this, &other, sizeof(State)); + + m_looper->safeRef(); + m_dash->safeRef(); + m_gradient->safeRef(); + m_pattern->safeRef(); +} + +PlatformContextSkia::State::~State() +{ + m_looper->safeUnref(); + m_dash->safeUnref(); + m_gradient->safeUnref(); + m_pattern->safeUnref(); +} + +SkColor PlatformContextSkia::State::applyAlpha(SkColor c) const +{ + int s = roundf(m_alpha * 256); + if (s >= 256) + return c; + if (s < 0) + return 0; + + int a = SkAlphaMul(SkColorGetA(c), s); + return (c & 0x00FFFFFF) | (a << 24); +} + +// PlatformContextSkia --------------------------------------------------------- + +// Danger: canvas can be NULL. +PlatformContextSkia::PlatformContextSkia(skia::PlatformCanvas* canvas) + : m_canvas(canvas) + , m_stateStack(sizeof(State)) +{ + m_stateStack.append(State()); + m_state = &m_stateStack.last(); +#if defined(OS_LINUX) + m_gdkskia = m_canvas ? gdk_skia_new(m_canvas) : 0; +#endif +} + +PlatformContextSkia::~PlatformContextSkia() +{ +#if defined(OS_LINUX) + if (m_gdkskia) { + g_object_unref(m_gdkskia); + m_gdkskia = 0; + } +#endif +} + +void PlatformContextSkia::setCanvas(skia::PlatformCanvas* canvas) +{ + m_canvas = canvas; +} + +void PlatformContextSkia::save() +{ + m_stateStack.append(*m_state); + m_state = &m_stateStack.last(); + + // Save our native canvas. + canvas()->save(); +} + +void PlatformContextSkia::restore() +{ + m_stateStack.removeLast(); + m_state = &m_stateStack.last(); + + // Restore our native canvas. + canvas()->restore(); +} + +void PlatformContextSkia::drawRect(SkRect rect) +{ + SkPaint paint; + int fillcolorNotTransparent = m_state->m_fillColor & 0xFF000000; + if (fillcolorNotTransparent) { + setupPaintForFilling(&paint); + canvas()->drawRect(rect, paint); + } + + if (m_state->m_strokeStyle != WebCore::NoStroke && + (m_state->m_strokeColor & 0xFF000000)) { + if (fillcolorNotTransparent) { + // This call is expensive so don't call it unnecessarily. + paint.reset(); + } + setupPaintForStroking(&paint, &rect, 0); + canvas()->drawRect(rect, paint); + } +} + +void PlatformContextSkia::setupPaintCommon(SkPaint* paint) const +{ +#ifdef SK_DEBUGx + { + SkPaint defaultPaint; + SkASSERT(*paint == defaultPaint); + } +#endif + + paint->setAntiAlias(m_state->m_useAntialiasing); + paint->setPorterDuffXfermode(m_state->m_porterDuffMode); + paint->setLooper(m_state->m_looper); + + if (m_state->m_gradient) + paint->setShader(m_state->m_gradient); + else if (m_state->m_pattern) + paint->setShader(m_state->m_pattern); +} + +void PlatformContextSkia::setupPaintForFilling(SkPaint* paint) const +{ + setupPaintCommon(paint); + paint->setColor(m_state->applyAlpha(m_state->m_fillColor)); +} + +float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, int length) const +{ + setupPaintCommon(paint); + float width = m_state->m_strokeThickness; + + // This allows dashing and dotting to work properly for hairline strokes. + if (width == 0) + width = 1; + + paint->setColor(m_state->applyAlpha(m_state->m_strokeColor)); + paint->setStyle(SkPaint::kStroke_Style); + paint->setStrokeWidth(SkFloatToScalar(width)); + paint->setStrokeCap(m_state->m_lineCap); + paint->setStrokeJoin(m_state->m_lineJoin); + paint->setStrokeMiter(SkFloatToScalar(m_state->m_miterLimit)); + + if (rect != 0 && (static_cast<int>(roundf(width)) & 1)) + rect->inset(-SK_ScalarHalf, -SK_ScalarHalf); + + if (m_state->m_dash) + paint->setPathEffect(m_state->m_dash); + else { + switch (m_state->m_strokeStyle) { + case WebCore::NoStroke: + case WebCore::SolidStroke: + break; + case WebCore::DashedStroke: + width = m_state->m_dashRatio * width; + // Fall through. + case WebCore::DottedStroke: + SkScalar dashLength; + if (length) { + // Determine about how many dashes or dots we should have. + int numDashes = length / roundf(width); + if (!(numDashes & 1)) + numDashes++; // Make it odd so we end on a dash/dot. + // Use the number of dashes to determine the length of a + // dash/dot, which will be approximately width + dashLength = SkScalarDiv(SkIntToScalar(length), SkIntToScalar(numDashes)); + } else + dashLength = SkFloatToScalar(width); + SkScalar intervals[2] = { dashLength, dashLength }; + paint->setPathEffect(new SkDashPathEffect(intervals, 2, 0))->unref(); + } + } + + return width; +} + +void PlatformContextSkia::setDrawLooper(SkDrawLooper* dl) +{ + SkRefCnt_SafeAssign(m_state->m_looper, dl); +} + +void PlatformContextSkia::setMiterLimit(float ml) +{ + m_state->m_miterLimit = ml; +} + +void PlatformContextSkia::setAlpha(float alpha) +{ + m_state->m_alpha = alpha; +} + +void PlatformContextSkia::setLineCap(SkPaint::Cap lc) +{ + m_state->m_lineCap = lc; +} + +void PlatformContextSkia::setLineJoin(SkPaint::Join lj) +{ + m_state->m_lineJoin = lj; +} + +void PlatformContextSkia::setPorterDuffMode(SkPorterDuff::Mode pdm) +{ + m_state->m_porterDuffMode = pdm; +} + +void PlatformContextSkia::setFillColor(SkColor color) +{ + m_state->m_fillColor = color; +} + +SkDrawLooper* PlatformContextSkia::getDrawLooper() const +{ + return m_state->m_looper; +} + +WebCore::StrokeStyle PlatformContextSkia::getStrokeStyle() const +{ + return m_state->m_strokeStyle; +} + +void PlatformContextSkia::setStrokeStyle(WebCore::StrokeStyle strokeStyle) +{ + m_state->m_strokeStyle = strokeStyle; +} + +void PlatformContextSkia::setStrokeColor(SkColor strokeColor) +{ + m_state->m_strokeColor = strokeColor; +} + +float PlatformContextSkia::getStrokeThickness() const +{ + return m_state->m_strokeThickness; +} + +void PlatformContextSkia::setStrokeThickness(float thickness) +{ + m_state->m_strokeThickness = thickness; +} + +int PlatformContextSkia::getTextDrawingMode() const +{ + return m_state->m_textDrawingMode; +} + +void PlatformContextSkia::setTextDrawingMode(int mode) +{ + // cTextClip is never used, so we assert that it isn't set: + // https://bugs.webkit.org/show_bug.cgi?id=21898 + ASSERT((mode & WebCore::cTextClip) == 0); + m_state->m_textDrawingMode = mode; +} + +void PlatformContextSkia::setUseAntialiasing(bool enable) +{ + m_state->m_useAntialiasing = enable; +} + +SkColor PlatformContextSkia::fillColor() const +{ + return m_state->m_fillColor; +} + +void PlatformContextSkia::beginPath() +{ + m_path.reset(); +} + +void PlatformContextSkia::addPath(const SkPath& path) +{ + m_path.addPath(path); +} + +void PlatformContextSkia::setFillRule(SkPath::FillType fr) +{ + m_path.setFillType(fr); +} + +void PlatformContextSkia::setGradient(SkShader* gradient) +{ + if (gradient != m_state->m_gradient) { + m_state->m_gradient->safeUnref(); + m_state->m_gradient = gradient; + } +} + +void PlatformContextSkia::setPattern(SkShader* pattern) +{ + if (pattern != m_state->m_pattern) { + m_state->m_pattern->safeUnref(); + m_state->m_pattern = pattern; + } +} + +void PlatformContextSkia::setDashPathEffect(SkDashPathEffect* dash) +{ + if (dash != m_state->m_dash) { + m_state->m_dash->safeUnref(); + m_state->m_dash = dash; + } +} + +void PlatformContextSkia::paintSkPaint(const SkRect& rect, + const SkPaint& paint) +{ + m_canvas->drawRect(rect, paint); +} + +const SkBitmap* PlatformContextSkia::bitmap() const +{ + return &m_canvas->getDevice()->accessBitmap(false); +} + +bool PlatformContextSkia::isPrinting() +{ + return m_canvas->getTopPlatformDevice().IsVectorial(); +} diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.h b/WebCore/platform/graphics/skia/PlatformContextSkia.h new file mode 100644 index 0000000..78e9a19 --- /dev/null +++ b/WebCore/platform/graphics/skia/PlatformContextSkia.h @@ -0,0 +1,173 @@ +/* + * 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. + */ + +#ifndef PlatformContextSkia_h +#define PlatformContextSkia_h + +#include "GraphicsContext.h" +#include "Noncopyable.h" + +#include "SkDashPathEffect.h" +#include "SkDrawLooper.h" +#include "SkDeque.h" +#include "skia/ext/platform_canvas.h" +#include "SkPaint.h" +#include "SkPath.h" + +#include <wtf/Vector.h> + +typedef struct _GdkDrawable GdkSkia; + +// This class holds the platform-specific state for GraphicsContext. We put +// most of our Skia wrappers on this class. In theory, a lot of this stuff could +// be moved to GraphicsContext directly, except that some code external to this +// would like to poke at our graphics layer as well (like the Image and Font +// stuff, which needs some amount of our wrappers and state around SkCanvas). +// +// So in general, this class uses just Skia types except when there's no easy +// conversion. GraphicsContext is responsible for converting the WebKit types to +// Skia types and setting up the eventual call to the Skia functions. +// +// This class then keeps track of all the current Skia state. WebKit expects +// that the graphics state that is pushed and popped by save() and restore() +// includes things like colors and pen styles. Skia does this differently, where +// push and pop only includes transforms and bitmaps, and the application is +// responsible for managing the painting state which is store in separate +// SkPaint objects. This class provides the adaptor that allows the painting +// state to be pushed and popped along with the bitmap. +class PlatformContextSkia : Noncopyable { +public: + // For printing, there shouldn't be any canvas. canvas can be NULL. If you + // supply a NULL canvas, you can also call setCanvas later. + PlatformContextSkia(skia::PlatformCanvas*); + ~PlatformContextSkia(); + + // Sets the canvas associated with this context. Use when supplying NULL + // to the constructor. + void setCanvas(skia::PlatformCanvas*); + + void save(); + void restore(); + + // Sets up the common flags on a paint for antialiasing, effects, etc. + // This is implicitly called by setupPaintFill and setupPaintStroke, but + // you may wish to call it directly sometimes if you don't want that other + // behavior. + void setupPaintCommon(SkPaint*) const; + + // Sets up the paint for the current fill style. + void setupPaintForFilling(SkPaint*) const; + + // Sets up the paint for stroking. Returns an int representing the width of + // the pen, or 1 if the pen's width is 0 if a non-zero length is provided, + // the number of dashes/dots on a dashed/dotted line will be adjusted to + // start and end that length with a dash/dot. + float setupPaintForStroking(SkPaint*, SkRect*, int length) const; + + // State setting functions. + void setDrawLooper(SkDrawLooper*); // Note: takes an additional ref. + void setMiterLimit(float); + void setAlpha(float); + void setLineCap(SkPaint::Cap); + void setLineJoin(SkPaint::Join); + void setFillRule(SkPath::FillType); + void setPorterDuffMode(SkPorterDuff::Mode); + void setFillColor(SkColor); + void setStrokeStyle(WebCore::StrokeStyle); + void setStrokeColor(SkColor); + void setStrokeThickness(float thickness); + void setTextDrawingMode(int mode); + void setUseAntialiasing(bool enable); + void setGradient(SkShader*); + void setPattern(SkShader*); + void setDashPathEffect(SkDashPathEffect*); + + SkDrawLooper* getDrawLooper() const; + WebCore::StrokeStyle getStrokeStyle() const; + float getStrokeThickness() const; + int getTextDrawingMode() const; + + void beginPath(); + void addPath(const SkPath&); + const SkPath* currentPath() const { return &m_path; } + + SkColor fillColor() const; + + skia::PlatformCanvas* canvas() { return m_canvas; } + + // FIXME: This should be pushed down to GraphicsContext. + void drawRect(SkRect rect); + + // FIXME: I'm still unsure how I will serialize this call. + void paintSkPaint(const SkRect&, const SkPaint&); + + const SkBitmap* bitmap() const; + + // Returns the canvas used for painting, NOT guaranteed to be non-NULL. + // + // Warning: This function is deprecated so the users are reminded that they + // should use this layer of indirection instead of using the canvas + // directly. This is to help with the eventual serialization. + skia::PlatformCanvas* canvas() const; + + // Returns if the context is a printing context instead of a display + // context. Bitmap shouldn't be resampled when printing to keep the best + // possible quality. + bool isPrinting(); + +#if defined(__linux__) + // FIXME: should be camelCase. + GdkSkia* gdk_skia() const { return m_gdkskia; } +#endif + +private: + // Defines drawing style. + struct State; + + // NULL indicates painting is disabled. Never delete this object. + skia::PlatformCanvas* m_canvas; + + // States stack. Enables local drawing state change with save()/restore() + // calls. + WTF::Vector<State> m_stateStack; + // Pointer to the current drawing state. This is a cached value of + // mStateStack.back(). + State* m_state; + + // Current path. + SkPath m_path; + +#if defined(__linux__) + // A pointer to a GDK Drawable wrapping of this Skia canvas + GdkSkia* m_gdkskia; +#endif +}; + +#endif // PlatformContextSkia_h diff --git a/WebCore/platform/graphics/skia/PlatformGraphics.h b/WebCore/platform/graphics/skia/PlatformGraphics.h new file mode 100644 index 0000000..4ae8835 --- /dev/null +++ b/WebCore/platform/graphics/skia/PlatformGraphics.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#ifndef PlatformGraphics_h +#define PlatformGraphics_h + +typedef class SkShader* PlatformGradient; +typedef class SkShader* PlatformPattern; + +#endif // PlatformGraphics_h diff --git a/WebCore/platform/graphics/skia/SkiaFontWin.cpp b/WebCore/platform/graphics/skia/SkiaFontWin.cpp new file mode 100644 index 0000000..6e79a7e --- /dev/null +++ b/WebCore/platform/graphics/skia/SkiaFontWin.cpp @@ -0,0 +1,218 @@ +/* + * 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 "SkiaFontWin.h" + +#include "SkCanvas.h" +#include "SkPaint.h" + +#include <wtf/ListHashSet.h> +#include <wtf/Vector.h> + +namespace WebCore { + +struct CachedOutlineKey { + CachedOutlineKey() : font(0), glyph(0), path(0) {} + CachedOutlineKey(HFONT f, WORD g) : font(f), glyph(g), path(0) {} + + HFONT font; + WORD glyph; + + // The lifetime of this pointer is managed externally to this class. Be sure + // to call DeleteOutline to remove items. + SkPath* path; +}; + +const bool operator==(const CachedOutlineKey& a, const CachedOutlineKey& b) +{ + return a.font == b.font && a.glyph == b.glyph; +} + +struct CachedOutlineKeyHash { + static unsigned hash(const CachedOutlineKey& key) + { + unsigned keyBytes; + memcpy(&keyBytes, &key.font, sizeof(unsigned)); + return keyBytes + key.glyph; + } + + static unsigned equal(const CachedOutlineKey& a, const CachedOutlineKey& b) + { + return a.font == b.font && a.glyph == b.glyph; + } + + static const bool safeToCompareToEmptyOrDeleted = true; +}; + +typedef ListHashSet<CachedOutlineKey, CachedOutlineKeyHash> OutlineCache; + +// FIXME: Convert from static constructor to accessor function. WebCore tries to +// avoid global constructors to save on start-up time. +static OutlineCache outlineCache; + +// The global number of glyph outlines we'll cache. +static const int outlineCacheSize = 256; + +static SkScalar FIXEDToSkScalar(FIXED fixed) +{ + SkFixed skFixed; + memcpy(&skFixed, &fixed, sizeof(SkFixed)); + return SkFixedToScalar(skFixed); +} + +// Removes the given key from the cached outlines, also deleting the path. +static void deleteOutline(OutlineCache::iterator deleteMe) +{ + delete deleteMe->path; + outlineCache.remove(deleteMe); +} + +static void addPolyCurveToPath(const TTPOLYCURVE* polyCurve, SkPath* path) +{ + switch (polyCurve->wType) { + case TT_PRIM_LINE: + for (WORD i = 0; i < polyCurve->cpfx; i++) { + path->lineTo(FIXEDToSkScalar(polyCurve->apfx[i].x), -FIXEDToSkScalar(polyCurve->apfx[i].y)); + } + break; + + case TT_PRIM_QSPLINE: + // FIXME: doesn't this duplicate points if we do the loop > once? + for (WORD i = 0; i < polyCurve->cpfx - 1; i++) { + SkScalar bx = FIXEDToSkScalar(polyCurve->apfx[i].x); + SkScalar by = FIXEDToSkScalar(polyCurve->apfx[i].y); + + SkScalar cx = FIXEDToSkScalar(polyCurve->apfx[i + 1].x); + SkScalar cy = FIXEDToSkScalar(polyCurve->apfx[i + 1].y); + if (i < polyCurve->cpfx - 2) { + // We're not the last point, compute C. + cx = SkScalarAve(bx, cx); + cy = SkScalarAve(by, cy); + } + + // Need to flip the y coordinates since the font's coordinate system is + // flipped from ours vertically. + path->quadTo(bx, -by, cx, -cy); + } + break; + + case TT_PRIM_CSPLINE: + // FIXME + break; + } +} + +// The size of the glyph path buffer. +static const int glyphPathBufferSize = 4096; + +// Fills the given SkPath with the outline for the given glyph index. The font +// currently selected into the given DC is used. Returns true on success. +static bool getPathForGlyph(HDC dc, WORD glyph, SkPath* path) +{ + char buffer[glyphPathBufferSize]; + GLYPHMETRICS gm; + MAT2 mat = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; // Each one is (fract,value). + + DWORD totalSize = GetGlyphOutlineW(dc, glyph, GGO_GLYPH_INDEX | GGO_NATIVE, + &gm, glyphPathBufferSize, buffer, &mat); + if (totalSize == GDI_ERROR) + return false; + + const char* curGlyph = buffer; + const char* endGlyph = &buffer[totalSize]; + while (curGlyph < endGlyph) { + const TTPOLYGONHEADER* polyHeader = + reinterpret_cast<const TTPOLYGONHEADER*>(curGlyph); + path->moveTo(FIXEDToSkScalar(polyHeader->pfxStart.x), + -FIXEDToSkScalar(polyHeader->pfxStart.y)); + + const char* curPoly = curGlyph + sizeof(TTPOLYGONHEADER); + const char* endPoly = curGlyph + polyHeader->cb; + while (curPoly < endPoly) { + const TTPOLYCURVE* polyCurve = + reinterpret_cast<const TTPOLYCURVE*>(curPoly); + addPolyCurveToPath(polyCurve, path); + curPoly += sizeof(WORD) * 2 + sizeof(POINTFX) * polyCurve->cpfx; + } + curGlyph += polyHeader->cb; + } + + path->close(); + return true; +} + +// Returns a SkPath corresponding to the give glyph in the given font. The font +// should be selected into the given DC. The returned path is owned by the +// hashtable. Returns 0 on error. +const SkPath* SkiaWinOutlineCache::lookupOrCreatePathForGlyph(HDC hdc, HFONT font, WORD glyph) +{ + CachedOutlineKey key(font, glyph); + OutlineCache::iterator found = outlineCache.find(key); + if (found != outlineCache.end()) { + // Keep in MRU order by removing & reinserting the value. + key = *found; + outlineCache.remove(found); + outlineCache.add(key); + return key.path; + } + + key.path = new SkPath; + if (!getPathForGlyph(hdc, glyph, key.path)) + return 0; + + if (outlineCache.size() > outlineCacheSize) + // The cache is too big, find the oldest value (first in the list). + deleteOutline(outlineCache.begin()); + + outlineCache.add(key); + return key.path; +} + + +void SkiaWinOutlineCache::removePathsForFont(HFONT hfont) +{ + // ListHashSet isn't the greatest structure for deleting stuff out of, but + // removing entries will be relatively rare (we don't remove fonts much, nor + // do we draw out own glyphs using these routines much either). + // + // We keep a list of all glyphs we're removing which we do in a separate + // pass. + Vector<CachedOutlineKey> outlinesToDelete; + for (OutlineCache::iterator i = outlineCache.begin(); + i != outlineCache.end(); ++i) + outlinesToDelete.append(*i); + + for (Vector<CachedOutlineKey>::iterator i = outlinesToDelete.begin(); + i != outlinesToDelete.end(); ++i) + deleteOutline(outlineCache.find(*i)); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/skia/SkiaFontWin.h b/WebCore/platform/graphics/skia/SkiaFontWin.h new file mode 100644 index 0000000..2adab39 --- /dev/null +++ b/WebCore/platform/graphics/skia/SkiaFontWin.h @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#ifndef SkiaWinOutlineCache_h +#define SkiaWinOutlineCache_h + +#include <windows.h> + +class SkPath; + +namespace WebCore { + +// FIXME: Rename file to SkiaWinOutlineCache +class SkiaWinOutlineCache { +public: + static const SkPath* lookupOrCreatePathForGlyph(HDC, HFONT, WORD); + // Removes any cached glyphs from the outline cache corresponding to the + // given font handle. + static void removePathsForFont(HFONT); + +private: + SkiaWinOutlineCache(); +}; + +} // namespace WebCore + +#endif // SkiaWinOutlineCache_h diff --git a/WebCore/platform/graphics/skia/SkiaUtils.cpp b/WebCore/platform/graphics/skia/SkiaUtils.cpp new file mode 100644 index 0000000..6d9ffe2 --- /dev/null +++ b/WebCore/platform/graphics/skia/SkiaUtils.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2006,2007,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 "SkiaUtils.h" + +#include "ImageBuffer.h" +#include "SharedBuffer.h" +#include "SkCanvas.h" +#include "SkColorPriv.h" +#include "SkMatrix.h" +#include "SkRegion.h" + +namespace WebCore { + +static const struct CompositOpToPorterDuffMode { + uint8_t mCompositOp; + uint8_t mPorterDuffMode; +} gMapCompositOpsToPorterDuffModes[] = { + { CompositeClear, SkPorterDuff::kClear_Mode }, + { CompositeCopy, SkPorterDuff::kSrcOver_Mode }, // TODO + { CompositeSourceOver, SkPorterDuff::kSrcOver_Mode }, + { CompositeSourceIn, SkPorterDuff::kSrcIn_Mode }, + { CompositeSourceOut, SkPorterDuff::kSrcOut_Mode }, + { CompositeSourceAtop, SkPorterDuff::kSrcATop_Mode }, + { CompositeDestinationOver, SkPorterDuff::kDstOver_Mode }, + { CompositeDestinationIn, SkPorterDuff::kDstIn_Mode }, + { CompositeDestinationOut, SkPorterDuff::kDstOut_Mode }, + { CompositeDestinationAtop, SkPorterDuff::kDstATop_Mode }, + { CompositeXOR, SkPorterDuff::kXor_Mode }, + { CompositePlusDarker, SkPorterDuff::kDarken_Mode }, + { CompositeHighlight, SkPorterDuff::kSrcOver_Mode }, // TODO + { CompositePlusLighter, SkPorterDuff::kLighten_Mode } +}; + +SkPorterDuff::Mode WebCoreCompositeToSkiaComposite(CompositeOperator op) +{ + const CompositOpToPorterDuffMode* table = gMapCompositOpsToPorterDuffModes; + + for (unsigned i = 0; i < SK_ARRAY_COUNT(gMapCompositOpsToPorterDuffModes); i++) { + if (table[i].mCompositOp == op) + return (SkPorterDuff::Mode)table[i].mPorterDuffMode; + } + + SkDEBUGF(("GraphicsContext::setCompositeOperation uknown CompositeOperator %d\n", op)); + return SkPorterDuff::kSrcOver_Mode; // fall-back +} + +static U8CPU InvScaleByte(U8CPU component, uint32_t scale) +{ + SkASSERT(component == (uint8_t)component); + return (component * scale + 0x8000) >> 16; +} + +SkColor SkPMColorToColor(SkPMColor pm) +{ + if (0 == pm) + return 0; + + unsigned a = SkGetPackedA32(pm); + uint32_t scale = (255 << 16) / a; + + return SkColorSetARGB(a, + InvScaleByte(SkGetPackedR32(pm), scale), + InvScaleByte(SkGetPackedG32(pm), scale), + InvScaleByte(SkGetPackedB32(pm), scale)); +} + +Color SkPMColorToWebCoreColor(SkPMColor pm) +{ + return SkPMColorToColor(pm); +} + +void IntersectRectAndRegion(const SkRegion& region, const SkRect& srcRect, SkRect* destRect) { + // The cliperator requires an int rect, so we round out. + SkIRect srcRectRounded; + srcRect.roundOut(&srcRectRounded); + + // The Cliperator will iterate over a bunch of rects where our transformed + // rect and the clipping region (which may be non-square) overlap. + SkRegion::Cliperator cliperator(region, srcRectRounded); + if (cliperator.done()) { + destRect->setEmpty(); + return; + } + + // Get the union of all visible rects in the clip that overlap our bitmap. + SkIRect currentVisibleRect = cliperator.rect(); + cliperator.next(); + while (!cliperator.done()) { + currentVisibleRect.join(cliperator.rect()); + cliperator.next(); + } + + destRect->set(currentVisibleRect); +} + +void ClipRectToCanvas(const SkCanvas& canvas, const SkRect& srcRect, SkRect* destRect) { + // Translate into the canvas' coordinate space. This is where the clipping + // region applies. + SkRect transformedSrc; + canvas.getTotalMatrix().mapRect(&transformedSrc, srcRect); + + // Do the intersection. + SkRect transformedDest; + IntersectRectAndRegion(canvas.getTotalClip(), transformedSrc, &transformedDest); + + // Now transform it back into world space. + SkMatrix inverseTransform; + canvas.getTotalMatrix().invert(&inverseTransform); + inverseTransform.mapRect(destRect, transformedDest); +} + +bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::FillType ft) +{ + SkRegion rgn; + SkRegion clip; + + SkPath::FillType originalFillType = originalPath->getFillType(); + + const SkPath* path = originalPath; + SkPath scaledPath; + int scale = 1; + + SkRect bounds; + originalPath->computeBounds(&bounds, SkPath::kFast_BoundsType); + + // We can immediately return false if the point is outside the bounding rect + if (!bounds.contains(SkFloatToScalar(point.x()), SkFloatToScalar(point.y()))) + return false; + + originalPath->setFillType(ft); + + // Skia has trouble with coordinates close to the max signed 16-bit values + // If we have those, we need to scale. + // + // TODO: remove this code once Skia is patched to work properly with large + // values + const SkScalar kMaxCoordinate = SkIntToScalar(1<<15); + SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop); + + if (biggestCoord > kMaxCoordinate) { + scale = SkScalarCeil(SkScalarDiv(biggestCoord, kMaxCoordinate)); + + SkMatrix m; + m.setScale(SkScalarInvert(SkIntToScalar(scale)), SkScalarInvert(SkIntToScalar(scale))); + originalPath->transform(m, &scaledPath); + path = &scaledPath; + } + + int x = static_cast<int>(floorf(point.x() / scale)); + int y = static_cast<int>(floorf(point.y() / scale)); + clip.setRect(x, y, x + 1, y + 1); + + bool contains = rgn.setPath(*path, clip); + + originalPath->setFillType(originalFillType); + return contains; +} + +GraphicsContext* scratchContext() +{ + static ImageBuffer* scratch = 0; + if (!scratch) + scratch = ImageBuffer::create(IntSize(1, 1), false).release(); + // We don't bother checking for failure creating the ImageBuffer, since our + // ImageBuffer initializer won't fail. + return scratch->context(); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/skia/SkiaUtils.h b/WebCore/platform/graphics/skia/SkiaUtils.h new file mode 100644 index 0000000..0e68574 --- /dev/null +++ b/WebCore/platform/graphics/skia/SkiaUtils.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2006,2007,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. + */ + +// All of the functions in this file should move to new homes and this file should be deleted. + +#ifndef SkiaUtils_h +#define SkiaUtils_h + +#include <wtf/MathExtras.h> +#include "GraphicsContext.h" +#include "SkPath.h" +#include "SkPorterDuff.h" + +class SkCanvas; +class SkRegion; + +namespace WebCore { + +SkPorterDuff::Mode WebCoreCompositeToSkiaComposite(CompositeOperator); + +// move this guy into SkColor.h +SkColor SkPMColorToColor(SkPMColor); + +// This should be an operator on Color +Color SkPMColorToWebCoreColor(SkPMColor); + +// Skia has problems when passed infinite, etc floats, filter them to 0. +inline SkScalar WebCoreFloatToSkScalar(float f) +{ + return SkFloatToScalar(isfinite(f) ? f : 0); +} + +inline SkScalar WebCoreDoubleToSkScalar(double d) +{ + return SkDoubleToScalar(isfinite(d) ? d : 0); +} + +// Computes the smallest rectangle that, which when drawn to the given canvas, +// will cover the same area as the source rectangle. It will clip to the canvas' +// clip, doing the necessary coordinate transforms. +// +// srcRect and destRect can be the same. +void ClipRectToCanvas(const SkCanvas&, const SkRect& srcRect, SkRect* destRect); + +// Determine if a given WebKit point is contained in a path +bool SkPathContainsPoint(SkPath*, const FloatPoint&, SkPath::FillType); + +// Returns a statically allocated 1x1 GraphicsContext intended for temporary +// operations. Please save() the state and restore() it when you're done with +// the context. +GraphicsContext* scratchContext(); + +} // namespace WebCore + +#endif // SkiaUtils_h diff --git a/WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp b/WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp new file mode 100644 index 0000000..1e2a194 --- /dev/null +++ b/WebCore/platform/graphics/skia/TransformationMatrixSkia.cpp @@ -0,0 +1,222 @@ +// 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 "TransformationMatrix.h" + +#include "FloatRect.h" +#include "IntRect.h" + +#include "SkiaUtils.h" + +namespace WebCore { + +TransformationMatrix::TransformationMatrix() +{ + m_transform.reset(); +} + +TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double e, double f) +{ + setMatrix(a, b, c, d, e, f); +} + +TransformationMatrix::TransformationMatrix(const SkMatrix& matrix) + : m_transform(matrix) +{ +} + +void TransformationMatrix::setMatrix(double a, double b, double c, double d, double e, double f) +{ + m_transform.reset(); + + m_transform.setScaleX(WebCoreDoubleToSkScalar(a)); + m_transform.setSkewX(WebCoreDoubleToSkScalar(c)); + m_transform.setTranslateX(WebCoreDoubleToSkScalar(e)); + + m_transform.setScaleY(WebCoreDoubleToSkScalar(d)); + m_transform.setSkewY(WebCoreDoubleToSkScalar(b)); + m_transform.setTranslateY(WebCoreDoubleToSkScalar(f)); +} + +void TransformationMatrix::map(double x, double y, double* x2, double* y2) const +{ + SkPoint src, dst; + src.set(WebCoreDoubleToSkScalar(x), WebCoreDoubleToSkScalar(y)); + m_transform.mapPoints(&dst, &src, 1); + + *x2 = SkScalarToDouble(dst.fX); + *y2 = SkScalarToDouble(dst.fY); +} + +IntRect TransformationMatrix::mapRect(const IntRect& src) const +{ + SkRect dst; + m_transform.mapRect(&dst, src); + return enclosingIntRect(dst); +} + +FloatRect TransformationMatrix::mapRect(const FloatRect& src) const +{ + SkRect dst; + m_transform.mapRect(&dst, src); + return dst; +} + +bool TransformationMatrix::isIdentity() const +{ + return m_transform.isIdentity(); +} + +void TransformationMatrix::reset() +{ + m_transform.reset(); +} + +TransformationMatrix &TransformationMatrix::scale(double sx, double sy) +{ + m_transform.preScale(WebCoreDoubleToSkScalar(sx), WebCoreDoubleToSkScalar(sy), 0, 0); + return *this; +} + +TransformationMatrix &TransformationMatrix::rotate(double d) +{ + m_transform.preRotate(WebCoreDoubleToSkScalar(d), 0, 0); + return *this; +} + +TransformationMatrix &TransformationMatrix::translate(double tx, double ty) +{ + m_transform.preTranslate(WebCoreDoubleToSkScalar(tx), WebCoreDoubleToSkScalar(ty)); + return *this; +} + +TransformationMatrix &TransformationMatrix::shear(double sx, double sy) +{ + m_transform.preSkew(WebCoreDoubleToSkScalar(sx), WebCoreDoubleToSkScalar(sy), 0, 0); + return *this; +} + +double TransformationMatrix::det() const +{ + return SkScalarToDouble(m_transform.getScaleX()) * SkScalarToDouble(m_transform.getScaleY()) - + SkScalarToDouble(m_transform.getSkewY()) * SkScalarToDouble(m_transform.getSkewX()); +} + +TransformationMatrix TransformationMatrix::inverse() const +{ + TransformationMatrix inverse; + m_transform.invert(&inverse.m_transform); + return inverse; +} + +TransformationMatrix::operator SkMatrix() const +{ + return m_transform; +} + +bool TransformationMatrix::operator==(const TransformationMatrix& m2) const +{ + return m_transform == m2.m_transform; +} + +TransformationMatrix &TransformationMatrix::operator*=(const TransformationMatrix& m2) +{ + m_transform.setConcat(m2.m_transform, m_transform); + return *this; +} + +TransformationMatrix TransformationMatrix::operator*(const TransformationMatrix& m2) +{ + TransformationMatrix cat; + cat.m_transform.setConcat(m2.m_transform, m_transform); + return cat; +} + +double TransformationMatrix::a() const +{ + return SkScalarToDouble(m_transform.getScaleX()); +} + +void TransformationMatrix::setA(double a) +{ + m_transform.setScaleX(WebCoreDoubleToSkScalar(a)); +} + +double TransformationMatrix::b() const +{ + return SkScalarToDouble(m_transform.getSkewY()); +} + +void TransformationMatrix::setB(double b) +{ + m_transform.setSkewY(WebCoreDoubleToSkScalar(b)); +} + +double TransformationMatrix::c() const +{ + return SkScalarToDouble(m_transform.getSkewX()); +} + +void TransformationMatrix::setC(double c) +{ + m_transform.setSkewX(WebCoreDoubleToSkScalar(c)); +} + +double TransformationMatrix::d() const +{ + return SkScalarToDouble(m_transform.getScaleY()); +} + +void TransformationMatrix::setD(double d) +{ + m_transform.setScaleY(WebCoreDoubleToSkScalar(d)); +} + +double TransformationMatrix::e() const +{ + return SkScalarToDouble(m_transform.getTranslateX()); +} + +void TransformationMatrix::setE(double e) +{ + m_transform.setTranslateX(WebCoreDoubleToSkScalar(e)); +} + +double TransformationMatrix::f() const +{ + return SkScalarToDouble(m_transform.getTranslateY()); +} + +void TransformationMatrix::setF(double f) +{ + m_transform.setTranslateY(WebCoreDoubleToSkScalar(f)); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/transforms/IdentityTransformOperation.h b/WebCore/platform/graphics/transforms/IdentityTransformOperation.h new file mode 100644 index 0000000..347737c --- /dev/null +++ b/WebCore/platform/graphics/transforms/IdentityTransformOperation.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.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 IdentityTransformOperation_h +#define IdentityTransformOperation_h + +#include "TransformOperation.h" + +namespace WebCore { + +class IdentityTransformOperation : public TransformOperation { +public: + static PassRefPtr<IdentityTransformOperation> create() + { + return adoptRef(new IdentityTransformOperation()); + } + +private: + virtual bool isIdentity() const { return true; } + virtual OperationType getOperationType() const { return IDENTITY; } + virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == IDENTITY; } + + virtual bool operator==(const TransformOperation& o) const + { + return isSameType(o); + } + + virtual bool apply(TransformationMatrix&, const IntSize&) const + { + return false; + } + + virtual PassRefPtr<TransformOperation> blend(const TransformOperation*, double, bool = false) + { + return this; + } + + IdentityTransformOperation() + { + } + +}; + +} // namespace WebCore + +#endif // IdentityTransformOperation_h diff --git a/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp b/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp new file mode 100644 index 0000000..153d96d --- /dev/null +++ b/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "MatrixTransformOperation.h" + +#include <algorithm> + +namespace WebCore { + +PassRefPtr<TransformOperation> MatrixTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) +{ + if (from && !from->isSameType(*this)) + return this; + + // convert the TransformOperations into matrices + IntSize size; + TransformationMatrix fromT; + TransformationMatrix toT(m_a, m_b, m_c, m_d, m_e, m_f); + if (from) { + const MatrixTransformOperation* m = static_cast<const MatrixTransformOperation*>(from); + fromT.setMatrix(m->m_a, m->m_b, m->m_c, m->m_d, m->m_e, m->m_f); + } + + if (blendToIdentity) + std::swap(fromT, toT); + + toT.blend(fromT, progress); + return MatrixTransformOperation::create(toT.a(), toT.b(), toT.c(), toT.d(), toT.e(), toT.f()); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/transforms/MatrixTransformOperation.h b/WebCore/platform/graphics/transforms/MatrixTransformOperation.h new file mode 100644 index 0000000..d272229 --- /dev/null +++ b/WebCore/platform/graphics/transforms/MatrixTransformOperation.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.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 MatrixTransformOperation_h +#define MatrixTransformOperation_h + +#include "TransformOperation.h" + +namespace WebCore { + +class MatrixTransformOperation : public TransformOperation { +public: + static PassRefPtr<MatrixTransformOperation> create(double a, double b, double c, double d, double e, double f) + { + return adoptRef(new MatrixTransformOperation(a, b, c, d, e, f)); + } + +private: + virtual bool isIdentity() const { return m_a == 1 && m_b == 0 && m_c == 0 && m_d == 1 && m_e == 0 && m_f == 0; } + virtual OperationType getOperationType() const { return MATRIX; } + virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == MATRIX; } + + virtual bool operator==(const TransformOperation& o) const + { + if (!isSameType(o)) + return false; + + const MatrixTransformOperation* m = static_cast<const MatrixTransformOperation*>(&o); + return m_a == m->m_a && m_b == m->m_b && m_c == m->m_c && m_d == m->m_d && m_e == m->m_e && m_f == m->m_f; + } + + virtual bool apply(TransformationMatrix& transform, const IntSize&) const + { + TransformationMatrix matrix(m_a, m_b, m_c, m_d, m_e, m_f); + transform = matrix * transform; + return false; + } + + virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false); + + MatrixTransformOperation(double a, double b, double c, double d, double e, double f) + : m_a(a) + , m_b(b) + , m_c(c) + , m_d(d) + , m_e(e) + , m_f(f) + { + } + + double m_a; + double m_b; + double m_c; + double m_d; + double m_e; + double m_f; +}; + +} // namespace WebCore + +#endif // MatrixTransformOperation_h diff --git a/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp b/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp new file mode 100644 index 0000000..4887cee --- /dev/null +++ b/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "RotateTransformOperation.h" + +namespace WebCore { + +PassRefPtr<TransformOperation> RotateTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) +{ + if (from && !from->isSameType(*this)) + return this; + + if (blendToIdentity) + return RotateTransformOperation::create(m_angle - m_angle * progress, m_type); + + const RotateTransformOperation* fromOp = static_cast<const RotateTransformOperation*>(from); + double fromAngle = fromOp ? fromOp->m_angle : 0; + return RotateTransformOperation::create(fromAngle + (m_angle - fromAngle) * progress, m_type); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/transforms/RotateTransformOperation.h b/WebCore/platform/graphics/transforms/RotateTransformOperation.h new file mode 100644 index 0000000..adc6c4c --- /dev/null +++ b/WebCore/platform/graphics/transforms/RotateTransformOperation.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.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 RotateTransformOperation_h +#define RotateTransformOperation_h + +#include "TransformOperation.h" + +namespace WebCore { + +class RotateTransformOperation : public TransformOperation { +public: + static PassRefPtr<RotateTransformOperation> create(double angle, OperationType type) + { + return adoptRef(new RotateTransformOperation(angle, type)); + } + + virtual bool isIdentity() const { return m_angle == 0; } + virtual OperationType getOperationType() const { return m_type; } + virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; } + + virtual bool operator==(const TransformOperation& o) const + { + if (!isSameType(o)) + return false; + const RotateTransformOperation* r = static_cast<const RotateTransformOperation*>(&o); + return m_angle == r->m_angle; + } + + virtual bool apply(TransformationMatrix& transform, const IntSize& /*borderBoxSize*/) const + { + transform.rotate(m_angle); + return false; + } + + virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false); + + double angle() const { return m_angle; } + +private: + RotateTransformOperation(double angle, OperationType type) + : m_angle(angle) + , m_type(type) + { + } + + double m_angle; + OperationType m_type; +}; + +} // namespace WebCore + +#endif // RotateTransformOperation_h diff --git a/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp b/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp new file mode 100644 index 0000000..49a8fd8 --- /dev/null +++ b/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "ScaleTransformOperation.h" + +namespace WebCore { + +PassRefPtr<TransformOperation> ScaleTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) +{ + if (from && !from->isSameType(*this)) + return this; + + if (blendToIdentity) + return ScaleTransformOperation::create(m_x + (1. - m_x) * progress, m_y + (1. - m_y) * progress, m_type); + + const ScaleTransformOperation* fromOp = static_cast<const ScaleTransformOperation*>(from); + double fromX = fromOp ? fromOp->m_x : 1.; + double fromY = fromOp ? fromOp->m_y : 1.; + return ScaleTransformOperation::create(fromX + (m_x - fromX) * progress, fromY + (m_y - fromY) * progress, m_type); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/transforms/ScaleTransformOperation.h b/WebCore/platform/graphics/transforms/ScaleTransformOperation.h new file mode 100644 index 0000000..289f8a1 --- /dev/null +++ b/WebCore/platform/graphics/transforms/ScaleTransformOperation.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.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 ScaleTransformOperation_h +#define ScaleTransformOperation_h + +#include "TransformOperation.h" + +namespace WebCore { + +class ScaleTransformOperation : public TransformOperation { +public: + static PassRefPtr<ScaleTransformOperation> create(double sx, double sy, OperationType type) + { + return adoptRef(new ScaleTransformOperation(sx, sy, type)); + } + +private: + virtual bool isIdentity() const { return m_x == 1 && m_y == 1; } + virtual OperationType getOperationType() const { return m_type; } + virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; } + + virtual bool operator==(const TransformOperation& o) const + { + if (!isSameType(o)) + return false; + const ScaleTransformOperation* s = static_cast<const ScaleTransformOperation*>(&o); + return m_x == s->m_x && m_y == s->m_y; + } + + virtual bool apply(TransformationMatrix& transform, const IntSize&) const + { + transform.scale(m_x, m_y); + return false; + } + + virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false); + + ScaleTransformOperation(double sx, double sy, OperationType type) + : m_x(sx) + , m_y(sy) + , m_type(type) + { + } + + double m_x; + double m_y; + OperationType m_type; +}; + +} // namespace WebCore + +#endif // ScaleTransformOperation_h diff --git a/WebCore/platform/graphics/transforms/SkewTransformOperation.cpp b/WebCore/platform/graphics/transforms/SkewTransformOperation.cpp new file mode 100644 index 0000000..2a430e9 --- /dev/null +++ b/WebCore/platform/graphics/transforms/SkewTransformOperation.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "SkewTransformOperation.h" + +namespace WebCore { + +PassRefPtr<TransformOperation> SkewTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) +{ + if (from && !from->isSameType(*this)) + return this; + + if (blendToIdentity) + return SkewTransformOperation::create(m_angleX - m_angleX * progress, m_angleY - m_angleY * progress, m_type); + + const SkewTransformOperation* fromOp = static_cast<const SkewTransformOperation*>(from); + double fromAngleX = fromOp ? fromOp->m_angleX : 0; + double fromAngleY = fromOp ? fromOp->m_angleY : 0; + return SkewTransformOperation::create(fromAngleX + (m_angleX - fromAngleX) * progress, fromAngleY + (m_angleY - fromAngleY) * progress, m_type); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/transforms/SkewTransformOperation.h b/WebCore/platform/graphics/transforms/SkewTransformOperation.h new file mode 100644 index 0000000..6343710 --- /dev/null +++ b/WebCore/platform/graphics/transforms/SkewTransformOperation.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.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 SkewTransformOperation_h +#define SkewTransformOperation_h + +#include "TransformOperation.h" + +namespace WebCore { + +class SkewTransformOperation : public TransformOperation { +public: + static PassRefPtr<SkewTransformOperation> create(double angleX, double angleY, OperationType type) + { + return adoptRef(new SkewTransformOperation(angleX, angleY, type)); + } + +private: + virtual bool isIdentity() const { return m_angleX == 0 && m_angleY == 0; } + virtual OperationType getOperationType() const { return m_type; } + virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; } + + virtual bool operator==(const TransformOperation& o) const + { + if (!isSameType(o)) + return false; + const SkewTransformOperation* s = static_cast<const SkewTransformOperation*>(&o); + return m_angleX == s->m_angleX && m_angleY == s->m_angleY; + } + + virtual bool apply(TransformationMatrix& transform, const IntSize&) const + { + transform.skew(m_angleX, m_angleY); + return false; + } + + virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false); + + SkewTransformOperation(double angleX, double angleY, OperationType type) + : m_angleX(angleX) + , m_angleY(angleY) + , m_type(type) + { + } + + double m_angleX; + double m_angleY; + OperationType m_type; +}; + +} // namespace WebCore + +#endif // SkewTransformOperation_h diff --git a/WebCore/platform/graphics/transforms/TransformOperation.h b/WebCore/platform/graphics/transforms/TransformOperation.h new file mode 100644 index 0000000..65a0def --- /dev/null +++ b/WebCore/platform/graphics/transforms/TransformOperation.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.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 TransformOperation_h +#define TransformOperation_h + +#include "TransformationMatrix.h" +#include "IntSize.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +// CSS Transforms (may become part of CSS3) + +class TransformOperation : public RefCounted<TransformOperation> { +public: + enum OperationType { + SCALE_X, SCALE_Y, SCALE, + TRANSLATE_X, TRANSLATE_Y, TRANSLATE, + ROTATE, + SKEW_X, SKEW_Y, SKEW, + MATRIX, IDENTITY, NONE + }; + + virtual ~TransformOperation() { } + + virtual bool operator==(const TransformOperation&) const = 0; + bool operator!=(const TransformOperation& o) const { return !(*this == o); } + + virtual bool isIdentity() const = 0; + + virtual bool apply(TransformationMatrix&, const IntSize& borderBoxSize) const = 0; + + virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false) = 0; + + virtual OperationType getOperationType() const = 0; + virtual bool isSameType(const TransformOperation&) const { return false; } +}; + +} // namespace WebCore + +#endif // TransformOperation_h diff --git a/WebCore/platform/graphics/transforms/TransformOperations.cpp b/WebCore/platform/graphics/transforms/TransformOperations.cpp new file mode 100644 index 0000000..3d71480 --- /dev/null +++ b/WebCore/platform/graphics/transforms/TransformOperations.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "TransformOperations.h" + +#include "IdentityTransformOperation.h" + +namespace WebCore { + +TransformOperations::TransformOperations(bool makeIdentity) +{ + if (makeIdentity) + m_operations.append(IdentityTransformOperation::create()); +} + +bool TransformOperations::operator==(const TransformOperations& o) const +{ + if (m_operations.size() != o.m_operations.size()) + return false; + + unsigned s = m_operations.size(); + for (unsigned i = 0; i < s; i++) { + if (*m_operations[i] != *o.m_operations[i]) + return false; + } + + return true; +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/transforms/TransformOperations.h b/WebCore/platform/graphics/transforms/TransformOperations.h new file mode 100644 index 0000000..f929417 --- /dev/null +++ b/WebCore/platform/graphics/transforms/TransformOperations.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.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 TransformOperations_h +#define TransformOperations_h + +#include "TransformOperation.h" +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class TransformOperations { +public: + TransformOperations(bool makeIdentity = false); + + bool operator==(const TransformOperations& o) const; + bool operator!=(const TransformOperations& o) const + { + return !(*this == o); + } + + void apply(const IntSize& sz, TransformationMatrix& t) const + { + for (unsigned i = 0; i < m_operations.size(); ++i) + m_operations[i]->apply(t, sz); + } + + Vector<RefPtr<TransformOperation> >& operations() { return m_operations; } + const Vector<RefPtr<TransformOperation> >& operations() const { return m_operations; } + +private: + Vector<RefPtr<TransformOperation> > m_operations; +}; + +} // namespace WebCore + +#endif // TransformOperations_h diff --git a/WebCore/platform/graphics/AffineTransform.cpp b/WebCore/platform/graphics/transforms/TransformationMatrix.cpp index fdeba44..b48d572 100644 --- a/WebCore/platform/graphics/AffineTransform.cpp +++ b/WebCore/platform/graphics/transforms/TransformationMatrix.cpp @@ -24,18 +24,19 @@ */ #include "config.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "FloatRect.h" +#include "FloatQuad.h" #include "IntRect.h" #include <wtf/MathExtras.h> namespace WebCore { -static void affineTransformDecompose(const AffineTransform& matrix, double sr[9]) +static void affineTransformDecompose(const TransformationMatrix& matrix, double sr[9]) { - AffineTransform m(matrix); + TransformationMatrix m(matrix); // Compute scaling factors double sx = sqrt(m.a() * m.a() + m.b() * m.b()); @@ -73,7 +74,7 @@ static void affineTransformDecompose(const AffineTransform& matrix, double sr[9] sr[7] = m.e(); sr[8] = m.f(); } -static void affineTransformCompose(AffineTransform& m, const double sr[9]) +static void affineTransformCompose(TransformationMatrix& m, const double sr[9]) { m.setA(sr[3]); m.setB(sr[4]); @@ -85,74 +86,74 @@ static void affineTransformCompose(AffineTransform& m, const double sr[9]) m.scale(sr[0], sr[1]); } -bool AffineTransform::isInvertible() const +bool TransformationMatrix::isInvertible() const { return det() != 0.0; } -AffineTransform& AffineTransform::multiply(const AffineTransform& other) +TransformationMatrix& TransformationMatrix::multiply(const TransformationMatrix& other) { return (*this) *= other; } -AffineTransform& AffineTransform::scale(double s) +TransformationMatrix& TransformationMatrix::scale(double s) { return scale(s, s); } -AffineTransform& AffineTransform::scaleNonUniform(double sx, double sy) +TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy) { return scale(sx, sy); } -AffineTransform& AffineTransform::rotateFromVector(double x, double y) +TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y) { return rotate(rad2deg(atan2(y, x))); } -AffineTransform& AffineTransform::flipX() +TransformationMatrix& TransformationMatrix::flipX() { return scale(-1.0f, 1.0f); } -AffineTransform& AffineTransform::flipY() +TransformationMatrix& TransformationMatrix::flipY() { return scale(1.0f, -1.0f); } -AffineTransform& AffineTransform::skew(double angleX, double angleY) +TransformationMatrix& TransformationMatrix::skew(double angleX, double angleY) { return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY))); } -AffineTransform& AffineTransform::skewX(double angle) +TransformationMatrix& TransformationMatrix::skewX(double angle) { return shear(tan(deg2rad(angle)), 0.0f); } -AffineTransform& AffineTransform::skewY(double angle) +TransformationMatrix& TransformationMatrix::skewY(double angle) { return shear(0.0f, tan(deg2rad(angle))); } -AffineTransform makeMapBetweenRects(const FloatRect& source, const FloatRect& dest) +TransformationMatrix makeMapBetweenRects(const FloatRect& source, const FloatRect& dest) { - AffineTransform transform; + TransformationMatrix transform; transform.translate(dest.x() - source.x(), dest.y() - source.y()); transform.scale(dest.width() / source.width(), dest.height() / source.height()); return transform; } -IntPoint AffineTransform::mapPoint(const IntPoint& point) const +IntPoint TransformationMatrix::mapPoint(const IntPoint& point) const { double x2, y2; map(point.x(), point.y(), &x2, &y2); - + // Round the point. return IntPoint(lround(x2), lround(y2)); } -FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const +FloatPoint TransformationMatrix::mapPoint(const FloatPoint& point) const { double x2, y2; map(point.x(), point.y(), &x2, &y2); @@ -160,7 +161,17 @@ FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const return FloatPoint(static_cast<float>(x2), static_cast<float>(y2)); } -void AffineTransform::blend(const AffineTransform& from, double progress) +FloatQuad TransformationMatrix::mapQuad(const FloatQuad& quad) const +{ + // FIXME: avoid 4 seperate library calls. Point mapping really needs + // to be platform-independent code. + return FloatQuad(mapPoint(quad.p1()), + mapPoint(quad.p2()), + mapPoint(quad.p3()), + mapPoint(quad.p4())); +} + +void TransformationMatrix::blend(const TransformationMatrix& from, double progress) { double srA[9], srB[9]; diff --git a/WebCore/platform/graphics/AffineTransform.h b/WebCore/platform/graphics/transforms/TransformationMatrix.h index 37c6033..db121d1 100644 --- a/WebCore/platform/graphics/AffineTransform.h +++ b/WebCore/platform/graphics/transforms/TransformationMatrix.h @@ -20,31 +20,28 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef AffineTransform_h -#define AffineTransform_h +#ifndef TransformationMatrix_h +#define TransformationMatrix_h #if PLATFORM(CG) #include <CoreGraphics/CGAffineTransform.h> -typedef CGAffineTransform PlatformAffineTransform; +typedef CGAffineTransform PlatformTransformationMatrix; #elif PLATFORM(QT) #include <QMatrix> -typedef QMatrix PlatformAffineTransform; +typedef QMatrix PlatformTransformationMatrix; #elif PLATFORM(CAIRO) #include <cairo.h> -typedef cairo_matrix_t PlatformAffineTransform; -#elif PLATFORM(SGL) +typedef cairo_matrix_t PlatformTransformationMatrix; +#elif PLATFORM(SKIA) || PLATFORM(SGL) #include "SkMatrix.h" -typedef SkMatrix PlatformAffineTransform; -#elif PLATFORM(SKIA) -#include "SkMatrix.h" -typedef SkMatrix PlatformAffineTransform; +typedef SkMatrix PlatformTransformationMatrix; #elif PLATFORM(WX) && USE(WXGC) #include <wx/defs.h> #include <wx/graphics.h> -typedef wxGraphicsMatrix PlatformAffineTransform; +typedef wxGraphicsMatrix PlatformTransformationMatrix; #endif namespace WebCore { @@ -53,13 +50,14 @@ class IntPoint; class IntRect; class FloatPoint; class FloatRect; +class FloatQuad; -class AffineTransform { +class TransformationMatrix { public: - AffineTransform(); - AffineTransform(double a, double b, double c, double d, double e, double f); + TransformationMatrix(); + TransformationMatrix(double a, double b, double c, double d, double e, double f); #if !PLATFORM(WX) || USE(WXGC) - AffineTransform(const PlatformAffineTransform&); + TransformationMatrix(const PlatformTransformationMatrix&); #endif void setMatrix(double a, double b, double c, double d, double e, double f); @@ -76,6 +74,8 @@ public: FloatRect mapRect(const FloatRect&) const; + FloatQuad mapQuad(const FloatQuad&) const; + bool isIdentity() const; double a() const; @@ -98,43 +98,43 @@ public: void reset(); - AffineTransform& multiply(const AffineTransform&); - AffineTransform& scale(double); - AffineTransform& scale(double sx, double sy); - AffineTransform& scaleNonUniform(double sx, double sy); - AffineTransform& rotate(double d); - AffineTransform& rotateFromVector(double x, double y); - AffineTransform& translate(double tx, double ty); - AffineTransform& shear(double sx, double sy); - AffineTransform& flipX(); - AffineTransform& flipY(); - AffineTransform& skew(double angleX, double angleY); - AffineTransform& skewX(double angle); - AffineTransform& skewY(double angle); - + TransformationMatrix& multiply(const TransformationMatrix&); + TransformationMatrix& scale(double); + TransformationMatrix& scale(double sx, double sy); + TransformationMatrix& scaleNonUniform(double sx, double sy); + TransformationMatrix& rotate(double d); + TransformationMatrix& rotateFromVector(double x, double y); + TransformationMatrix& translate(double tx, double ty); + TransformationMatrix& shear(double sx, double sy); + TransformationMatrix& flipX(); + TransformationMatrix& flipY(); + TransformationMatrix& skew(double angleX, double angleY); + TransformationMatrix& skewX(double angle); + TransformationMatrix& skewY(double angle); + double det() const; bool isInvertible() const; - AffineTransform inverse() const; + TransformationMatrix inverse() const; - void blend(const AffineTransform& from, double progress); + void blend(const TransformationMatrix& from, double progress); #if !PLATFORM(WX) || USE(WXGC) - operator PlatformAffineTransform() const; + operator PlatformTransformationMatrix() const; #endif - bool operator==(const AffineTransform&) const; - bool operator!=(const AffineTransform& other) const { return !(*this == other); } - AffineTransform& operator*=(const AffineTransform&); - AffineTransform operator*(const AffineTransform&); - + bool operator==(const TransformationMatrix&) const; + bool operator!=(const TransformationMatrix& other) const { return !(*this == other); } + TransformationMatrix& operator*=(const TransformationMatrix&); + TransformationMatrix operator*(const TransformationMatrix&); + private: #if !PLATFORM(WX) || USE(WXGC) - PlatformAffineTransform m_transform; + PlatformTransformationMatrix m_transform; #endif }; -AffineTransform makeMapBetweenRects(const FloatRect& source, const FloatRect& dest); +TransformationMatrix makeMapBetweenRects(const FloatRect& source, const FloatRect& dest); } // namespace WebCore -#endif // AffineTransform_h +#endif // TransformationMatrix_h diff --git a/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp b/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp new file mode 100644 index 0000000..47471c4 --- /dev/null +++ b/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "TranslateTransformOperation.h" + +namespace WebCore { + +PassRefPtr<TransformOperation> TranslateTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) +{ + if (from && !from->isSameType(*this)) + return this; + + if (blendToIdentity) + return TranslateTransformOperation::create(Length(m_x.type()).blend(m_x, progress), Length(m_y.type()).blend(m_y, progress), m_type); + + const TranslateTransformOperation* fromOp = static_cast<const TranslateTransformOperation*>(from); + Length fromX = fromOp ? fromOp->m_x : Length(m_x.type()); + Length fromY = fromOp ? fromOp->m_y : Length(m_y.type()); + return TranslateTransformOperation::create(m_x.blend(fromX, progress), m_y.blend(fromY, progress), m_type); +} + +} // namespace WebCore diff --git a/WebCore/platform/graphics/transforms/TranslateTransformOperation.h b/WebCore/platform/graphics/transforms/TranslateTransformOperation.h new file mode 100644 index 0000000..61ccbcc --- /dev/null +++ b/WebCore/platform/graphics/transforms/TranslateTransformOperation.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.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 TranslateTransformOperation_h +#define TranslateTransformOperation_h + +#include "Length.h" +#include "TransformOperation.h" + +namespace WebCore { + +class TranslateTransformOperation : public TransformOperation { +public: + static PassRefPtr<TranslateTransformOperation> create(const Length& tx, const Length& ty, OperationType type) + { + return adoptRef(new TranslateTransformOperation(tx, ty, type)); + } + + virtual bool isIdentity() const { return m_x.calcFloatValue(1) == 0 && m_y.calcFloatValue(1) == 0; } + virtual OperationType getOperationType() const { return m_type; } + virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; } + + virtual bool operator==(const TransformOperation& o) const + { + if (!isSameType(o)) + return false; + const TranslateTransformOperation* t = static_cast<const TranslateTransformOperation*>(&o); + return m_x == t->m_x && m_y == t->m_y; + } + + virtual bool apply(TransformationMatrix& transform, const IntSize& borderBoxSize) const + { + transform.translate(m_x.calcFloatValue(borderBoxSize.width()), m_y.calcFloatValue(borderBoxSize.height())); + return m_x.type() == Percent || m_y.type() == Percent; + } + + virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false); + +private: + TranslateTransformOperation(const Length& tx, const Length& ty, OperationType type) + : m_x(tx) + , m_y(ty) + , m_type(type) + { + } + + Length m_x; + Length m_y; + OperationType m_type; +}; + +} // namespace WebCore + +#endif // TranslateTransformOperation_h diff --git a/WebCore/platform/graphics/win/FontCGWin.cpp b/WebCore/platform/graphics/win/FontCGWin.cpp index 1766cd9..9ca95f3 100644 --- a/WebCore/platform/graphics/win/FontCGWin.cpp +++ b/WebCore/platform/graphics/win/FontCGWin.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 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 @@ -26,7 +26,7 @@ #include "config.h" #include "Font.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "FloatConversion.h" #include "GlyphBuffer.h" #include "GraphicsContext.h" @@ -227,7 +227,7 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData XFORM xform; GetWorldTransform(hdc, &xform); - AffineTransform hdcTransform(xform.eM11, xform.eM21, xform.eM12, xform.eM22, xform.eDx, xform.eDy); + TransformationMatrix hdcTransform(xform.eM11, xform.eM21, xform.eM12, xform.eM22, xform.eDx, xform.eDy); CGAffineTransform initialGlyphTransform = hdcTransform.isInvertible() ? hdcTransform.inverse() : CGAffineTransformIdentity; if (font->platformData().syntheticOblique()) initialGlyphTransform = CGAffineTransformConcat(initialGlyphTransform, CGAffineTransformMake(1, 0, tanf(syntheticObliqueAngle * piFloat / 180.0f), 1, 0, 0)); @@ -294,14 +294,18 @@ static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { - if (font->m_font.useGDI()) { - drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point); - return; - } - CGContextRef cgContext = graphicsContext->platformContext(); + bool shouldUseFontSmoothing = WebCoreShouldUseFontSmoothing(); + + if (font->platformData().useGDI()) { + static bool canUsePlatformNativeGlyphs = wkCanUsePlatformNativeGlyphs(); + if (!canUsePlatformNativeGlyphs || !shouldUseFontSmoothing || (graphicsContext->textDrawingMode() & cTextStroke)) { + drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point); + return; + } + } - uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext, WebCoreShouldUseFontSmoothing()); + uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext, shouldUseFontSmoothing); const FontPlatformData& platformData = font->platformData(); @@ -322,7 +326,7 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo FloatSize translation = glyphBuffer.offsetAt(from); CGContextSetFontSize(cgContext, platformData.size()); - wkSetCGContextFontRenderingStyle(cgContext, font->isSystemFont(), false); + wkSetCGContextFontRenderingStyle(cgContext, font->isSystemFont(), false, font->platformData().useGDI()); IntSize shadowSize; int shadowBlur; diff --git a/WebCore/platform/graphics/win/FontCacheWin.cpp b/WebCore/platform/graphics/win/FontCacheWin.cpp index 49b3d76..9acc5a0 100644 --- a/WebCore/platform/graphics/win/FontCacheWin.cpp +++ b/WebCore/platform/graphics/win/FontCacheWin.cpp @@ -134,7 +134,7 @@ static const Vector<DWORD, 4>& getCJKCodePageMasks() static bool initialized; if (!initialized) { initialized = true; - IMLangFontLink2* langFontLink = FontCache::getFontLinkInterface(); + IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface(); if (!langFontLink) return codePageMasks; diff --git a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp index 26fceba..ba8afe7 100644 --- a/WebCore/platform/graphics/win/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/win/FontCustomPlatformData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 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 @@ -27,6 +27,7 @@ #include "SharedBuffer.h" #include "SoftLinking.h" #include <ApplicationServices/ApplicationServices.h> +#include <WebKitSystemInterface/WebKitSystemInterface.h> #include <wtf/RetainPtr.h> // From t2embapi.h, which is missing from the Microsoft Platform SDK. @@ -64,7 +65,10 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b ASSERT(m_fontReference); ASSERT(T2embedLibrary()); - LOGFONT logFont; + static bool canUsePlatformNativeGlyphs = wkCanUsePlatformNativeGlyphs(); + LOGFONT _logFont; + + LOGFONT& logFont = canUsePlatformNativeGlyphs ? *static_cast<LOGFONT*>(malloc(sizeof(LOGFONT))) : _logFont; if (m_name.isNull()) TTGetNewFontName(&m_fontReference, logFont.lfFaceName, LF_FACESIZE, 0, 0); else @@ -86,6 +90,8 @@ FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, b logFont.lfWeight = bold ? 700 : 400; HFONT hfont = CreateFontIndirect(&logFont); + if (canUsePlatformNativeGlyphs) + wkSetFontPlatformInfo(m_cgFont, &logFont, free); return FontPlatformData(hfont, m_cgFont, size, bold, italic, renderingMode == AlternateRenderingMode); } diff --git a/WebCore/platform/graphics/win/FontPlatformData.h b/WebCore/platform/graphics/win/FontPlatformData.h index d61afa8..09a8b55 100644 --- a/WebCore/platform/graphics/win/FontPlatformData.h +++ b/WebCore/platform/graphics/win/FontPlatformData.h @@ -45,6 +45,7 @@ public: FontPlatformData() #if PLATFORM(CAIRO) : m_fontFace(0) + , m_scaledFont(0) , #else : diff --git a/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp index bbfdb9f..c7e59ab 100644 --- a/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp +++ b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp @@ -2,7 +2,7 @@ * This file is part of the internal font implementation. It should not be included by anyone other than * FontMac.cpp, FontWin.cpp and Font.cpp. * - * Copyright (C) 2006, 2007, 2008 Apple Inc. + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -27,6 +27,7 @@ #include "PlatformString.h" #include "StringHash.h" #include <ApplicationServices/ApplicationServices.h> +#include <WebKitSystemInterface/WebKitSystemInterface.h> #include <wtf/HashMap.h> #include <wtf/RetainPtr.h> #include <wtf/Vector.h> @@ -119,6 +120,11 @@ void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR* ASSERT(m_cgFont); } } + if (m_useGDI && wkCanUsePlatformNativeGlyphs()) { + LOGFONT* logfont = static_cast<LOGFONT*>(malloc(sizeof(LOGFONT))); + GetObject(font, sizeof(*logfont), logfont); + wkSetFontPlatformInfo(m_cgFont.get(), logfont, free); + } } FontPlatformData::FontPlatformData(HFONT hfont, CGFontRef font, float size, bool bold, bool oblique, bool useGDI) diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp index 5a4279a..dccbe6c 100644 --- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "GraphicsContext.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "NotImplemented.h" #include "Path.h" @@ -173,6 +173,16 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo m_data->restore(); } +void GraphicsContext::setShouldIncludeChildWindows(bool include) +{ + m_data->m_shouldIncludeChildWindows = include; +} + +bool GraphicsContext::shouldIncludeChildWindows() const +{ + return m_data->m_shouldIncludeChildWindows; +} + GraphicsContext::WindowsBitmap::WindowsBitmap(HDC hdc, IntSize size) : m_hdc(0) , m_size(size) @@ -222,14 +232,16 @@ GraphicsContext::WindowsBitmap* GraphicsContext::createWindowsBitmap(IntSize siz void GraphicsContext::drawWindowsBitmap(WindowsBitmap* image, const IntPoint& point) { RetainPtr<CGColorSpaceRef> deviceRGB(AdoptCF, CGColorSpaceCreateDeviceRGB()); - RetainPtr<CFDataRef> imageData(AdoptCF, CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, image->buffer(), image->bufferLength(), kCFAllocatorNull)); + // FIXME: Creating CFData is non-optimal, but needed to avoid crashing when printing. Ideally we should + // make a custom CGDataProvider that controls the WindowsBitmap lifetime. see <rdar://6394455> + RetainPtr<CFDataRef> imageData(AdoptCF, CFDataCreate(kCFAllocatorDefault, image->buffer(), image->bufferLength())); 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()); } -void GraphicsContextPlatformPrivate::concatCTM(const AffineTransform& transform) +void GraphicsContextPlatformPrivate::concatCTM(const TransformationMatrix& transform) { if (!m_hdc) return; diff --git a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp index 3dcf6ba..892d24a 100644 --- a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "GraphicsContext.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "NotImplemented.h" #include "Path.h" @@ -102,7 +102,7 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo cairo_surface_mark_dirty(surface); } -void GraphicsContextPlatformPrivate::concatCTM(const AffineTransform& transform) +void GraphicsContextPlatformPrivate::concatCTM(const TransformationMatrix& transform) { cairo_surface_t* surface = cairo_get_target(cr); HDC hdc = cairo_win32_surface_get_dc(surface); diff --git a/WebCore/platform/graphics/win/GraphicsContextWin.cpp b/WebCore/platform/graphics/win/GraphicsContextWin.cpp index dbf9fad..b3ebcb0 100644 --- a/WebCore/platform/graphics/win/GraphicsContextWin.cpp +++ b/WebCore/platform/graphics/win/GraphicsContextWin.cpp @@ -32,7 +32,7 @@ #include "GraphicsContextPlatformPrivateCairo.h" #endif -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "NotImplemented.h" #include "Path.h" #include <wtf/MathExtras.h> diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp index cef4217..1b09e1f 100644 --- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp +++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp @@ -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 @@ -239,8 +239,9 @@ IntSize MediaPlayerPrivate::naturalSize() const bool MediaPlayerPrivate::hasVideo() const { - // This is not used at the moment - return true; + if (!m_qtMovie) + return false; + return m_qtMovie->hasVideo(); } void MediaPlayerPrivate::setVolume(float volume) diff --git a/WebCore/platform/graphics/win/QTMovieWin.cpp b/WebCore/platform/graphics/win/QTMovieWin.cpp index 8eee41b..32aecd3 100644 --- a/WebCore/platform/graphics/win/QTMovieWin.cpp +++ b/WebCore/platform/graphics/win/QTMovieWin.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Computer, 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 @@ -710,6 +710,14 @@ void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount) } } + +bool QTMovieWin::hasVideo() const +{ + if (!m_private->m_movie) + return false; + return (GetMovieIndTrackType(m_private->m_movie, 1, VisualMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly)); +} + pascal OSErr movieDrawingCompleteProc(Movie movie, long data) { UppParam param; diff --git a/WebCore/platform/graphics/win/QTMovieWin.h b/WebCore/platform/graphics/win/QTMovieWin.h index e31780a..2186974 100644 --- a/WebCore/platform/graphics/win/QTMovieWin.h +++ b/WebCore/platform/graphics/win/QTMovieWin.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Computer, 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 @@ -86,6 +86,8 @@ public: void disableUnsupportedTracks(unsigned& enabledTrackCount); + bool hasVideo() const; + static unsigned countSupportedTypes(); static void getSupportedType(unsigned index, const UChar*& str, unsigned& len); diff --git a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp index 0e9f9fb..9d5c3b9 100644 --- a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp +++ b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp @@ -91,6 +91,7 @@ void SimpleFontData::platformCommonDestroy() { // We don't hash this on Win32, so it's effectively owned by us. delete m_smallCapsFontData; + m_smallCapsFontData = 0; ScriptFreeCache(&m_scriptCache); delete m_scriptFontProperties; @@ -124,7 +125,7 @@ bool SimpleFontData::containsCharacters(const UChar* characters, int length) con // FIXME: Microsoft documentation seems to imply that characters can be output using a given font and DC // merely by testing code page intersection. This seems suspect though. Can't a font only partially // cover a given code page? - IMLangFontLink2* langFontLink = FontCache::getFontLinkInterface(); + IMLangFontLink2* langFontLink = fontCache()->getFontLinkInterface(); if (!langFontLink) return false; @@ -176,6 +177,7 @@ void SimpleFontData::determinePitch() float SimpleFontData::widthForGDIGlyph(Glyph glyph) const { HDC hdc = GetDC(0); + SetGraphicsMode(hdc, GM_ADVANCED); HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont()); int width; GetCharWidthI(hdc, glyph, 1, 0, &width); diff --git a/WebCore/platform/graphics/wx/FontPlatformData.h b/WebCore/platform/graphics/wx/FontPlatformData.h index e3a3cce..d2394dc 100644 --- a/WebCore/platform/graphics/wx/FontPlatformData.h +++ b/WebCore/platform/graphics/wx/FontPlatformData.h @@ -81,7 +81,7 @@ public: bool operator==(const FontPlatformData& other) const { if (m_fontState == VALID) - return other.m_fontState == VALID && m_font.Ok() && other.m_font.Ok() && m_font.IsSameAs(other.m_font); + return other.m_fontState == VALID && m_font.IsOk() && other.m_font.IsOk() && m_font.IsSameAs(other.m_font); else return m_fontState == other.m_fontState; } @@ -89,7 +89,7 @@ public: bool isHashTableDeletedValue() const { return m_fontState == DELETED; } unsigned computeHash() const { - ASSERT(m_font.Ok()); + ASSERT(m_font.IsOk()); // make a hash that is unique for this font, but not globally unique - that is, // a font whose properties are equal should generate the same hash diff --git a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp index 435e7ce..59e388e 100644 --- a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp +++ b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "GraphicsContext.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "FloatRect.h" #include "Font.h" #include "IntRect.h" @@ -284,7 +284,7 @@ void GraphicsContext::clip(const FloatRect& r) wxPoint pos(0, 0); if (windc) { -#ifndef __WXGTK__ +#if !defined(__WXGTK__) || wxCHECK_VERSION(2,9,0) wxWindow* window = windc->GetWindow(); #else wxWindow* window = windc->m_owner; @@ -349,10 +349,10 @@ void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*) notImplemented(); } -AffineTransform GraphicsContext::getCTM() const +TransformationMatrix GraphicsContext::getCTM() const { notImplemented(); - return AffineTransform(); + return TransformationMatrix(); } void GraphicsContext::translate(float tx, float ty) @@ -414,7 +414,13 @@ void GraphicsContext::setURLForRect(const KURL&, const IntRect&) void GraphicsContext::setCompositeOperation(CompositeOperator op) { if (m_data->context) + { +#if wxCHECK_VERSION(2,9,0) + m_data->context->SetLogicalFunction(static_cast<wxRasterOperationMode>(getWxCompositingOperation(op, false))); +#else m_data->context->SetLogicalFunction(getWxCompositingOperation(op, false)); +#endif + } } void GraphicsContext::beginPath() @@ -455,7 +461,7 @@ void GraphicsContext::setPlatformFillColor(const Color& color) m_data->context->SetBrush(wxBrush(color)); } -void GraphicsContext::concatCTM(const AffineTransform& transform) +void GraphicsContext::concatCTM(const TransformationMatrix& transform) { if (paintingDisabled()) return; @@ -464,7 +470,7 @@ void GraphicsContext::concatCTM(const AffineTransform& transform) return; } -void GraphicsContext::setUseAntialiasing(bool enable) +void GraphicsContext::setPlatformShouldAntialias(bool enable) { if (paintingDisabled()) return; diff --git a/WebCore/platform/graphics/wx/ImageSourceWx.cpp b/WebCore/platform/graphics/wx/ImageSourceWx.cpp index 3ce4f2a..d523354 100644 --- a/WebCore/platform/graphics/wx/ImageSourceWx.cpp +++ b/WebCore/platform/graphics/wx/ImageSourceWx.cpp @@ -30,6 +30,7 @@ #include "GIFImageDecoder.h" #include "ICOImageDecoder.h" #include "JPEGImageDecoder.h" +#include "NotImplemented.h" #include "PNGImageDecoder.h" #include "SharedBuffer.h" #include "XBMImageDecoder.h" @@ -92,7 +93,7 @@ ImageSource::ImageSource() ImageSource::~ImageSource() { - delete m_decoder; + clear(true); } bool ImageSource::initialized() const @@ -141,6 +142,12 @@ int ImageSource::repetitionCount() return m_decoder->repetitionCount(); } +String ImageSource::filenameExtension() const +{ + notImplemented(); + return String(); +} + size_t ImageSource::frameCount() const { return m_decoder ? m_decoder->frameCount() : 0; @@ -152,10 +159,18 @@ bool ImageSource::frameIsCompleteAtIndex(size_t index) return (m_decoder && m_decoder->frameBufferAtIndex(index) != 0); } -void ImageSource::clear() +void ImageSource::clear(bool destroyAll, size_t clearBeforeFrame, SharedBuffer* data, bool allDataReceived) { - delete m_decoder; + 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) @@ -205,8 +220,9 @@ NativeImagePtr ImageSource::createFrameAtIndex(size_t index) } } - +#if !wxCHECK_VERSION(2,9,0) bmp->UseAlpha(); +#endif ASSERT(bmp->IsOk()); return bmp; } diff --git a/WebCore/platform/graphics/wx/ImageWx.cpp b/WebCore/platform/graphics/wx/ImageWx.cpp index a05a31f..e52e9ff 100644 --- a/WebCore/platform/graphics/wx/ImageWx.cpp +++ b/WebCore/platform/graphics/wx/ImageWx.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "Image.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "BitmapImage.h" #include "FloatRect.h" #include "GraphicsContext.h" @@ -52,15 +52,17 @@ namespace WebCore { // this is in GraphicsContextWx.cpp int getWxCompositingOperation(CompositeOperator op, bool hasAlpha); -void FrameData::clear() +bool FrameData::clear(bool clearMetadata) { + if (clearMetadata) + m_haveMetadata = false; + if (m_frame) { delete m_frame; m_frame = 0; - // NOTE: We purposefully don't reset metadata here, so that even if we - // throw away previously-decoded data, animation loops can still access - // properties like frame durations without re-decoding. + return true; } + return false; } // ================================================ @@ -95,6 +97,7 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR #if USE(WXGC) wxGCDC* context = (wxGCDC*)ctxt->platformContext(); + wxGraphicsContext* gc = context->GetGraphicsContext(); #else wxWindowDC* context = ctxt->platformContext(); #endif @@ -114,7 +117,29 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR // Set the compositing operation. ctxt->setCompositeOperation(op); + +#if USE(WXGC) + float scaleX = src.width() / dst.width(); + float scaleY = src.height() / dst.height(); + FloatRect adjustedDestRect = dst; + FloatSize selfSize = currentFrameSize(); + + if (src.size() != selfSize) { + adjustedDestRect.setLocation(FloatPoint(dst.x() - src.x() / scaleX, dst.y() - src.y() / scaleY)); + adjustedDestRect.setSize(FloatSize(selfSize.width() / scaleX, selfSize.height() / scaleY)); + } + + // If the image is only partially loaded, then shrink the destination rect that we're drawing into accordingly. + int currHeight = bitmap->GetHeight(); + if (currHeight < selfSize.height()) + adjustedDestRect.setHeight(adjustedDestRect.height() * currHeight / selfSize.height()); + + gc->PushState(); + gc->Clip(dst.x(), dst.y(), dst.width(), dst.height()); + gc->DrawBitmap(*bitmap, adjustedDestRect.x(), adjustedDestRect.y(), adjustedDestRect.width(), adjustedDestRect.height()); + gc->PopState(); +#else IntRect srcIntRect(src); IntRect dstIntRect(dst); bool rescaling = false; @@ -124,7 +149,8 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR wxImage img = bitmap->ConvertToImage(); img.Rescale(dstIntRect.width(), dstIntRect.height()); bitmap = new wxBitmap(img); - } + } + wxMemoryDC mydc; ASSERT(bitmap->GetRefData()); mydc.SelectObject(*bitmap); @@ -143,10 +169,12 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatR delete bitmap; bitmap = NULL; } +#endif + ctxt->restore(); } -void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, CompositeOperator, const FloatRect& dstRect) +void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, const TransformationMatrix& patternTransform, const FloatPoint& phase, CompositeOperator, const FloatRect& dstRect) { if (!m_source.initialized()) return; @@ -169,23 +197,33 @@ void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, c #if USE(WXGC) wxGraphicsContext* gc = context->GetGraphicsContext(); gc->ConcatTransform(patternTransform); -#endif - +#else wxMemoryDC mydc; mydc.SelectObject(*bitmap); +#endif - while ( currentW < dstRect.width() ) { - while ( currentH < dstRect.height() ) { + wxPoint origin(context->GetDeviceOrigin()); + wxSize clientSize(context->GetSize()); + + while ( currentW < dstRect.width() && currentW < clientSize.x - origin.x ) { + while ( currentH < dstRect.height() && currentH < clientSize.y - origin.y) { +#if USE(WXGC) + gc->DrawBitmap(*bitmap, (wxDouble)dstRect.x() + currentW, (wxDouble)dstRect.y() + currentH, (wxDouble)srcRect.width(), (wxDouble)srcRect.height()); +#else context->Blit((wxCoord)dstRect.x() + currentW, (wxCoord)dstRect.y() + currentH, (wxCoord)srcRect.width(), (wxCoord)srcRect.height(), &mydc, (wxCoord)srcRect.x(), (wxCoord)srcRect.y(), wxCOPY, true); +#endif currentH += srcRect.height(); } currentW += srcRect.width(); currentH = 0; } ctxt->restore(); + +#if !USE(WXGC) mydc.SelectObject(wxNullBitmap); +#endif // NB: delete is causing crashes during page load, but not during the deletion // itself. It occurs later on when a valid bitmap created in frameAtIndex diff --git a/WebCore/platform/graphics/wx/PathWx.cpp b/WebCore/platform/graphics/wx/PathWx.cpp index 5ff9914..60c71d5 100644 --- a/WebCore/platform/graphics/wx/PathWx.cpp +++ b/WebCore/platform/graphics/wx/PathWx.cpp @@ -26,10 +26,11 @@ #include "config.h" #include "Path.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "FloatPoint.h" #include "FloatRect.h" #include "NotImplemented.h" +#include "StrokeStyleApplier.h" #include <stdio.h> @@ -64,7 +65,7 @@ Path::Path() } Path::~Path() -{ +{ } Path::Path(const Path& path) @@ -73,7 +74,16 @@ Path::Path(const Path& path) } bool Path::contains(const FloatPoint& point, const WindRule rule) const -{ +{ +#if USE(WXGC) + if (m_path) { +#if wxCHECK_VERSION(2,9,0) + return m_path->Contains(point.x(), point.y(), static_cast<wxPolygonFillMode>(getWxWindRuleForWindRule(rule))); +#else + return m_path->Contains(point.x(), point.y(), getWxWindRuleForWindRule(rule)); +#endif + } +#endif return false; } @@ -93,6 +103,12 @@ FloatRect Path::boundingRect() const return FloatRect(); } +FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) +{ + notImplemented(); + return FloatRect(); +} + Path& Path::operator=(const Path&) { notImplemented(); @@ -121,60 +137,93 @@ void Path::moveTo(const FloatPoint& point) #endif } -void Path::addLineTo(const FloatPoint&) -{ - notImplemented(); +void Path::addLineTo(const FloatPoint& point) +{ +#if USE(WXGC) + if (m_path) + m_path->AddLineToPoint(point.x(), point.y()); +#endif } -void Path::addQuadCurveTo(const FloatPoint&, const FloatPoint&) -{ - notImplemented(); +void Path::addQuadCurveTo(const FloatPoint& control, const FloatPoint& end) +{ +#if USE(WXGC) + if (m_path) + m_path->AddQuadCurveToPoint(control.x(), control.y(), end.x(), end.y()); +#endif } -void Path::addBezierCurveTo(const FloatPoint&, const FloatPoint&, const FloatPoint&) -{ - notImplemented(); +void Path::addBezierCurveTo(const FloatPoint& control1, const FloatPoint& control2, const FloatPoint& end) +{ +#if USE(WXGC) + if (m_path) + m_path->AddCurveToPoint(control1.x(), control1.y(), control2.x(), control2.y(), end.x(), end.y()); +#endif } -void Path::addArcTo(const FloatPoint&, const FloatPoint&, float) -{ - notImplemented(); +void Path::addArcTo(const FloatPoint& point1, const FloatPoint& point2, float radius) +{ +#if USE(WXGC) + if (m_path) + m_path->AddArcToPoint(point1.x(), point1.y(), point2.x(), point2.y(), radius); +#endif } void Path::closeSubpath() -{ - notImplemented(); +{ +#if USE(WXGC) + if (m_path) + m_path->CloseSubpath(); +#endif } -void Path::addArc(const FloatPoint&, float, float, float, bool) -{ - notImplemented(); +void Path::addArc(const FloatPoint& point, float radius, float startAngle, float endAngle, bool clockwise) +{ +#if USE(WXGC) + if (m_path) + m_path->AddArc(point.x(), point.y(), radius, startAngle, endAngle, clockwise); +#endif } -void Path::addRect(const FloatRect&) -{ - notImplemented(); +void Path::addRect(const FloatRect& rect) +{ +#if USE(WXGC) + if (m_path) + m_path->AddRectangle(rect.x(), rect.y(), rect.width(), rect.height()); +#endif } -void Path::addEllipse(const FloatRect&) -{ - notImplemented(); +void Path::addEllipse(const FloatRect& rect) +{ +#if USE(WXGC) + if (m_path) + m_path->AddEllipse(rect.x(), rect.y(), rect.width(), rect.height()); +#endif } -void Path::transform(const AffineTransform&) -{ - notImplemented(); +void Path::transform(const TransformationMatrix& transform) +{ +#if USE(WXGC) + if (m_path) + m_path->Transform(transform); +#endif } void Path::apply(void* info, PathApplierFunction function) const -{ +{ notImplemented(); } bool Path::isEmpty() const { - notImplemented(); - return false; +#if USE(WXGC) + if (m_path) { + wxDouble width, height; + m_path->GetBox(NULL, NULL, &width, &height); + return (width == 0 && height == 0); + } +#endif + return true; } } diff --git a/WebCore/platform/graphics/wx/AffineTransformWx.cpp b/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp index 12485ae..e6a02b8 100644 --- a/WebCore/platform/graphics/wx/AffineTransformWx.cpp +++ b/WebCore/platform/graphics/wx/TransformationMatrixWx.cpp @@ -20,11 +20,11 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "FloatRect.h" #include "IntRect.h" @@ -37,105 +37,125 @@ namespace WebCore { #if USE(WXGC) -AffineTransform::AffineTransform(const PlatformAffineTransform& matrix) +TransformationMatrix::TransformationMatrix(const PlatformTransformationMatrix& matrix) { m_transform = matrix; } #endif -AffineTransform::AffineTransform(double a, double b, double c, double d, double e, double f) +TransformationMatrix::TransformationMatrix(double a, double b, double c, double d, double e, double f) { #if USE(WXGC) - wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer(); + wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer(); m_transform = renderer->CreateMatrix(); #endif setMatrix(a, b, c, d, e, f); } -AffineTransform::AffineTransform() -{ +TransformationMatrix::TransformationMatrix() +{ // NB: If we ever support using Cairo backend on Win/Mac, this will need to be // changed somehow (though I'm not sure how as we don't have a reference to the // graphics context here. #if USE(WXGC) - wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer(); + wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetDefaultRenderer(); m_transform = renderer->CreateMatrix(); #endif } -AffineTransform AffineTransform::inverse() const +TransformationMatrix TransformationMatrix::inverse() const { notImplemented(); return *this; } -void AffineTransform::setMatrix(double a, double b, double c, double d, double e, double f) +void TransformationMatrix::setMatrix(double a, double b, double c, double d, double e, double f) { #if USE(WXGC) m_transform.Set(a, b, c, d, e, f); #endif } -void AffineTransform::map(double x, double y, double *x2, double *y2) const -{ +void TransformationMatrix::map(double x, double y, double *x2, double *y2) const +{ notImplemented(); } -IntRect AffineTransform::mapRect(const IntRect &rect) const +IntRect TransformationMatrix::mapRect(const IntRect &rect) const { - notImplemented(); +#if USE(WXGC) + double x, y, width, height; + x = rect.x(); + y = rect.y(); + width = rect.width(); + height = rect.height(); + + m_transform.TransformPoint(&x, &y); + m_transform.TransformDistance(&width, &height); + return IntRect(x, y, width, height); +#endif return IntRect(); } -FloatRect AffineTransform::mapRect(const FloatRect &rect) const +FloatRect TransformationMatrix::mapRect(const FloatRect &rect) const { - notImplemented(); +#if USE(WXGC) + double x, y, width, height; + x = rect.x(); + y = rect.y(); + width = rect.width(); + height = rect.height(); + + m_transform.TransformPoint(&x, &y); + m_transform.TransformDistance(&width, &height); + return FloatRect(x, y, width, height); +#endif return FloatRect(); } -AffineTransform& AffineTransform::scale(double sx, double sy) +TransformationMatrix& TransformationMatrix::scale(double sx, double sy) { #if USE(WXGC) - m_transform.Scale((wxDouble)sx, (wxDouble)sy); + m_transform.Scale((wxDouble)sx, (wxDouble)sy); #endif - return *this; + return *this; } -void AffineTransform::reset() +void TransformationMatrix::reset() { notImplemented(); } -AffineTransform& AffineTransform::rotate(double d) -{ +TransformationMatrix& TransformationMatrix::rotate(double d) +{ #if USE(WXGC) - m_transform.Rotate((wxDouble)d); + m_transform.Rotate((wxDouble)d); #endif - return *this; + return *this; } -AffineTransform& AffineTransform::translate(double tx, double ty) -{ +TransformationMatrix& TransformationMatrix::translate(double tx, double ty) +{ #if USE(WXGC) - m_transform.Translate((wxDouble)tx, (wxDouble)ty); + m_transform.Translate((wxDouble)tx, (wxDouble)ty); #endif - return *this; + return *this; } -AffineTransform& AffineTransform::shear(double sx, double sy) -{ - notImplemented(); - return *this; +TransformationMatrix& TransformationMatrix::shear(double sx, double sy) +{ + notImplemented(); + return *this; } -AffineTransform& AffineTransform::operator*=(const AffineTransform& other) -{ +TransformationMatrix& TransformationMatrix::operator*=(const TransformationMatrix& other) +{ notImplemented(); - return *this; + return *this; } -bool AffineTransform::operator== (const AffineTransform &other) const +bool TransformationMatrix::operator== (const TransformationMatrix &other) const { #if USE(WXGC) return m_transform.IsEqual((wxGraphicsMatrix)other); @@ -145,26 +165,26 @@ bool AffineTransform::operator== (const AffineTransform &other) const #endif } -AffineTransform AffineTransform::operator* (const AffineTransform &other) +TransformationMatrix TransformationMatrix::operator* (const TransformationMatrix &other) { notImplemented(); return *this; //m_transform * other.m_transform; } -double AffineTransform::det() const -{ - notImplemented(); +double TransformationMatrix::det() const +{ + notImplemented(); return 0; } #if USE(WXGC) -AffineTransform::operator wxGraphicsMatrix() const +TransformationMatrix::operator wxGraphicsMatrix() const { return m_transform; } #endif -double AffineTransform::a() const +double TransformationMatrix::a() const { double a = 0; #if USE(WXGC) @@ -173,12 +193,12 @@ double AffineTransform::a() const return a; } -void AffineTransform::setA(double a) +void TransformationMatrix::setA(double a) { setMatrix(a, b(), c(), d(), e(), f()); } -double AffineTransform::b() const +double TransformationMatrix::b() const { double b = 0; #if USE(WXGC) @@ -187,12 +207,12 @@ double AffineTransform::b() const return b; } -void AffineTransform::setB(double b) +void TransformationMatrix::setB(double b) { setMatrix(a(), b, c(), d(), e(), f()); } -double AffineTransform::c() const +double TransformationMatrix::c() const { double c = 0; #if USE(WXGC) @@ -201,12 +221,12 @@ double AffineTransform::c() const return c; } -void AffineTransform::setC(double c) +void TransformationMatrix::setC(double c) { setMatrix(a(), b(), c, d(), e(), f()); } -double AffineTransform::d() const +double TransformationMatrix::d() const { double d = 0; #if USE(WXGC) @@ -215,12 +235,12 @@ double AffineTransform::d() const return d; } -void AffineTransform::setD(double d) +void TransformationMatrix::setD(double d) { setMatrix(a(), b(), c(), d, e(), f()); } -double AffineTransform::e() const +double TransformationMatrix::e() const { double e = 0; #if USE(WXGC) @@ -229,12 +249,12 @@ double AffineTransform::e() const return e; } -void AffineTransform::setE(double e) +void TransformationMatrix::setE(double e) { setMatrix(a(), b(), c(), d(), e, f()); } -double AffineTransform::f() const +double TransformationMatrix::f() const { double f = 0; #if USE(WXGC) @@ -243,7 +263,7 @@ double AffineTransform::f() const return f; } -void AffineTransform::setF(double f) +void TransformationMatrix::setF(double f) { setMatrix(a(), b(), c(), d(), e(), f); } diff --git a/WebCore/platform/gtk/FileSystemGtk.cpp b/WebCore/platform/gtk/FileSystemGtk.cpp index 965cea9..4f0ae01 100644 --- a/WebCore/platform/gtk/FileSystemGtk.cpp +++ b/WebCore/platform/gtk/FileSystemGtk.cpp @@ -29,7 +29,6 @@ #include <glib.h> #include <glib/gstdio.h> -#include <glib/gutils.h> #include <unistd.h> diff --git a/WebCore/platform/gtk/GeolocationServiceGtk.cpp b/WebCore/platform/gtk/GeolocationServiceGtk.cpp new file mode 100644 index 0000000..0c80dd6 --- /dev/null +++ b/WebCore/platform/gtk/GeolocationServiceGtk.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2008 Holger Hans Peter Freyther + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "GeolocationServiceGtk.h" + +namespace WebCore { + +GeolocationService* GeolocationService::create(GeolocationServiceClient* client) +{ + return new GeolocationServiceGtk(client); +} + +GeolocationServiceGtk::GeolocationServiceGtk(GeolocationServiceClient* client) + : GeolocationService(client) +{} + +bool GeolocationServiceGtk::startUpdating(PositionOptions*) +{ + return false; +} + +void GeolocationServiceGtk::stopUpdating() +{ +} + +void GeolocationServiceGtk::suspend() +{ +} + +void GeolocationServiceGtk::resume() +{ +} + +Geoposition* GeolocationServiceGtk::lastPosition() const +{ + return 0; +} + +PositionError* GeolocationServiceGtk::lastError() const +{ + return 0; +} + +} diff --git a/WebCore/platform/gtk/GeolocationServiceGtk.h b/WebCore/platform/gtk/GeolocationServiceGtk.h new file mode 100644 index 0000000..02aff2d --- /dev/null +++ b/WebCore/platform/gtk/GeolocationServiceGtk.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2008 Holger Hans Peter Freyther + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef GeolocationServiceGtk_h +#define GeolocationServiceGtk_h + +#include "GeolocationService.h" + +namespace WebCore { + class GeolocationServiceGtk : public GeolocationService { + public: + GeolocationServiceGtk(GeolocationServiceClient*); + + virtual bool startUpdating(PositionOptions*); + virtual void stopUpdating(); + + virtual void suspend(); + virtual void resume(); + + Geoposition* lastPosition() const; + PositionError* lastError() const; + }; +} + +#endif diff --git a/WebCore/platform/gtk/KeyEventGtk.cpp b/WebCore/platform/gtk/KeyEventGtk.cpp index 153ef19..e0742f4 100644 --- a/WebCore/platform/gtk/KeyEventGtk.cpp +++ b/WebCore/platform/gtk/KeyEventGtk.cpp @@ -36,7 +36,9 @@ #include <gdk/gdk.h> #include <gdk/gdkkeysyms.h> -#include <gtk/gtkversion.h> + +// GTK_CHECK_VERSION is defined in gtk/gtkversion.h +#include <gtk/gtk.h> namespace WebCore { @@ -464,6 +466,32 @@ static int windowsKeyCodeForKeyEvent(unsigned int keycode) // VK_NONAME (FC) Reserved for future use // VK_PA1 (FD) PA1 key // VK_OEM_CLEAR (FE) Clear key + case GDK_F1: + case GDK_F2: + case GDK_F3: + case GDK_F4: + case GDK_F5: + case GDK_F6: + case GDK_F7: + case GDK_F8: + case GDK_F9: + case GDK_F10: + case GDK_F11: + case GDK_F12: + case GDK_F13: + case GDK_F14: + case GDK_F15: + case GDK_F16: + case GDK_F17: + case GDK_F18: + case GDK_F19: + case GDK_F20: + case GDK_F21: + case GDK_F22: + case GDK_F23: + case GDK_F24: + return VK_F1 + (keycode - GDK_F1); + default: return 0; } diff --git a/WebCore/platform/gtk/MIMETypeRegistryGtk.cpp b/WebCore/platform/gtk/MIMETypeRegistryGtk.cpp index 20fe0cb..8afb60f 100644 --- a/WebCore/platform/gtk/MIMETypeRegistryGtk.cpp +++ b/WebCore/platform/gtk/MIMETypeRegistryGtk.cpp @@ -39,6 +39,7 @@ static const ExtensionMap extensionMap [] = { { "bmp", "image/bmp" }, { "css", "text/css" }, { "gif", "image/gif" }, + { "htm", "text/html" }, { "html", "text/html" }, { "ico", "image/x-icon" }, { "jpeg", "image/jpeg" }, @@ -54,6 +55,8 @@ static const ExtensionMap extensionMap [] = { { "xml", "text/xml" }, { "xsl", "text/xsl" }, { "xhtml", "application/xhtml+xml" }, + { "wml", "text/vnd.wap.wml" }, + { "wmlc", "application/vnd.wap.wmlc" }, { 0, 0 } }; diff --git a/WebCore/platform/gtk/MouseEventGtk.cpp b/WebCore/platform/gtk/MouseEventGtk.cpp index f441f00..2400ebf 100644 --- a/WebCore/platform/gtk/MouseEventGtk.cpp +++ b/WebCore/platform/gtk/MouseEventGtk.cpp @@ -27,11 +27,12 @@ #include "config.h" #include "PlatformMouseEvent.h" -#include "SystemTime.h" #include "Assertions.h" #include <gdk/gdk.h> -#include <gtk/gtkversion.h> + +// GTK_CHECK_VERSION is defined in gtk/gtkversion.h +#include <gtk/gtk.h> namespace WebCore { diff --git a/WebCore/platform/gtk/PlatformScreenGtk.cpp b/WebCore/platform/gtk/PlatformScreenGtk.cpp index 9788253..3512be1 100644 --- a/WebCore/platform/gtk/PlatformScreenGtk.cpp +++ b/WebCore/platform/gtk/PlatformScreenGtk.cpp @@ -47,10 +47,20 @@ namespace WebCore { int screenDepth(Widget* widget) { GtkWidget* container = GTK_WIDGET(widget->root()->hostWindow()->platformWindow()); + if (!container) return 24; - GdkVisual* visual = gdk_drawable_get_visual(GDK_DRAWABLE(GTK_WIDGET(widget->root()->hostWindow()->platformWindow())->window)); + if (!GTK_WIDGET_REALIZED(container)) { + GtkWidget* toplevel = gtk_widget_get_toplevel(container); + if (GTK_WIDGET_TOPLEVEL(toplevel)) + container = toplevel; + else + return 24; + } + + + GdkVisual* visual = gdk_drawable_get_visual(GDK_DRAWABLE(container->window)); return visual->depth; } @@ -75,8 +85,8 @@ bool screenIsMonochrome(Widget* widget) FloatRect screenRect(Widget* widget) { - GtkWidget* container = GTK_WIDGET(widget->root()->hostWindow()->platformWindow()); - if (!container) + GtkWidget* container = gtk_widget_get_toplevel(GTK_WIDGET(widget->root()->hostWindow()->platformWindow())); + if (!GTK_WIDGET_TOPLEVEL(container)) return FloatRect(); GdkScreen* screen = gtk_widget_has_screen(container) ? gtk_widget_get_screen(container) : gdk_screen_get_default(); diff --git a/WebCore/platform/gtk/RenderThemeGtk.cpp b/WebCore/platform/gtk/RenderThemeGtk.cpp index bf8b8d7..ee462e0 100644 --- a/WebCore/platform/gtk/RenderThemeGtk.cpp +++ b/WebCore/platform/gtk/RenderThemeGtk.cpp @@ -23,9 +23,10 @@ #include "config.h" #include "RenderThemeGtk.h" -#include "AffineTransform.h" +#include "TransformationMatrix.h" #include "GraphicsContext.h" #include "NotImplemented.h" +#include "RenderBox.h" #include "RenderObject.h" #include "gtkdrawing.h" @@ -82,10 +83,16 @@ bool RenderThemeGtk::controlSupportsTints(const RenderObject* o) const int RenderThemeGtk::baselinePosition(const RenderObject* o) const { + if (!o->isBox()) + return 0; + // FIXME: This strategy is possibly incorrect for the GTK+ port. if (o->style()->appearance() == CheckboxPart || - o->style()->appearance() == RadioPart) - return o->marginTop() + o->height() - 2; + o->style()->appearance() == RadioPart) { + const RenderBox* box = toRenderBox(o); + return box->marginTop() + box->height() - 2; + } + return RenderTheme::baselinePosition(o); } @@ -161,7 +168,7 @@ static bool paintMozWidget(RenderTheme* theme, GtkThemeWidgetType type, RenderOb break; } - AffineTransform ctm = i.context->getCTM(); + TransformationMatrix ctm = i.context->getCTM(); IntPoint pos = ctm.mapPoint(rect.location()); GdkRectangle gdkRect = IntRect(pos.x(), pos.y(), rect.width(), rect.height()); @@ -409,7 +416,7 @@ Color RenderThemeGtk::inactiveListBoxSelectionForegroundColor() const return widget->style->text[GTK_STATE_ACTIVE]; } -double RenderThemeGtk::caretBlinkFrequency() const +double RenderThemeGtk::caretBlinkInterval() const { GtkSettings* settings = gtk_settings_get_default(); diff --git a/WebCore/platform/gtk/RenderThemeGtk.h b/WebCore/platform/gtk/RenderThemeGtk.h index dda8bc8..76f7a0a 100644 --- a/WebCore/platform/gtk/RenderThemeGtk.h +++ b/WebCore/platform/gtk/RenderThemeGtk.h @@ -66,7 +66,7 @@ public: virtual Color inactiveListBoxSelectionBackgroundColor() const; virtual Color inactiveListBoxSelectionForegroundColor() const; - virtual double caretBlinkFrequency() const; + virtual double caretBlinkInterval() const; // System fonts. virtual void systemFont(int propId, FontDescription&) const; diff --git a/WebCore/platform/gtk/ScrollbarGtk.cpp b/WebCore/platform/gtk/ScrollbarGtk.cpp index 099895d..df165e3 100644 --- a/WebCore/platform/gtk/ScrollbarGtk.cpp +++ b/WebCore/platform/gtk/ScrollbarGtk.cpp @@ -76,7 +76,7 @@ ScrollbarGtk::~ScrollbarGtk() g_object_unref(G_OBJECT(platformWidget())); } -void ScrollbarGtk::frameRectsChanged() const +void ScrollbarGtk::frameRectsChanged() { if (!parent() || !parent()->isScrollViewScrollbar(this)) return; @@ -114,23 +114,6 @@ void ScrollbarGtk::setFrameRect(const IntRect& rect) frameRectsChanged(); } -void ScrollbarGtk::frameRectsChanged() -{ - if (!parent()) - return; - - ASSERT(parent()->isFrameView()); - - FrameView* frameView = static_cast<FrameView*>(parent()); - IntRect windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size()); - - IntSize sz = frameRect().size(); - sz.clampNegativeToZero(); - - GtkAllocation allocation = { windowRect.x(), windowRect.y(), sz.width(), sz.height() }; - gtk_widget_size_allocate(platformWidget(), &allocation); -} - void ScrollbarGtk::gtkValueChanged(GtkAdjustment*, ScrollbarGtk* that) { that->setValue(static_cast<int>(gtk_adjustment_get_value(that->m_adjustment))); diff --git a/WebCore/platform/gtk/ScrollbarGtk.h b/WebCore/platform/gtk/ScrollbarGtk.h index 50e9184..11ff079 100644 --- a/WebCore/platform/gtk/ScrollbarGtk.h +++ b/WebCore/platform/gtk/ScrollbarGtk.h @@ -48,14 +48,13 @@ public: virtual void setEnabled(bool); - virtual void frameRectsChanged() const; + virtual void frameRectsChanged(); protected: ScrollbarGtk(ScrollbarClient*, ScrollbarOrientation, ScrollbarControlSize); virtual void updateThumbPosition(); virtual void updateThumbProportion(); - virtual void frameRectsChanged(); private: static void gtkValueChanged(GtkAdjustment*, ScrollbarGtk*); diff --git a/WebCore/platform/gtk/SharedTimerGtk.cpp b/WebCore/platform/gtk/SharedTimerGtk.cpp index e0a5b60..0a760ed 100644 --- a/WebCore/platform/gtk/SharedTimerGtk.cpp +++ b/WebCore/platform/gtk/SharedTimerGtk.cpp @@ -28,8 +28,8 @@ #include "config.h" #include "SharedTimer.h" -#include "SystemTime.h" #include <wtf/Assertions.h> +#include <wtf/CurrentTime.h> #include <glib.h> namespace WebCore { diff --git a/WebCore/platform/gtk/TemporaryLinkStubs.cpp b/WebCore/platform/gtk/TemporaryLinkStubs.cpp index 5093794..edabd10 100644 --- a/WebCore/platform/gtk/TemporaryLinkStubs.cpp +++ b/WebCore/platform/gtk/TemporaryLinkStubs.cpp @@ -58,8 +58,6 @@ Vector<char> loadResourceIntoArray(const char* resourceName) void PluginView::invalidateRegion(NPRegion) { notImplemented(); } -Color WebCore::focusRingColor() { return Color(); } - namespace WebCore { void getSupportedKeySizes(Vector<String>&) { notImplemented(); } String signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String &challengeString, const KURL &url) { return String(); } diff --git a/WebCore/platform/gtk/WheelEventGtk.cpp b/WebCore/platform/gtk/WheelEventGtk.cpp index fbe31f7..64ec65a 100644 --- a/WebCore/platform/gtk/WheelEventGtk.cpp +++ b/WebCore/platform/gtk/WheelEventGtk.cpp @@ -29,7 +29,9 @@ #include "PlatformWheelEvent.h" #include <gdk/gdk.h> -#include <gtk/gtkversion.h> + +// GTK_CHECK_VERSION is defined in gtk/gtkversion.h +#include <gtk/gtk.h> namespace WebCore { diff --git a/WebCore/platform/gtk/gtk2drawing.c b/WebCore/platform/gtk/gtk2drawing.c index 83b4cb4..dd46e74 100644 --- a/WebCore/platform/gtk/gtk2drawing.c +++ b/WebCore/platform/gtk/gtk2drawing.c @@ -89,7 +89,7 @@ static GtkWidget* gMenuItemWidget; static GtkWidget* gImageMenuItemWidget; static GtkWidget* gCheckMenuItemWidget; static GtkWidget* gTreeViewWidget; -static GtkWidget* gMiddleTreeViewColumn; +static GtkTreeViewColumn* gMiddleTreeViewColumn; static GtkWidget* gTreeHeaderCellWidget; static GtkWidget* gTreeHeaderSortArrowWidget; static GtkWidget* gExpanderWidget; @@ -143,7 +143,7 @@ setup_widget_prototype(GtkWidget* widget) gtk_container_add(GTK_CONTAINER(protoLayout), widget); gtk_widget_realize(widget); - g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); return MOZ_GTK_SUCCESS; } @@ -288,7 +288,7 @@ moz_gtk_get_combo_box_inner_button(GtkWidget *widget, gpointer client_data) g_object_add_weak_pointer(G_OBJECT(widget), (gpointer) &gComboBoxButtonWidget); gtk_widget_realize(widget); - g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); } } @@ -307,7 +307,7 @@ moz_gtk_get_combo_box_button_inner_widgets(GtkWidget *widget, } else return; gtk_widget_realize(widget); - g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); } static gint @@ -348,7 +348,7 @@ ensure_combo_box_widgets() &gComboBoxArrowWidget); gtk_widget_realize(gComboBoxArrowWidget); g_object_set_data(G_OBJECT(gComboBoxArrowWidget), - "transparent-bg-hint", TRUE); + "transparent-bg-hint", GINT_TO_POINTER(TRUE)); } } else { /* Shouldn't be reached with current internal gtk implementation; we @@ -398,7 +398,7 @@ moz_gtk_get_combo_box_entry_inner_widgets(GtkWidget *widget, } else return; gtk_widget_realize(widget); - g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); } static void @@ -409,7 +409,8 @@ moz_gtk_get_combo_box_entry_arrow(GtkWidget *widget, gpointer client_data) g_object_add_weak_pointer(G_OBJECT(widget), (gpointer) &gComboBoxEntryArrowWidget); gtk_widget_realize(widget); - g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", + GINT_TO_POINTER(TRUE)); } } @@ -461,7 +462,7 @@ ensure_combo_box_entry_widgets() &gComboBoxEntryArrowWidget); gtk_widget_realize(gComboBoxEntryArrowWidget); g_object_set_data(G_OBJECT(gComboBoxEntryArrowWidget), - "transparent-bg-hint", TRUE); + "transparent-bg-hint", GINT_TO_POINTER(TRUE)); } } else { /* Shouldn't be reached with current internal gtk implementation; @@ -501,7 +502,8 @@ ensure_toolbar_widget() gToolbarWidget = gtk_toolbar_new(); gtk_container_add(GTK_CONTAINER(gHandleBoxWidget), gToolbarWidget); gtk_widget_realize(gToolbarWidget); - g_object_set_data(G_OBJECT(gToolbarWidget), "transparent-bg-hint", TRUE); + g_object_set_data(G_OBJECT(gToolbarWidget), "transparent-bg-hint", + GINT_TO_POINTER(TRUE)); } return MOZ_GTK_SUCCESS; } @@ -590,7 +592,7 @@ ensure_menu_bar_item_widget() gMenuBarItemWidget); gtk_widget_realize(gMenuBarItemWidget); g_object_set_data(G_OBJECT(gMenuBarItemWidget), - "transparent-bg-hint", TRUE); + "transparent-bg-hint", GINT_TO_POINTER(TRUE)); } return MOZ_GTK_SUCCESS; } @@ -605,7 +607,7 @@ ensure_menu_popup_widget() gMenuPopupWidget); gtk_widget_realize(gMenuPopupWidget); g_object_set_data(G_OBJECT(gMenuPopupWidget), - "transparent-bg-hint", TRUE); + "transparent-bg-hint", GINT_TO_POINTER(TRUE)); } return MOZ_GTK_SUCCESS; } @@ -620,7 +622,7 @@ ensure_menu_item_widget() gMenuItemWidget); gtk_widget_realize(gMenuItemWidget); g_object_set_data(G_OBJECT(gMenuItemWidget), - "transparent-bg-hint", TRUE); + "transparent-bg-hint", GINT_TO_POINTER(TRUE)); } return MOZ_GTK_SUCCESS; } @@ -635,7 +637,7 @@ ensure_image_menu_item_widget() gImageMenuItemWidget); gtk_widget_realize(gImageMenuItemWidget); g_object_set_data(G_OBJECT(gImageMenuItemWidget), - "transparent-bg-hint", TRUE); + "transparent-bg-hint", GINT_TO_POINTER(TRUE)); } return MOZ_GTK_SUCCESS; } @@ -650,7 +652,7 @@ ensure_menu_separator_widget() gMenuSeparatorWidget); gtk_widget_realize(gMenuSeparatorWidget); g_object_set_data(G_OBJECT(gMenuSeparatorWidget), - "transparent-bg-hint", TRUE); + "transparent-bg-hint", GINT_TO_POINTER(TRUE)); } return MOZ_GTK_SUCCESS; } @@ -665,7 +667,7 @@ ensure_check_menu_item_widget() gCheckMenuItemWidget); gtk_widget_realize(gCheckMenuItemWidget); g_object_set_data(G_OBJECT(gCheckMenuItemWidget), - "transparent-bg-hint", TRUE); + "transparent-bg-hint", GINT_TO_POINTER(TRUE)); } return MOZ_GTK_SUCCESS; } @@ -720,9 +722,9 @@ ensure_tree_header_cell_widget() gTreeHeaderCellWidget = GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn)->button; gTreeHeaderSortArrowWidget = GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn)->arrow; g_object_set_data(G_OBJECT(gTreeHeaderCellWidget), - "transparent-bg-hint", TRUE); + "transparent-bg-hint", GINT_TO_POINTER(TRUE)); g_object_set_data(G_OBJECT(gTreeHeaderSortArrowWidget), - "transparent-bg-hint", TRUE); + "transparent-bg-hint", GINT_TO_POINTER(TRUE)); } return MOZ_GTK_SUCCESS; } @@ -1536,11 +1538,12 @@ moz_gtk_entry_paint(GdkDrawable* drawable, GdkRectangle* rect, * If the theme is able to cope with transparency, then we can skip pre-filling * and notify the theme it will paint directly on the canvas. */ if (theme_honors_transparency) { - g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", + GINT_TO_POINTER(TRUE)); } else { gdk_draw_rectangle(drawable, style->base_gc[bg_state], TRUE, cliprect->x, cliprect->y, cliprect->width, cliprect->height); - g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", FALSE); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(FALSE)); } /* Get the position of the inner window, see _gtk_entry_get_borders */ diff --git a/WebCore/platform/gtk/gtkdrawing.h b/WebCore/platform/gtk/gtkdrawing.h index 6e44d4a..eb6995a 100644 --- a/WebCore/platform/gtk/gtkdrawing.h +++ b/WebCore/platform/gtk/gtkdrawing.h @@ -49,7 +49,7 @@ #define _GTK_DRAWING_H_ #include <gdk/gdk.h> -#include <gtk/gtkstyle.h> +#include <gtk/gtk.h> #ifdef __cplusplus extern "C" { diff --git a/WebCore/platform/image-decoders/ImageDecoder.h b/WebCore/platform/image-decoders/ImageDecoder.h index 3df2e88..e21ddcf 100644 --- a/WebCore/platform/image-decoders/ImageDecoder.h +++ b/WebCore/platform/image-decoders/ImageDecoder.h @@ -28,6 +28,7 @@ #include "IntRect.h" #include "ImageSource.h" +#include "PlatformString.h" #include "SharedBuffer.h" #include <wtf/Vector.h> @@ -54,6 +55,16 @@ public: m_disposalMethod(DisposeNotSpecified), m_hasAlpha(false) {} + void clear() { + m_bytes.clear(); + m_rect = IntRect(); + m_height = 0; + m_status = FrameEmpty; + m_duration = 0; + m_disposalMethod = DisposeNotSpecified; + m_hasAlpha = false; + } + const RGBA32Array& bytes() const { return m_bytes; } RGBA32Array& bytes() { return m_bytes; } const IntRect& rect() const { return m_rect; } @@ -107,6 +118,9 @@ public: ImageDecoder() :m_sizeAvailable(false), m_failed(false) {} virtual ~ImageDecoder() {} + // The the filename extension usually associated with an undecoded image of this type. + virtual String filenameExtension() const = 0; + // All specific decoder plugins must do something with the data they are given. virtual void setData(SharedBuffer* data, bool allDataReceived) { m_data = data; } @@ -135,6 +149,14 @@ public: bool failed() const { return m_failed; } void setFailed() { m_failed = true; } + // Wipe out frames in the frame buffer cache before |clearBeforeFrame|, + // assuming this can be done without breaking decoding. Different decoders + // place different restrictions on what frames are safe to destroy, so this + // is left to them to implement. + // For convenience's sake, we provide a default (empty) implementation, + // since in practice only GIFs will ever use this. + virtual void clearFrameBufferCache(size_t clearBeforeFrame) { } + protected: RefPtr<SharedBuffer> m_data; // The encoded data. Vector<RGBA32Buffer> m_frameBufferCache; diff --git a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h index 0f515f0..d850cc7 100644 --- a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h +++ b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h @@ -36,6 +36,8 @@ class BMPImageReader; class BMPImageDecoder : public ImageDecoder { public: + virtual String filenameExtension() const { return "bmp"; } + // Whether or not the size information has been decoded yet. virtual bool isSizeAvailable() const; diff --git a/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp b/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp index 22a6f09..843e65a 100644 --- a/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp +++ b/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp @@ -156,9 +156,18 @@ int GIFImageDecoder::repetitionCount() const // packets sent back by the webserver) not always. Our caller is // responsible for waiting until image decoding has finished to ask this if // it needs an authoritative answer. In the meantime, we should default to - // "loop once", both in the reader and here. - if (m_reader) - m_repetitionCount = m_reader->repetitionCount(); + // "loop once". + if (m_reader) { + // Added wrinkle: ImageSource::clear() may destroy the reader, making + // the result from the reader _less_ authoritative on future calls. To + // detect this, the reader returns cLoopCountNotSeen (-2) instead of + // cAnimationLoopOnce (-1) when its current incarnation hasn't actually + // seen a loop count yet; in this case we return our previously-cached + // value. + const int repetitionCount = m_reader->repetitionCount(); + if (repetitionCount != cLoopCountNotSeen) + m_repetitionCount = repetitionCount; + } return m_repetitionCount; } @@ -174,6 +183,40 @@ RGBA32Buffer* GIFImageDecoder::frameBufferAtIndex(size_t index) return &frame; } +void GIFImageDecoder::clearFrameBufferCache(size_t clearBeforeFrame) +{ + // In some cases, like if the decoder was destroyed while animating, we + // can be asked to clear more frames than we currently have. + if (m_frameBufferCache.isEmpty()) + return; // Nothing to do. + // The "-1" here is tricky. It does not mean that |clearBeforeFrame| is the + // last frame we wish to preserve, but rather that we never want to clear + // the very last frame in the cache: it's empty (so clearing it is + // pointless), it's partial (so we don't want to clear it anyway), or the + // cache could be enlarged with a future setData() call and it could be + // needed to construct the next frame (see comments below). Callers can + // always use ImageSource::clear(true, ...) to completely free the memory in + // this case. + clearBeforeFrame = std::min(clearBeforeFrame, m_frameBufferCache.size() - 1); + const Vector<RGBA32Buffer>::iterator end(m_frameBufferCache.begin() + clearBeforeFrame); + for (Vector<RGBA32Buffer>::iterator i(m_frameBufferCache.begin()); i != end; ++i) { + if (i->status() == RGBA32Buffer::FrameEmpty) + continue; // Nothing to do. + + // The layout of frames is: + // [empty frames][complete frames][partial frame][empty frames] + // ...where each of these groups may be empty. We should not clear a + // partial frame since that's what's being decoded right now, and we + // also should not clear the last complete frame, since it may be needed + // when constructing the next frame. Note that "i + 1" is safe since + // i < end < m_frameBufferCache.end(). + if ((i->status() == RGBA32Buffer::FramePartial) || ((i + 1)->status() != RGBA32Buffer::FrameComplete)) + break; + + i->clear(); + } +} + // Feed data to the GIF reader. void GIFImageDecoder::decode(GIFQuery query, unsigned haltAtFrame) const { @@ -228,6 +271,7 @@ void GIFImageDecoder::initFrameBuffer(unsigned frameIndex) // first frame specifies this method, it will get treated like // DisposeOverwriteBgcolor below and reset to a completely empty image.) const RGBA32Buffer* prevBuffer = &m_frameBufferCache[--frameIndex]; + ASSERT(prevBuffer->status() == RGBA32Buffer::FrameComplete); RGBA32Buffer::FrameDisposalMethod prevMethod = prevBuffer->disposalMethod(); while ((frameIndex > 0) && @@ -360,7 +404,12 @@ void GIFImageDecoder::haveDecodedRow(unsigned frameIndex, void GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration, RGBA32Buffer::FrameDisposalMethod disposalMethod) { + // Initialize the frame if necessary. Some GIFs insert do-nothing frames, + // in which case we never reach haveDecodedRow() before getting here. RGBA32Buffer& buffer = m_frameBufferCache[frameIndex]; + if (buffer.status() == RGBA32Buffer::FrameEmpty) + initFrameBuffer(frameIndex); + buffer.ensureHeight(m_size.height()); buffer.setStatus(RGBA32Buffer::FrameComplete); buffer.setDuration(frameDuration); diff --git a/WebCore/platform/image-decoders/gif/GIFImageDecoder.h b/WebCore/platform/image-decoders/gif/GIFImageDecoder.h index b407b8d..02b43a2 100644 --- a/WebCore/platform/image-decoders/gif/GIFImageDecoder.h +++ b/WebCore/platform/image-decoders/gif/GIFImageDecoder.h @@ -39,6 +39,8 @@ public: GIFImageDecoder(); ~GIFImageDecoder(); + virtual String filenameExtension() const { return "gif"; } + // Take the data and store it. virtual void setData(SharedBuffer* data, bool allDataReceived); @@ -54,6 +56,8 @@ public: virtual RGBA32Buffer* frameBufferAtIndex(size_t index); + virtual void clearFrameBufferCache(size_t clearBeforeFrame); + virtual unsigned frameDurationAtIndex(size_t index) { return 0; } enum GIFQuery { GIFFullQuery, GIFSizeQuery, GIFFrameCountQuery }; diff --git a/WebCore/platform/image-decoders/gif/GIFImageReader.h b/WebCore/platform/image-decoders/gif/GIFImageReader.h index faa08d2..855e6be 100644 --- a/WebCore/platform/image-decoders/gif/GIFImageReader.h +++ b/WebCore/platform/image-decoders/gif/GIFImageReader.h @@ -47,6 +47,8 @@ #define MAX_COLORS 256 #define MAX_HOLD_SIZE 256 +const int cLoopCountNotSeen = -2; + /* gif2.h The interface for the GIF87/89a decoder. */ @@ -187,7 +189,7 @@ struct GIFImageReader { screen_bgcolor = version = 0; screen_width = screen_height = 0; global_colormap_size = images_decoded = images_count = 0; - loop_count = -1; + loop_count = cLoopCountNotSeen; count = 0; } diff --git a/WebCore/platform/image-decoders/ico/ICOImageDecoder.h b/WebCore/platform/image-decoders/ico/ICOImageDecoder.h index 6571b99..a4f3dbd 100644 --- a/WebCore/platform/image-decoders/ico/ICOImageDecoder.h +++ b/WebCore/platform/image-decoders/ico/ICOImageDecoder.h @@ -36,6 +36,8 @@ class ICOImageReader; class ICOImageDecoder : public ImageDecoder { public: + virtual String filenameExtension() const { return "ico"; } + // Whether or not the size information has been decoded yet. virtual bool isSizeAvailable() const; diff --git a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h index 57fd9da..b4d7b2a 100644 --- a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h +++ b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h @@ -39,6 +39,8 @@ public: JPEGImageDecoder(); ~JPEGImageDecoder(); + virtual String filenameExtension() const { return "jpg"; } + // Take the data and store it. virtual void setData(SharedBuffer* data, bool allDataReceived); diff --git a/WebCore/platform/image-decoders/png/PNGImageDecoder.h b/WebCore/platform/image-decoders/png/PNGImageDecoder.h index 926f1f2..8c73785 100644 --- a/WebCore/platform/image-decoders/png/PNGImageDecoder.h +++ b/WebCore/platform/image-decoders/png/PNGImageDecoder.h @@ -39,6 +39,8 @@ public: PNGImageDecoder(); ~PNGImageDecoder(); + virtual String filenameExtension() const { return "png"; } + // Take the data and store it. virtual void setData(SharedBuffer* data, bool allDataReceived); diff --git a/WebCore/platform/image-decoders/skia/BMPImageDecoder.cpp b/WebCore/platform/image-decoders/skia/BMPImageDecoder.cpp new file mode 100644 index 0000000..08d5df5 --- /dev/null +++ b/WebCore/platform/image-decoders/skia/BMPImageDecoder.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2008, 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 "BMPImageDecoder.h" + +namespace WebCore { + +// Number of bits in .BMP used to store the file header (doesn't match +// "sizeof(BMPImageDecoder::BitmapFileHeader)" since we omit some fields and +// don't pack). +static const size_t sizeOfFileHeader = 14; + +void BMPImageDecoder::decodeImage(SharedBuffer* data) +{ + // Read and process file header. + if ((m_decodedOffset < sizeOfFileHeader) && !processFileHeader(data)) + return; + + // Decode BMP. + decodeBMP(data); +} + +bool BMPImageDecoder::processFileHeader(SharedBuffer* data) +{ + // Read file header. + ASSERT(!m_decodedOffset); + if (data->size() < sizeOfFileHeader) + return false; + const uint16_t fileType = + (data->data()[0] << 8) | static_cast<uint8_t>(data->data()[1]); + m_imgDataOffset = readUint32(data, 10); + m_decodedOffset = m_headerOffset = sizeOfFileHeader; + + // See if this is a bitmap filetype we understand. + enum { + BMAP = 'BM', + // The following additional OS/2 2.x header values (see + // http://www.fileformat.info/format/os2bmp/egff.htm ) aren't widely + // decoded, and are unlikely to be in much use. + /* + ICON = 'IC', + POINTER = 'PT', + COLORICON = 'CI', + COLORPOINTER = 'CP', + BITMAPARRAY = 'BA', + */ + }; + if (fileType != BMAP) + m_failed = true; + + return !m_failed; +} + +} // namespace WebCore diff --git a/WebCore/platform/image-decoders/skia/BMPImageDecoder.h b/WebCore/platform/image-decoders/skia/BMPImageDecoder.h new file mode 100644 index 0000000..065981f --- /dev/null +++ b/WebCore/platform/image-decoders/skia/BMPImageDecoder.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2008, 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 BMPImageDecoder_h +#define BMPImageDecoder_h + +#include "BMPImageReader.h" + +namespace WebCore { + + // This class decodes the BMP image format. + class BMPImageDecoder : public BMPImageReader { + public: + virtual String filenameExtension() const { return "bmp"; } + + // BMPImageReader + virtual void decodeImage(SharedBuffer*); + + private: + // Processes the file header at the beginning of the data. Returns true if + // the file header could be decoded. + bool processFileHeader(SharedBuffer*); + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/image-decoders/skia/BMPImageReader.cpp b/WebCore/platform/image-decoders/skia/BMPImageReader.cpp new file mode 100644 index 0000000..829b107 --- /dev/null +++ b/WebCore/platform/image-decoders/skia/BMPImageReader.cpp @@ -0,0 +1,835 @@ +/* + * Copyright (c) 2008, 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 "BMPImageReader.h" + +namespace WebCore { + +BMPImageReader::BMPImageReader() + : m_decodedOffset(0) + , m_headerOffset(0) + , m_imgDataOffset(0) + , m_andMaskState(None) + , m_isOS21x(false) + , m_isOS22x(false) + , m_isTopDown(false) + , m_needToProcessBitmasks(false) + , m_needToProcessColorTable(false) + , m_tableSizeInBytes(0) + , m_seenNonZeroAlphaPixel(false) + , m_seenZeroAlphaPixel(false) +{ + m_frameBufferCache.resize(1); + + // Clue-in decodeBMP() that we need to detect the correct info header size. + memset(&m_infoHeader, 0, sizeof(m_infoHeader)); +} + +void BMPImageReader::setData(SharedBuffer* data, bool allDataReceived) +{ + ImageDecoder::setData(data, allDataReceived); + + // NOTE: This function intentionally uses frameBufferAtIndex() instead of + // checking m_frameBufferCache.first() directly, so that it will do the + // right thing for ICOImageDecoder, which needs to override this accessor + // to support ICOs which contain PNGs. + + // Return quickly when we can't do any more work. + if (m_failed || data->isEmpty() + || (frameBufferAtIndex(0)->status() == RGBA32Buffer::FrameComplete)) + return; + + // Decode as much as we can. This assumes |data| starts at the beginning + // of the image data, rather than containing just the latest chunk. + decodeImage(data); + if (m_failed) { + // Handle failure before getting the framebuffer below. + m_colorTable.clear(); + return; + } + + // If we got all the data but couldn't finish decoding, fail. + const bool finished = + (frameBufferAtIndex(0)->status() == RGBA32Buffer::FrameComplete); + if (allDataReceived && !finished) + m_failed = true; + + // Release the color table when we no longer need it. + if (finished || m_failed) + m_colorTable.clear(); +} + +RGBA32Buffer* BMPImageReader::frameBufferAtIndex(size_t index) +{ + return index ? 0 : &m_frameBufferCache.first(); +} + +void BMPImageReader::decodeBMP(SharedBuffer* data) +{ + // Calculate size of info header. + if (!m_infoHeader.biSize && !getInfoHeaderSize(data)) + return; + + // Read and process info header. + if ((m_decodedOffset < (m_headerOffset + m_infoHeader.biSize)) + && !processInfoHeader(data)) + return; + + // Read and process the bitmasks, if needed. + if (m_needToProcessBitmasks && !processBitmasks(data)) + return; + + // Read and process the color table, if needed. + if (m_needToProcessColorTable && !processColorTable(data)) + return; + + // Initialize frame buffer state, if needed. + if (m_frameBufferCache.first().status() == RGBA32Buffer::FrameEmpty) { + m_frameBufferCache.first().setRect(IntRect(IntPoint(), size())); + m_frameBufferCache.first().setStatus(RGBA32Buffer::FramePartial); + if (!m_frameBufferCache.first().setSize(m_infoHeader.biWidth, + m_infoHeader.biHeight)) { + // Unable to allocate. + m_failed = true; + return; + } + + // setSize() calls eraseARGB(), which resets the alpha flag, so we force + // it back to false here. We'll set it true below in all cases where + // these 0s could actually show through. + m_frameBufferCache.first().setHasAlpha(false); + if (!m_isTopDown) + m_coord.setY(size().height() - 1); + } + + // Decode the data. + if ((m_andMaskState != Decoding) && !pastEndOfImage(0)) { + if ((m_infoHeader.biCompression == RLE4) + || (m_infoHeader.biCompression == RLE8) + || (m_infoHeader.biCompression == RLE24)) { + if (!processRLEData(data)) + return; + } else if (!processNonRLEData(data, false, 0)) + return; + } + + // If the image has an AND mask and there was no alpha data, process the + // mask. + if ((m_andMaskState == NotYetDecoded) + && !m_frameBufferCache.first().hasAlpha()) { + // Reset decoding coordinates to start of image. + m_coord.setX(0); + m_coord.setY(m_isTopDown ? 0 : (size().height() - 1)); + + // The AND mask is stored as 1-bit data. + m_infoHeader.biBitCount = 1; + + m_andMaskState = Decoding; + } + if ((m_andMaskState == Decoding) && !processNonRLEData(data, false, 0)) + return; + + // Done! + m_frameBufferCache.first().setStatus(RGBA32Buffer::FrameComplete); +} + +bool BMPImageReader::getInfoHeaderSize(SharedBuffer* data) +{ + // Get size of info header. + ASSERT(m_decodedOffset == m_headerOffset); + if ((m_decodedOffset > data->size()) + || ((data->size() - m_decodedOffset) < 4)) + return false; + m_infoHeader.biSize = readUint32(data, 0); + // Don't increment m_decodedOffset here, it just makes the code in + // processInfoHeader() more confusing. + + // Don't allow the header to overflow (which would be harmless here, but + // problematic or at least confusing in other places), or to overrun the + // image data. + if (((m_headerOffset + m_infoHeader.biSize) < m_headerOffset) + || (m_imgDataOffset + && (m_imgDataOffset < (m_headerOffset + m_infoHeader.biSize)))) { + m_failed = true; + return false; + } + + // See if this is a header size we understand: + // OS/2 1.x: 12 + if (m_infoHeader.biSize == 12) + m_isOS21x = true; + // Windows V3: 40 + else if ((m_infoHeader.biSize == 40) || isWindowsV4Plus()) + ; + // OS/2 2.x: any multiple of 4 between 16 and 64, inclusive, or 42 or 46 + else if ((m_infoHeader.biSize >= 16) && (m_infoHeader.biSize <= 64) + && (((m_infoHeader.biSize & 3) == 0) || (m_infoHeader.biSize == 42) + || (m_infoHeader.biSize == 46))) + m_isOS22x = true; + else + m_failed = true; + + return !m_failed; +} + +bool BMPImageReader::processInfoHeader(SharedBuffer* data) +{ + // Read info header. + ASSERT(m_decodedOffset == m_headerOffset); + if ((m_decodedOffset > data->size()) + || ((data->size() - m_decodedOffset) < m_infoHeader.biSize) + || !readInfoHeader(data)) + return false; + m_decodedOffset += m_infoHeader.biSize; + + // Sanity-check header values. + if (!isInfoHeaderValid()) { + m_failed = true; + return false; + } + + // Make our size available to the caller. + if (!setSize(m_infoHeader.biWidth, m_infoHeader.biHeight)) { + m_failed = true; + return false; + } + + // For paletted images, bitmaps can set biClrUsed to 0 to mean "all + // colors", so set it to the maximum number of colors for this bit depth. + // Also do this for bitmaps that put too large a value here. + if (m_infoHeader.biBitCount < 16) { + const uint32_t maxColors = + static_cast<uint32_t>(1) << m_infoHeader.biBitCount; + if ((m_infoHeader.biClrUsed == 0) + || (m_infoHeader.biClrUsed > maxColors)) + m_infoHeader.biClrUsed = maxColors; + } + + // For any bitmaps that set their BitCount to the wrong value, reset the + // counts now that we've calculated the number of necessary colors, since + // other code relies on this value being correct. + if (m_infoHeader.biCompression == RLE8) + m_infoHeader.biBitCount = 8; + else if (m_infoHeader.biCompression == RLE4) + m_infoHeader.biBitCount = 4; + + // Tell caller what still needs to be processed. + if (m_infoHeader.biBitCount >= 16) + m_needToProcessBitmasks = true; + else if (m_infoHeader.biBitCount > 0) + m_needToProcessColorTable = true; + + return true; +} + +bool BMPImageReader::readInfoHeader(SharedBuffer* data) +{ + // Pre-initialize some fields that not all headers set. + m_infoHeader.biCompression = RGB; + m_infoHeader.biClrUsed = 0; + + if (m_isOS21x) { + m_infoHeader.biWidth = readUint16(data, 4); + m_infoHeader.biHeight = readUint16(data, 6); + ASSERT(m_andMaskState == None); // ICO is a Windows format, not OS/2! + m_infoHeader.biBitCount = readUint16(data, 10); + return true; + } + + m_infoHeader.biWidth = readUint32(data, 4); + m_infoHeader.biHeight = readUint32(data, 8); + if (m_andMaskState != None) + m_infoHeader.biHeight /= 2; + m_infoHeader.biBitCount = readUint16(data, 14); + + // Read compression type, if present. + if (m_infoHeader.biSize >= 20) { + uint32_t biCompression = readUint32(data, 16); + + // Detect OS/2 2.x-specific compression types. + if ((biCompression == 3) && (m_infoHeader.biBitCount == 1)) { + m_infoHeader.biCompression = HUFFMAN1D; + m_isOS22x = true; + } else if ((biCompression == 4) && (m_infoHeader.biBitCount == 24)) { + m_infoHeader.biCompression = RLE24; + m_isOS22x = true; + } else if (biCompression > 5) { + // Some type we don't understand. + m_failed = true; + return false; + } else + m_infoHeader.biCompression = static_cast<CompressionType>(biCompression); + } + + // Read colors used, if present. + if (m_infoHeader.biSize >= 36) + m_infoHeader.biClrUsed = readUint32(data, 32); + + // Windows V4+ can safely read the four bitmasks from 40-56 bytes in, so do + // that here. If the bit depth is less than 16, these values will be + // ignored by the image data decoders. If the bit depth is at least 16 but + // the compression format isn't BITFIELDS, these values will be ignored and + // overwritten* in processBitmasks(). + // NOTE: We allow alpha here. Microsoft doesn't really document this well, + // but some BMPs appear to use it. + // + // For non-Windows V4+, m_bitMasks[] et. al will be initialized later + // during processBitmasks(). + // + // *Except the alpha channel. Bizarrely, some RGB bitmaps expect decoders + // to pay attention to the alpha mask here, so there's a special case in + // processBitmasks() that doesn't always overwrite that value. + if (isWindowsV4Plus()) { + m_bitMasks[0] = readUint32(data, 40); + m_bitMasks[1] = readUint32(data, 44); + m_bitMasks[2] = readUint32(data, 48); + m_bitMasks[3] = readUint32(data, 52); + } + + // Detect top-down BMPs. + if (m_infoHeader.biHeight < 0) { + m_isTopDown = true; + m_infoHeader.biHeight = -m_infoHeader.biHeight; + } + + return true; +} + +bool BMPImageReader::isInfoHeaderValid() const +{ + // Non-positive widths/heights are invalid. (We've already flipped the + // sign of the height for top-down bitmaps.) + if ((m_infoHeader.biWidth <= 0) || (m_infoHeader.biHeight == 0)) + return false; + + // Only Windows V3+ has top-down bitmaps. + if (m_isTopDown && (m_isOS21x || m_isOS22x)) + return false; + + // Only bit depths of 1, 4, 8, or 24 are universally supported. + if ((m_infoHeader.biBitCount != 1) && (m_infoHeader.biBitCount != 4) + && (m_infoHeader.biBitCount != 8) + && (m_infoHeader.biBitCount != 24)) { + // Windows V3+ additionally supports bit depths of 0 (for embedded + // JPEG/PNG images), 16, and 32. + if (m_isOS21x || m_isOS22x) + return false; + if ((m_infoHeader.biBitCount != 0) + && (m_infoHeader.biBitCount != 16) + && (m_infoHeader.biBitCount != 32)) + return false; + } + + // Each compression type is only valid with certain bit depths (except RGB, + // which can be used with any bit depth). Also, some formats do not + // some compression types. + switch (m_infoHeader.biCompression) { + case RGB: + if (m_infoHeader.biBitCount == 0) + return false; + break; + + case RLE8: + // Supposedly there are undocumented formats like "BitCount = 1, + // Compression = RLE4" (which means "4 bit, but with a 2-color table"), + // so also allow the paletted RLE compression types to have too low a + // bit count; we'll correct this later. + if (m_infoHeader.biBitCount == 0 || m_infoHeader.biBitCount > 8) + return false; + break; + + case RLE4: + // See comments in RLE8. + if (m_infoHeader.biBitCount == 0 || m_infoHeader.biBitCount > 4) + return false; + break; + + case BITFIELDS: + // Only valid for Windows V3+. + if (m_isOS21x || m_isOS22x) + return false; + if ((m_infoHeader.biBitCount != 16) && (m_infoHeader.biBitCount != 32)) + return false; + break; + + case JPEG: + case PNG: + // Only valid for Windows V3+. + if (m_isOS21x || m_isOS22x) + return false; + if (m_infoHeader.biBitCount != 0) + return false; + break; + + case HUFFMAN1D: + // Only valid for OS/2 2.x. + if (!m_isOS22x) + return false; + if (m_infoHeader.biBitCount != 1) + return false; + break; + + case RLE24: + // Only valid for OS/2 2.x. + if (!m_isOS22x) + return false; + if (m_infoHeader.biBitCount != 24) + return false; + break; + + default: + // Some type we don't understand. This should have been caught in + // readInfoHeader(). + ASSERT_NOT_REACHED(); + return false; + } + + // Top-down bitmaps cannot be compressed; they must be RGB or BITFIELDS. + if (m_isTopDown && (m_infoHeader.biCompression != RGB) + && (m_infoHeader.biCompression != BITFIELDS)) + return false; + + // Reject the following valid bitmap types that we don't currently bother + // decoding. Few other people decode these either, they're unlikely to be + // in much use. + // TODO(pkasting): Consider supporting these someday. + // * Bitmaps larger than 2^16 pixels in either dimension (Windows + // probably doesn't draw these well anyway, and the decoded data would + // take a lot of memory). + if ((m_infoHeader.biWidth >= (1 << 16)) + || (m_infoHeader.biHeight >= (1 << 16))) + return false; + // * Windows V3+ JPEG-in-BMP and PNG-in-BMP bitmaps (supposedly not found + // in the wild, only used to send data to printers?). + if ((m_infoHeader.biCompression == JPEG) + || (m_infoHeader.biCompression == PNG)) + return false; + // * OS/2 2.x Huffman-encoded monochrome bitmaps (see + // http://www.fileformat.info/mirror/egff/ch09_05.htm , re: "G31D" + // algorithm). + if (m_infoHeader.biCompression == HUFFMAN1D) + return false; + + return true; +} + +bool BMPImageReader::processBitmasks(SharedBuffer* data) +{ + // Create m_bitMasks[] values. + if (m_infoHeader.biCompression != BITFIELDS) { + // The format doesn't actually use bitmasks. To simplify the decode + // logic later, create bitmasks for the RGB data. For Windows V4+, + // this overwrites the masks we read from the header, which are + // supposed to be ignored in non-BITFIELDS cases. + // 16 bits: MSB <- xRRRRRGG GGGBBBBB -> LSB + // 24/32 bits: MSB <- [AAAAAAAA] RRRRRRRR GGGGGGGG BBBBBBBB -> LSB + const int numBits = (m_infoHeader.biBitCount == 16) ? 5 : 8; + for (int i = 0; i <= 2; ++i) { + m_bitMasks[i] = + ((static_cast<uint32_t>(1) << (numBits * (3 - i))) - 1) ^ + ((static_cast<uint32_t>(1) << (numBits * (2 - i))) - 1); + } + + // For Windows V4+ 32-bit RGB, don't overwrite the alpha mask from the + // header (see note in readInfoHeader()). + if (m_infoHeader.biBitCount < 32) + m_bitMasks[3] = 0; + else if (!isWindowsV4Plus()) + m_bitMasks[3] = static_cast<uint32_t>(0xff000000); + } else if (!isWindowsV4Plus()) { + // For Windows V4+ BITFIELDS mode bitmaps, this was already done when + // we read the info header. + + // Fail if we don't have enough file space for the bitmasks. + static const int SIZEOF_BITMASKS = 12; + if (((m_headerOffset + m_infoHeader.biSize + SIZEOF_BITMASKS) < (m_headerOffset + m_infoHeader.biSize)) + || (m_imgDataOffset && (m_imgDataOffset < (m_headerOffset + m_infoHeader.biSize + SIZEOF_BITMASKS)))) { + m_failed = true; + return false; + } + + // Read bitmasks. + if ((data->size() - m_decodedOffset) < SIZEOF_BITMASKS) + return false; + m_bitMasks[0] = readUint32(data, 0); + m_bitMasks[1] = readUint32(data, 4); + m_bitMasks[2] = readUint32(data, 8); + // No alpha in anything other than Windows V4+. + m_bitMasks[3] = 0; + + m_decodedOffset += SIZEOF_BITMASKS; + } + + // We've now decoded all the non-image data we care about. Skip anything + // else before the actual raster data. + if (m_imgDataOffset) + m_decodedOffset = m_imgDataOffset; + m_needToProcessBitmasks = false; + + // Check masks and set shift values. + for (int i = 0; i < 4; ++i) { + // Trim the mask to the allowed bit depth. Some Windows V4+ BMPs + // specify a bogus alpha channel in bits that don't exist in the pixel + // data (for example, bits 25-31 in a 24-bit RGB format). + if (m_infoHeader.biBitCount < 32) + m_bitMasks[i] &= ((static_cast<uint32_t>(1) << m_infoHeader.biBitCount) - 1); + + // For empty masks (common on the alpha channel, especially after the + // trimming above), quickly clear the shifts and continue, to avoid an + // infinite loop in the counting code below. + uint32_t tempMask = m_bitMasks[i]; + if (!tempMask) { + m_bitShiftsRight[i] = m_bitShiftsLeft[i] = 0; + continue; + } + + // Make sure bitmask does not overlap any other bitmasks. + for (int j = 0; j < i; ++j) { + if (tempMask & m_bitMasks[j]) { + m_failed = true; + return false; + } + } + + // Count offset into pixel data. + for (m_bitShiftsRight[i] = 0; !(tempMask & 1); tempMask >>= 1) + ++m_bitShiftsRight[i]; + + // Count size of mask. + for (m_bitShiftsLeft[i] = 8; tempMask & 1; tempMask >>= 1) + --m_bitShiftsLeft[i]; + + // Make sure bitmask is contiguous. + if (tempMask) { + m_failed = true; + return false; + } + + // Since RGBABuffer tops out at 8 bits per channel, adjust the shift + // amounts to use the most significant 8 bits of the channel. + if (m_bitShiftsLeft[i] < 0) { + m_bitShiftsRight[i] -= m_bitShiftsLeft[i]; + m_bitShiftsLeft[i] = 0; + } + } + + return true; +} + +bool BMPImageReader::processColorTable(SharedBuffer* data) +{ + m_tableSizeInBytes = m_infoHeader.biClrUsed * (m_isOS21x ? 3 : 4); + + // Fail if we don't have enough file space for the color table. + if (((m_headerOffset + m_infoHeader.biSize + m_tableSizeInBytes) < (m_headerOffset + m_infoHeader.biSize)) + || (m_imgDataOffset && (m_imgDataOffset < (m_headerOffset + m_infoHeader.biSize + m_tableSizeInBytes)))) { + m_failed = true; + return false; + } + + // Read color table. + if ((m_decodedOffset > data->size()) + || ((data->size() - m_decodedOffset) < m_tableSizeInBytes)) + return false; + m_colorTable.resize(m_infoHeader.biClrUsed); + for (size_t i = 0; i < m_infoHeader.biClrUsed; ++i) { + m_colorTable[i].rgbBlue = data->data()[m_decodedOffset++]; + m_colorTable[i].rgbGreen = data->data()[m_decodedOffset++]; + m_colorTable[i].rgbRed = data->data()[m_decodedOffset++]; + // Skip padding byte (not present on OS/2 1.x). + if (!m_isOS21x) + ++m_decodedOffset; + } + + // We've now decoded all the non-image data we care about. Skip anything + // else before the actual raster data. + if (m_imgDataOffset) + m_decodedOffset = m_imgDataOffset; + m_needToProcessColorTable = false; + + return true; +} + +bool BMPImageReader::processRLEData(SharedBuffer* data) +{ + if (m_decodedOffset > data->size()) + return false; + + // RLE decoding is poorly specified. Two main problems: + // (1) Are EOL markers necessary? What happens when we have too many + // pixels for one row? + // http://www.fileformat.info/format/bmp/egff.htm says extra pixels + // should wrap to the next line. Real BMPs I've encountered seem to + // instead expect extra pixels to be ignored until the EOL marker is + // seen, although this has only happened in a few cases and I suspect + // those BMPs may be invalid. So we only change lines on EOL (or Delta + // with dy > 0), and fail in most cases when pixels extend past the end + // of the line. + // (2) When Delta, EOL, or EOF are seen, what happens to the "skipped" + // pixels? + // http://www.daubnet.com/formats/BMP.html says these should be filled + // with color 0. However, the "do nothing" and "don't care" comments + // of other references suggest leaving these alone, i.e. letting them + // be transparent to the background behind the image. This seems to + // match how MSPAINT treats BMPs, so we do that. Note that when we + // actually skip pixels for a case like this, we need to note on the + // framebuffer that we have alpha. + + // Impossible to decode row-at-a-time, so just do things as a stream of + // bytes. + while (true) { + // Every entry takes at least two bytes; bail if there isn't enough + // data. + if ((data->size() - m_decodedOffset) < 2) + return false; + + // For every entry except EOF, we'd better not have reached the end of + // the image. + const uint8_t count = data->data()[m_decodedOffset]; + const uint8_t code = data->data()[m_decodedOffset + 1]; + if (((count != 0) || (code != 1)) && pastEndOfImage(0)) { + m_failed = true; + return false; + } + + // Decode. + if (count == 0) { + switch (code) { + case 0: // Magic token: EOL + // Skip any remaining pixels in this row. + if (m_coord.x() < size().width()) + m_frameBufferCache.first().setHasAlpha(true); + moveBufferToNextRow(); + + m_decodedOffset += 2; + break; + + case 1: // Magic token: EOF + // Skip any remaining pixels in the image. + if ((m_coord.x() < size().width()) + || (m_isTopDown ? (m_coord.y() < (size().height() - 1)) : (m_coord.y() > 0))) + m_frameBufferCache.first().setHasAlpha(true); + return true; + + case 2: { // Magic token: Delta + // The next two bytes specify dx and dy. Bail if there isn't + // enough data. + if ((data->size() - m_decodedOffset) < 4) + return false; + + // Fail if this takes us past the end of the desired row or + // past the end of the image. + const uint8_t dx = data->data()[m_decodedOffset + 2]; + const uint8_t dy = data->data()[m_decodedOffset + 3]; + if ((dx != 0) || (dy != 0)) + m_frameBufferCache.first().setHasAlpha(true); + if (((m_coord.x() + dx) > size().width()) || + pastEndOfImage(dy)) { + m_failed = true; + return false; + } + + // Skip intervening pixels. + m_coord.move(dx, m_isTopDown ? dy : -dy); + + m_decodedOffset += 4; + break; + } + + default: // Absolute mode + // |code| pixels specified as in BI_RGB, zero-padded at the end + // to a multiple of 16 bits. + // Because processNonRLEData() expects m_decodedOffset to + // point to the beginning of the pixel data, bump it past + // the escape bytes and then reset if decoding failed. + m_decodedOffset += 2; + if (!processNonRLEData(data, true, code)) { + m_decodedOffset -= 2; + return false; + } + break; + } + } else { // Encoded mode + // The following color data is repeated for |count| total pixels. + // Strangely, some BMPs seem to specify excessively large counts + // here; ignore pixels past the end of the row. + const int endX = std::min(m_coord.x() + count, size().width()); + + if (m_infoHeader.biCompression == RLE24) { + // Bail if there isn't enough data. + if ((data->size() - m_decodedOffset) < 4) + return false; + + // One BGR triple that we copy |count| times. + fillRGBA(endX, data->data()[m_decodedOffset + 3], + data->data()[m_decodedOffset + 2], code, 0xff); + m_decodedOffset += 4; + } else { + // RLE8 has one color index that gets repeated; RLE4 has two + // color indexes in the upper and lower 4 bits of the byte, + // which are alternated. + size_t colorIndexes[2] = {code, code}; + if (m_infoHeader.biCompression == RLE4) { + colorIndexes[0] = (colorIndexes[0] >> 4) & 0xf; + colorIndexes[1] &= 0xf; + } + if ((colorIndexes[0] >= m_infoHeader.biClrUsed) + || (colorIndexes[1] >= m_infoHeader.biClrUsed)) { + m_failed = true; + return false; + } + for (int which = 0; m_coord.x() < endX; ) { + setI(colorIndexes[which]); + which = !which; + } + + m_decodedOffset += 2; + } + } + } +} + +bool BMPImageReader::processNonRLEData(SharedBuffer* data, bool inRLE, int numPixels) +{ + if (m_decodedOffset > data->size()) + return false; + + if (!inRLE) + numPixels = size().width(); + + // Fail if we're being asked to decode more pixels than remain in the row. + const int endX = m_coord.x() + numPixels; + if (endX > size().width()) { + m_failed = true; + return false; + } + + // Determine how many bytes of data the requested number of pixels + // requires. + const size_t pixelsPerByte = 8 / m_infoHeader.biBitCount; + const size_t bytesPerPixel = m_infoHeader.biBitCount / 8; + const size_t unpaddedNumBytes = (m_infoHeader.biBitCount < 16) + ? ((numPixels + pixelsPerByte - 1) / pixelsPerByte) + : (numPixels * bytesPerPixel); + // RLE runs are zero-padded at the end to a multiple of 16 bits. Non-RLE + // data is in rows and is zero-padded to a multiple of 32 bits. + const size_t alignBits = inRLE ? 1 : 3; + const size_t paddedNumBytes = (unpaddedNumBytes + alignBits) & ~alignBits; + + // Decode as many rows as we can. (For RLE, where we only want to decode + // one row, we've already checked that this condition is true.) + while (!pastEndOfImage(0)) { + // Bail if we don't have enough data for the desired number of pixels. + if ((data->size() - m_decodedOffset) < paddedNumBytes) + return false; + + if (m_infoHeader.biBitCount < 16) { + // Paletted data. Pixels are stored little-endian within bytes. + // Decode pixels one byte at a time, left to right (so, starting at + // the most significant bits in the byte). + const uint8_t mask = (1 << m_infoHeader.biBitCount) - 1; + for (size_t byte = 0; byte < unpaddedNumBytes; ++byte) { + uint8_t pixelData = data->data()[m_decodedOffset + byte]; + for (size_t pixel = 0; (pixel < pixelsPerByte) && (m_coord.x() < endX); ++pixel) { + const size_t colorIndex = + (pixelData >> (8 - m_infoHeader.biBitCount)) & mask; + if (m_andMaskState == Decoding) { + // There's no way to accurately represent an AND + XOR + // operation as an RGBA image, so where the AND values + // are 1, we simply set the framebuffer pixels to fully + // transparent, on the assumption that most ICOs on the + // web will not be doing a lot of inverting. + if (colorIndex) { + setRGBA(0, 0, 0, 0); + m_frameBufferCache.first().setHasAlpha(true); + } else + m_coord.move(1, 0); + } else { + if (colorIndex >= m_infoHeader.biClrUsed) { + m_failed = true; + return false; + } + setI(colorIndex); + } + pixelData <<= m_infoHeader.biBitCount; + } + } + } else { + // RGB data. Decode pixels one at a time, left to right. + while (m_coord.x() < endX) { + const uint32_t pixel = readCurrentPixel(data, bytesPerPixel); + + // Some BMPs specify an alpha channel but don't actually use it + // (it contains all 0s). To avoid displaying these images as + // fully-transparent, decode as if images are fully opaque + // until we actually see a non-zero alpha value; at that point, + // reset any previously-decoded pixels to fully transparent and + // continue decoding based on the real alpha channel values. + // As an optimization, avoid setting "hasAlpha" to true for + // images where all alpha values are 255; opaque images are + // faster to draw. + int alpha = getAlpha(pixel); + if (!m_seenNonZeroAlphaPixel && (alpha == 0)) { + m_seenZeroAlphaPixel = true; + alpha = 255; + } else { + m_seenNonZeroAlphaPixel = true; + if (m_seenZeroAlphaPixel) { + // The eraseARGB() call here also sets "hasAlpha" true. + m_frameBufferCache.first().bitmap().eraseARGB(0, 0, 0, + 0); + m_seenZeroAlphaPixel = false; + } else if (alpha != 255) + m_frameBufferCache.first().setHasAlpha(true); + } + + setRGBA(getComponent(pixel, 0), getComponent(pixel, 1), + getComponent(pixel, 2), alpha); + } + } + + // Success, keep going. + m_decodedOffset += paddedNumBytes; + if (inRLE) + return true; + moveBufferToNextRow(); + } + + // Finished decoding whole image. + return true; +} + +void BMPImageReader::moveBufferToNextRow() +{ + m_coord.move(-m_coord.x(), m_isTopDown ? 1 : -1); +} + +} // namespace WebCore diff --git a/WebCore/platform/image-decoders/skia/BMPImageReader.h b/WebCore/platform/image-decoders/skia/BMPImageReader.h new file mode 100644 index 0000000..0edf7b0 --- /dev/null +++ b/WebCore/platform/image-decoders/skia/BMPImageReader.h @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2008, 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 BMPImageReader_h +#define BMPImageReader_h + +#include <stdint.h> +#include "ImageDecoder.h" + +namespace WebCore { + + // This class decodes a BMP image. It is used as a base for the BMP and ICO + // decoders, which wrap it in the appropriate code to read file headers, etc. + class BMPImageReader : public ImageDecoder { + public: + BMPImageReader(); + + // Does the actual decoding. |data| starts at the beginning of the file, + // but may be incomplete. + virtual void decodeImage(SharedBuffer* data) = 0; + + // ImageDecoder + virtual void setData(SharedBuffer* data, bool allDataReceived); + virtual RGBA32Buffer* frameBufferAtIndex(size_t index); + + protected: + enum AndMaskState { + None, + NotYetDecoded, + Decoding, + }; + + // Decodes a single BMP, starting with an info header. + void decodeBMP(SharedBuffer* data); + + // Read a value from |data[m_decodedOffset + additionalOffset]|, converting + // from little to native endianness. + inline uint16_t readUint16(SharedBuffer* data, int additionalOffset) const + { + uint16_t result; + memcpy(&result, &data->data()[m_decodedOffset + additionalOffset], 2); + #if PLATFORM(BIG_ENDIAN) + result = ((result & 0xff) << 8) | ((result & 0xff00) >> 8); + #endif + return result; + } + + inline uint32_t readUint32(SharedBuffer* data, int additionalOffset) const + { + uint32_t result; + memcpy(&result, &data->data()[m_decodedOffset + additionalOffset], 4); + #if PLATFORM(BIG_ENDIAN) + result = ((result & 0xff) << 24) | ((result & 0xff00) << 8) | + ((result & 0xff0000) >> 8) | ((result & 0xff000000) >> 24); + #endif + return result; + } + + // An index into |m_data| representing how much we've already decoded. + size_t m_decodedOffset; + + // The file offset at which the BMP info header starts. + size_t m_headerOffset; + + // The file offset at which the actual image bits start. When decoding ICO + // files, this is set to 0, since it's not stored anywhere in a header; the + // reader functions expect the image data to start immediately after the + // header and (if necessary) color table. + size_t m_imgDataOffset; + + // ICOs store a 1bpp "mask" immediately after the main bitmap image data + // (and, confusingly, add its height to the biHeight value in the info + // header, thus doubling it). This variable tracks whether we have such a + // mask and if we've started decoding it yet. + AndMaskState m_andMaskState; + + private: + // The various BMP compression types. We don't currently decode all these. + enum CompressionType { + // Universal types + RGB = 0, + RLE8 = 1, + RLE4 = 2, + // Windows V3+ only + BITFIELDS = 3, + JPEG = 4, + PNG = 5, + // OS/2 2.x-only + HUFFMAN1D, // Stored in file as 3 + RLE24, // Stored in file as 4 + }; + + // These are based on the Windows BITMAPINFOHEADER and RGBTRIPLE structs, + // but with unnecessary entries removed. + struct BitmapInfoHeader { + uint32_t biSize; + int32_t biWidth; + int32_t biHeight; + uint16_t biBitCount; + CompressionType biCompression; + uint32_t biClrUsed; + }; + struct RGBTriple { + uint8_t rgbBlue; + uint8_t rgbGreen; + uint8_t rgbRed; + }; + + // Determines the size of the BMP info header. Returns true if the size is + // valid. + bool getInfoHeaderSize(SharedBuffer* data); + + // Processes the BMP info header. Returns true if the info header could be + // decoded. + bool processInfoHeader(SharedBuffer* data); + + // Helper function for processInfoHeader() which does the actual reading of + // header values from the byte stream. Returns false on error. + bool readInfoHeader(SharedBuffer* data); + + // Returns true if this is a Windows V4+ BMP. + inline bool isWindowsV4Plus() const + { + // Windows V4 info header is 108 bytes. V5 is 124 bytes. + return (m_infoHeader.biSize == 108) || (m_infoHeader.biSize == 124); + } + + // Returns false if consistency errors are found in the info header. + bool isInfoHeaderValid() const; + + // For BI_BITFIELDS images, initializes the m_bitMasks[] and m_bitOffsets[] + // arrays. processInfoHeader() will initialize these for other compression + // types where needed. + bool processBitmasks(SharedBuffer* data); + + // For paletted images, allocates and initializes the m_colorTable[] array. + bool processColorTable(SharedBuffer* data); + + // Processes an RLE-encoded image. Returns true if the entire image was + // decoded. + bool processRLEData(SharedBuffer* data); + + // Processes a set of non-RLE-compressed pixels. Two cases: + // * inRLE = true: the data is inside an RLE-encoded bitmap. Tries to + // process |numPixels| pixels on the current row; returns true on + // success. + // * inRLE = false: the data is inside a non-RLE-encoded bitmap. + // |numPixels| is ignored. Expects |m_coord| to point at the beginning + // of the next row to be decoded. Tries to process as many complete + // rows as possible. Returns true if the whole image was decoded. + bool processNonRLEData(SharedBuffer* data, bool inRLE, int numPixels); + + // Returns true if the current y-coordinate plus |numRows| would be past + // the end of the image. Here "plus" means "toward the end of the image", + // so downwards for m_isTopDown images and upwards otherwise. + inline bool pastEndOfImage(int numRows) + { + return m_isTopDown + ? ((m_coord.y() + numRows) >= size().height()) + : ((m_coord.y() - numRows) < 0); + } + + // Returns the pixel data for the current X coordinate in a uint32_t. + // Assumes m_decodedOffset has been set to the beginning of the current + // row. + // NOTE: Only as many bytes of the return value as are needed to hold the + // pixel data will actually be set. + inline uint32_t readCurrentPixel(SharedBuffer* data, int bytesPerPixel) const + { + const int additionalOffset = m_coord.x() * bytesPerPixel; + switch (bytesPerPixel) { + case 2: + return readUint16(data, additionalOffset); + + case 3: { + // It doesn't matter that we never set the most significant byte of + // the return value here in little-endian mode, the caller won't + // read it. + uint32_t pixel; + memcpy(&pixel, + &data->data()[m_decodedOffset + additionalOffset], 3); + #if PLATFORM(BIG_ENDIAN) + pixel = ((pixel & 0xff00) << 8) | ((pixel & 0xff0000) >> 8) | + ((pixel & 0xff000000) >> 24); + #endif + return pixel; + } + + case 4: + return readUint32(data, additionalOffset); + + default: + ASSERT_NOT_REACHED(); + return 0; + } + } + + // Returns the value of the desired component (0, 1, 2, 3 == R, G, B, A) in + // the given pixel data. + inline unsigned getComponent(uint32_t pixel, int component) const + { + return ((pixel & m_bitMasks[component]) >> m_bitShiftsRight[component]) + << m_bitShiftsLeft[component]; + } + + inline unsigned getAlpha(uint32_t pixel) const + { + // For images without alpha, return alpha of 0xff. + if (m_bitMasks[3] == 0) + return 0xff; + + return getComponent(pixel, 3); + } + + // Sets the current pixel to the color given by |colorIndex|. This also + // increments the relevant local variables to move the current pixel right + // by one. + inline void setI(size_t colorIndex) + { + setRGBA(m_colorTable[colorIndex].rgbRed, m_colorTable[colorIndex].rgbGreen, + m_colorTable[colorIndex].rgbBlue, 0xff); + } + + // Like setI(), but with the individual component values specified. + inline void setRGBA(unsigned red, unsigned green, unsigned blue, unsigned alpha) + { + RGBA32Buffer::setRGBA( + m_frameBufferCache.first().bitmap().getAddr32(m_coord.x(), m_coord.y()), + red, green, blue, alpha); + m_coord.move(1, 0); + } + + // Fills pixels from the current X-coordinate up to, but not including, + // |endCoord| with the color given by the individual components. This also + // increments the relevant local variables to move the current pixel right + // to |endCoord|. + inline void fillRGBA(int endCoord, unsigned red, unsigned green, unsigned blue, unsigned alpha) + { + while (m_coord.x() < endCoord) + setRGBA(red, green, blue, alpha); + } + + // Resets the relevant local variables to start drawing at the left edge of + // the "next" row, where "next" is above or below the current row depending + // on the value of |m_isTopDown|. + void moveBufferToNextRow(); + + // The BMP info header. + BitmapInfoHeader m_infoHeader; + + // True if this is an OS/2 1.x (aka Windows 2.x) BMP. The struct layouts + // for this type of BMP are slightly different from the later, more common + // formats. + bool m_isOS21x; + + // True if this is an OS/2 2.x BMP. The meanings of compression types 3 + // and 4 for this type of BMP differ from Windows V3+ BMPs. + // + // This will be falsely negative in some cases, but only ones where the way + // we misinterpret the data is irrelevant. + bool m_isOS22x; + + // True if the BMP is not vertically flipped, that is, the first line of + // raster data in the file is the top line of the image. + bool m_isTopDown; + + // These flags get set to false as we finish each processing stage. + bool m_needToProcessBitmasks; + bool m_needToProcessColorTable; + + // Masks/offsets for the color values for non-palette formats. These are + // bitwise, with array entries 0, 1, 2, 3 corresponding to R, G, B, A. + // + // The right/left shift values are meant to be applied after the masks. + // We need to right shift to compensate for the bitfields' offsets into the + // 32 bits of pixel data, and left shift to scale the color values up for + // fields with less than 8 bits of precision. Sadly, we can't just combine + // these into one shift value because the net shift amount could go either + // direction. (If only "<< -x" were equivalent to ">> x"...) + uint32_t m_bitMasks[4]; + int m_bitShiftsRight[4]; + int m_bitShiftsLeft[4]; + + // The color palette, for paletted formats. + size_t m_tableSizeInBytes; + Vector<RGBTriple> m_colorTable; + + // The coordinate to which we've decoded the image. + IntPoint m_coord; + + // Variables that track whether we've seen pixels with alpha values != 0 + // and == 0, respectively. See comments in processNonRLEData() on how + // these are used. + bool m_seenNonZeroAlphaPixel; + bool m_seenZeroAlphaPixel; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/image-decoders/skia/GIFImageDecoder.cpp b/WebCore/platform/image-decoders/skia/GIFImageDecoder.cpp new file mode 100644 index 0000000..38bfa97 --- /dev/null +++ b/WebCore/platform/image-decoders/skia/GIFImageDecoder.cpp @@ -0,0 +1,470 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008, 2009 Google, 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 "GIFImageDecoder.h" +#include "GIFImageReader.h" + +namespace WebCore { + +class GIFImageDecoderPrivate { +public: + GIFImageDecoderPrivate(GIFImageDecoder* decoder = 0) + : m_reader(decoder) + , m_readOffset(0) + { + } + + ~GIFImageDecoderPrivate() + { + m_reader.close(); + } + + bool decode(SharedBuffer* data, + GIFImageDecoder::GIFQuery query = GIFImageDecoder::GIFFullQuery, + unsigned int haltFrame = -1) + { + return m_reader.read((const unsigned char*)data->data() + m_readOffset, data->size() - m_readOffset, + query, + haltFrame); + } + + unsigned frameCount() const { return m_reader.images_count; } + int repetitionCount() const { return m_reader.loop_count; } + + void setReadOffset(unsigned o) { m_readOffset = o; } + + bool isTransparent() const { return m_reader.frame_reader->is_transparent; } + + void getColorMap(unsigned char*& map, unsigned& size) const + { + if (m_reader.frame_reader->is_local_colormap_defined) { + map = m_reader.frame_reader->local_colormap; + size = (unsigned)m_reader.frame_reader->local_colormap_size; + } else { + map = m_reader.global_colormap; + size = m_reader.global_colormap_size; + } + } + + unsigned frameXOffset() const { return m_reader.frame_reader->x_offset; } + unsigned frameYOffset() const { return m_reader.frame_reader->y_offset; } + unsigned frameWidth() const { return m_reader.frame_reader->width; } + unsigned frameHeight() const { return m_reader.frame_reader->height; } + + int transparentPixel() const { return m_reader.frame_reader->tpixel; } + + unsigned duration() const { return m_reader.frame_reader->delay_time; } + +private: + GIFImageReader m_reader; + unsigned m_readOffset; +}; + +GIFImageDecoder::GIFImageDecoder() + : m_frameCountValid(true) + , m_repetitionCount(cAnimationLoopOnce) + , m_reader(0) +{ +} + +GIFImageDecoder::~GIFImageDecoder() +{ + delete m_reader; +} + +// Take the data and store it. +void GIFImageDecoder::setData(SharedBuffer* data, bool allDataReceived) +{ + if (m_failed) + return; + + // Cache our new data. + ImageDecoder::setData(data, allDataReceived); + + // Our frame count is now unknown. + m_frameCountValid = false; + + // Create the GIF reader. + if (!m_reader && !m_failed) + m_reader = new GIFImageDecoderPrivate(this); +} + +// Whether or not the size information has been decoded yet. +bool GIFImageDecoder::isSizeAvailable() const +{ + // If we have pending data to decode, send it to the GIF reader now. + if (!ImageDecoder::isSizeAvailable() && m_reader) { + if (m_failed) + return false; + + // The decoder will go ahead and aggressively consume everything up until the first + // size is encountered. + decode(GIFSizeQuery, 0); + } + + return !m_failed && ImageDecoder::isSizeAvailable(); +} + +// The total number of frames for the image. Will scan the image data for the answer +// (without necessarily decoding all of the individual frames). +int GIFImageDecoder::frameCount() +{ + // If the decoder had an earlier error, we will just return what we had decoded + // so far. + if (!m_frameCountValid) { + // FIXME: Scanning all the data has O(n^2) behavior if the data were to come in really + // slowly. Might be interesting to try to clone our existing read session to preserve + // state, but for now we just crawl all the data. Note that this is no worse than what + // ImageIO does on Mac right now (it also crawls all the data again). + GIFImageDecoderPrivate reader; + // This function may fail, but we want to keep any partial data it may + // have decoded, so don't mark it is invalid. If there is an overflow + // or some serious error, m_failed will have gotten set for us. + reader.decode(m_data.get(), GIFFrameCountQuery); + m_frameCountValid = true; + m_frameBufferCache.resize(reader.frameCount()); + } + + return m_frameBufferCache.size(); +} + +// The number of repetitions to perform for an animation loop. +int GIFImageDecoder::repetitionCount() const +{ + // This value can arrive at any point in the image data stream. Most GIFs + // in the wild declare it near the beginning of the file, so it usually is + // set by the time we've decoded the size, but (depending on the GIF and the + // packets sent back by the webserver) not always. Our caller is + // responsible for waiting until image decoding has finished to ask this if + // it needs an authoritative answer. In the meantime, we should default to + // "loop once". + if (m_reader) { + // Added wrinkle: ImageSource::clear() may destroy the reader, making + // the result from the reader _less_ authoritative on future calls. To + // detect this, the reader returns cLoopCountNotSeen (-2) instead of + // cAnimationLoopOnce (-1) when its current incarnation hasn't actually + // seen a loop count yet; in this case we return our previously-cached + // value. + const int repetitionCount = m_reader->repetitionCount(); + if (repetitionCount != cLoopCountNotSeen) + m_repetitionCount = repetitionCount; + } + return m_repetitionCount; +} + +RGBA32Buffer* GIFImageDecoder::frameBufferAtIndex(size_t index) +{ + if (index >= static_cast<size_t>(frameCount())) + return 0; + + RGBA32Buffer& frame = m_frameBufferCache[index]; + if (frame.status() != RGBA32Buffer::FrameComplete && m_reader) + decode(GIFFullQuery, index+1); // Decode this frame. + return &frame; +} + +void GIFImageDecoder::clearFrameBufferCache(size_t clearBeforeFrame) +{ + // In some cases, like if the decoder was destroyed while animating, we + // can be asked to clear more frames than we currently have. + if (m_frameBufferCache.isEmpty()) + return; // Nothing to do. + // The "-1" here is tricky. It does not mean that |clearBeforeFrame| is the + // last frame we wish to preserve, but rather that we never want to clear + // the very last frame in the cache: it's empty (so clearing it is + // pointless), it's partial (so we don't want to clear it anyway), or the + // cache could be enlarged with a future setData() call and it could be + // needed to construct the next frame (see comments below). Callers can + // always use ImageSource::clear(true, ...) to completely free the memory in + // this case. + clearBeforeFrame = std::min(clearBeforeFrame, m_frameBufferCache.size() - 1); + const Vector<RGBA32Buffer>::iterator end(m_frameBufferCache.begin() + clearBeforeFrame); + for (Vector<RGBA32Buffer>::iterator i(m_frameBufferCache.begin()); i != end; ++i) { + if (i->status() == RGBA32Buffer::FrameEmpty) + continue; // Nothing to do. + + // The layout of frames is: + // [empty frames][complete frames][partial frame][empty frames] + // ...where each of these groups may be empty. We should not clear a + // partial frame since that's what's being decoded right now, and we + // also should not clear the last complete frame, since it may be needed + // when constructing the next frame. Note that "i + 1" is safe since + // i < end < m_frameBufferCache.end(). + if ((i->status() == RGBA32Buffer::FramePartial) || ((i + 1)->status() != RGBA32Buffer::FrameComplete)) + break; + + i->clear(); + } +} + +// Feed data to the GIF reader. +void GIFImageDecoder::decode(GIFQuery query, unsigned haltAtFrame) const +{ + if (m_failed) + return; + + m_failed = !m_reader->decode(m_data.get(), query, haltAtFrame); + + if (m_failed) { + delete m_reader; + m_reader = 0; + } +} + +// Callbacks from the GIF reader. +bool GIFImageDecoder::sizeNowAvailable(unsigned width, unsigned height) +{ + return setSize(width, height); +} + +void GIFImageDecoder::decodingHalted(unsigned bytesLeft) +{ + m_reader->setReadOffset(m_data->size() - bytesLeft); +} + +bool GIFImageDecoder::initFrameBuffer(unsigned frameIndex) +{ + // Initialize the frame rect in our buffer. + IntRect frameRect(m_reader->frameXOffset(), m_reader->frameYOffset(), + m_reader->frameWidth(), m_reader->frameHeight()); + + // Make sure the frameRect doesn't extend past the bottom-right of the buffer. + if (frameRect.right() > size().width()) + frameRect.setWidth(size().width() - m_reader->frameXOffset()); + if (frameRect.bottom() > size().height()) + frameRect.setHeight(size().height() - m_reader->frameYOffset()); + + RGBA32Buffer* const buffer = &m_frameBufferCache[frameIndex]; + buffer->setRect(frameRect); + + if (frameIndex == 0) { + // This is the first frame, so we're not relying on any previous data. + if (!prepEmptyFrameBuffer(buffer)) { + buffer->setStatus(RGBA32Buffer::FrameComplete); + m_failed = true; + return false; + } + } else { + // The starting state for this frame depends on the previous frame's + // disposal method. + // + // Frames that use the DisposeOverwritePrevious method are effectively + // no-ops in terms of changing the starting state of a frame compared to + // the starting state of the previous frame, so skip over them. (If the + // first frame specifies this method, it will get treated like + // DisposeOverwriteBgcolor below and reset to a completely empty image.) + const RGBA32Buffer* prevBuffer = &m_frameBufferCache[--frameIndex]; + ASSERT(prevBuffer->status() == RGBA32Buffer::FrameComplete); + RGBA32Buffer::FrameDisposalMethod prevMethod = + prevBuffer->disposalMethod(); + while ((frameIndex > 0) + && (prevMethod == RGBA32Buffer::DisposeOverwritePrevious)) { + prevBuffer = &m_frameBufferCache[--frameIndex]; + prevMethod = prevBuffer->disposalMethod(); + } + + if ((prevMethod == RGBA32Buffer::DisposeNotSpecified) || + (prevMethod == RGBA32Buffer::DisposeKeep)) { + // Preserve the last frame as the starting state for this frame. + buffer->copyBitmapData(*prevBuffer); + // This next line isn't currently necessary since the alpha state is + // currently carried along in the Skia bitmap data, but it's safe, + // future-proof, and parallel to the Cairo code. + buffer->setHasAlpha(prevBuffer->hasAlpha()); + } else { + // We want to clear the previous frame to transparent, without + // affecting pixels in the image outside of the frame. + const IntRect& prevRect = prevBuffer->rect(); + if ((frameIndex == 0) + || prevRect.contains(IntRect(IntPoint(0, 0), size()))) { + // Clearing the first frame, or a frame the size of the whole + // image, results in a completely empty image. + prepEmptyFrameBuffer(buffer); + } else { + // Copy the whole previous buffer, then clear just its frame. + buffer->copyBitmapData(*prevBuffer); + // Unnecessary (but safe); see comments on the similar call above. + buffer->setHasAlpha(prevBuffer->hasAlpha()); + SkBitmap& bitmap = buffer->bitmap(); + for (int y = prevRect.y(); y < prevRect.bottom(); ++y) { + for (int x = prevRect.x(); x < prevRect.right(); ++x) + buffer->setRGBA(bitmap.getAddr32(x, y), 0, 0, 0, 0); + } + if ((prevRect.width() > 0) && (prevRect.height() > 0)) + buffer->setHasAlpha(true); + } + } + } + + // Update our status to be partially complete. + buffer->setStatus(RGBA32Buffer::FramePartial); + + // Reset the alpha pixel tracker for this frame. + m_currentBufferSawAlpha = false; + return true; +} + +bool GIFImageDecoder::prepEmptyFrameBuffer(RGBA32Buffer* buffer) const +{ + if (!buffer->setSize(size().width(), size().height())) + return false; + // This next line isn't currently necessary since Skia's eraseARGB() sets + // this for us, but we do it for similar reasons to the setHasAlpha() calls + // in initFrameBuffer() above. + buffer->setHasAlpha(true); + return true; +} + +void GIFImageDecoder::haveDecodedRow(unsigned frameIndex, + unsigned char* rowBuffer, // Pointer to single scanline temporary buffer + unsigned char* rowEnd, + unsigned rowNumber, // The row index + unsigned repeatCount, // How many times to repeat the row + bool writeTransparentPixels) +{ + // Initialize the frame if necessary. + RGBA32Buffer& buffer = m_frameBufferCache[frameIndex]; + if ((buffer.status() == RGBA32Buffer::FrameEmpty) && !initFrameBuffer(frameIndex)) + return; + + // Do nothing for bogus data. + if (rowBuffer == 0 || static_cast<int>(m_reader->frameYOffset() + rowNumber) >= size().height()) + return; + + unsigned colorMapSize; + unsigned char* colorMap; + m_reader->getColorMap(colorMap, colorMapSize); + if (!colorMap) + return; + + // The buffers that we draw are the entire image's width and height, so a final output frame is + // width * height RGBA32 values in size. + // + // A single GIF frame, however, can be smaller than the entire image, i.e., it can represent some sub-rectangle + // within the overall image. The rows we are decoding are within this + // sub-rectangle. This means that if the GIF frame's sub-rectangle is (x,y,w,h) then row 0 is really row + // y, and each row goes from x to x+w. + unsigned dstPos = (m_reader->frameYOffset() + rowNumber) * size().width() + m_reader->frameXOffset(); + unsigned* dst = buffer.bitmap().getAddr32(0, 0) + dstPos; + unsigned* dstEnd = dst + size().width() - m_reader->frameXOffset(); + unsigned* currDst = dst; + unsigned char* currentRowByte = rowBuffer; + + while (currentRowByte != rowEnd && currDst < dstEnd) { + if ((!m_reader->isTransparent() || *currentRowByte != m_reader->transparentPixel()) && *currentRowByte < colorMapSize) { + unsigned colorIndex = *currentRowByte * 3; + unsigned red = colorMap[colorIndex]; + unsigned green = colorMap[colorIndex + 1]; + unsigned blue = colorMap[colorIndex + 2]; + RGBA32Buffer::setRGBA(currDst, red, green, blue, 255); + } else { + m_currentBufferSawAlpha = true; + // We may or may not need to write transparent pixels to the buffer. + // If we're compositing against a previous image, it's wrong, and if + // we're writing atop a cleared, fully transparent buffer, it's + // unnecessary; but if we're decoding an interlaced gif and + // displaying it "Haeberli"-style, we must write these for passes + // beyond the first, or the initial passes will "show through" the + // later ones. + if (writeTransparentPixels) + RGBA32Buffer::setRGBA(currDst, 0, 0, 0, 0); + } + currDst++; + currentRowByte++; + } + + if (repeatCount > 1) { + // Copy the row |repeatCount|-1 times. + unsigned num = currDst - dst; + unsigned data_size = num * sizeof(unsigned); + unsigned width = size().width(); + unsigned* end = buffer.bitmap().getAddr32(0, 0) + width * size().height(); + currDst = dst + width; + for (unsigned i = 1; i < repeatCount; i++) { + if (currDst + num > end) // Protect against a buffer overrun from a bogus repeatCount. + break; + memcpy(currDst, dst, data_size); + currDst += width; + } + } +} + +void GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration, RGBA32Buffer::FrameDisposalMethod disposalMethod) +{ + // Initialize the frame if necessary. Some GIFs insert do-nothing frames, + // in which case we never reach haveDecodedRow() before getting here. + RGBA32Buffer& buffer = m_frameBufferCache[frameIndex]; + if ((buffer.status() == RGBA32Buffer::FrameEmpty) && !initFrameBuffer(frameIndex)) + return; + + buffer.setStatus(RGBA32Buffer::FrameComplete); + buffer.setDuration(frameDuration); + buffer.setDisposalMethod(disposalMethod); + + if (!m_currentBufferSawAlpha) { + // The whole frame was non-transparent, so it's possible that the entire + // resulting buffer was non-transparent, and we can setHasAlpha(false). + if (buffer.rect().contains(IntRect(IntPoint(0, 0), size()))) + buffer.setHasAlpha(false); + else if (frameIndex > 0) { + // Tricky case. This frame does not have alpha only if everywhere + // outside its rect doesn't have alpha. To know whether this is + // true, we check the start state of the frame -- if it doesn't have + // alpha, we're safe. + // + // First skip over prior DisposeOverwritePrevious frames (since they + // don't affect the start state of this frame) the same way we do in + // initFrameBuffer(). + const RGBA32Buffer* prevBuffer = &m_frameBufferCache[--frameIndex]; + while ((frameIndex > 0) + && (prevBuffer->disposalMethod() == RGBA32Buffer::DisposeOverwritePrevious)) + prevBuffer = &m_frameBufferCache[--frameIndex]; + + // Now, if we're at a DisposeNotSpecified or DisposeKeep frame, then + // we can say we have no alpha if that frame had no alpha. But + // since in initFrameBuffer() we already copied that frame's alpha + // state into the current frame's, we need do nothing at all here. + // + // The only remaining case is a DisposeOverwriteBgcolor frame. If + // it had no alpha, and its rect is contained in the current frame's + // rect, we know the current frame has no alpha. + if ((prevBuffer->disposalMethod() == RGBA32Buffer::DisposeOverwriteBgcolor) + && !prevBuffer->hasAlpha() && buffer.rect().contains(prevBuffer->rect())) + buffer.setHasAlpha(false); + } + } +} + +void GIFImageDecoder::gifComplete() +{ + if (m_reader) + m_repetitionCount = m_reader->repetitionCount(); + delete m_reader; + m_reader = 0; +} + +} // namespace WebCore diff --git a/WebCore/platform/image-decoders/skia/GIFImageDecoder.h b/WebCore/platform/image-decoders/skia/GIFImageDecoder.h new file mode 100644 index 0000000..d234a76 --- /dev/null +++ b/WebCore/platform/image-decoders/skia/GIFImageDecoder.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008, 2009 Google, 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. + */ + +#ifndef GIFImageDecoder_h +#define GIFImageDecoder_h + +#include "ImageDecoder.h" + +namespace WebCore { + + class GIFImageDecoderPrivate; + + // This class decodes the GIF image format. + class GIFImageDecoder : public ImageDecoder { + public: + GIFImageDecoder(); + ~GIFImageDecoder(); + + virtual String filenameExtension() const { return "gif"; } + + // Take the data and store it. + virtual void setData(SharedBuffer* data, bool allDataReceived); + + // Whether or not the size information has been decoded yet. + virtual bool isSizeAvailable() const; + + // The total number of frames for the image. Will scan the image data for the answer + // (without necessarily decoding all of the individual frames). + virtual int frameCount(); + + // The number of repetitions to perform for an animation loop. + virtual int repetitionCount() const; + + virtual RGBA32Buffer* frameBufferAtIndex(size_t index); + + virtual void clearFrameBufferCache(size_t clearBeforeFrame); + + virtual unsigned frameDurationAtIndex(size_t index) { return 0; } + + enum GIFQuery { GIFFullQuery, GIFSizeQuery, GIFFrameCountQuery }; + + void decode(GIFQuery, unsigned haltAtFrame) const; + + // Callbacks from the GIF reader. + bool sizeNowAvailable(unsigned width, unsigned height); + void decodingHalted(unsigned bytesLeft); + void haveDecodedRow(unsigned frameIndex, unsigned char* rowBuffer, unsigned char* rowEnd, unsigned rowNumber, + unsigned repeatCount, bool writeTransparentPixels); + void frameComplete(unsigned frameIndex, unsigned frameDuration, RGBA32Buffer::FrameDisposalMethod disposalMethod); + void gifComplete(); + + private: + // Called to initialize the frame buffer with the given index, based on the + // previous frame's disposal method. Returns true on success. On failure, + // this will mark the image as failed. + bool initFrameBuffer(unsigned frameIndex); + + // A helper for initFrameBuffer(), this sets the size of the buffer, and + // fills it with transparent pixels. + bool prepEmptyFrameBuffer(RGBA32Buffer*) const; + + bool m_frameCountValid; + bool m_currentBufferSawAlpha; + mutable int m_repetitionCount; + mutable GIFImageDecoderPrivate* m_reader; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/image-decoders/skia/GIFImageReader.cpp b/WebCore/platform/image-decoders/skia/GIFImageReader.cpp new file mode 100644 index 0000000..48df514 --- /dev/null +++ b/WebCore/platform/image-decoders/skia/GIFImageReader.cpp @@ -0,0 +1,951 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Chris Saari <saari@netscape.com> + * Apple Computer + * Google, Inc. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* +The Graphics Interchange Format(c) is the copyright property of CompuServe +Incorporated. Only CompuServe Incorporated is authorized to define, redefine, +enhance, alter, modify or change in any way the definition of the format. + +CompuServe Incorporated hereby grants a limited, non-exclusive, royalty-free +license for the use of the Graphics Interchange Format(sm) in computer +software; computer software utilizing GIF(sm) must acknowledge ownership of the +Graphics Interchange Format and its Service Mark by CompuServe Incorporated, in +User and Technical Documentation. Computer software utilizing GIF, which is +distributed or may be distributed without User or Technical Documentation must +display to the screen or printer a message acknowledging ownership of the +Graphics Interchange Format and the Service Mark by CompuServe Incorporated; in +this case, the acknowledgement may be displayed in an opening screen or leading +banner, or a closing screen or trailing banner. A message such as the following +may be used: + + "The Graphics Interchange Format(c) is the Copyright property of + CompuServe Incorporated. GIF(sm) is a Service Mark property of + CompuServe Incorporated." + +For further information, please contact : + + CompuServe Incorporated + Graphics Technology Department + 5000 Arlington Center Boulevard + Columbus, Ohio 43220 + U. S. A. + +CompuServe Incorporated maintains a mailing list with all those individuals and +organizations who wish to receive copies of this document when it is corrected +or revised. This service is offered free of charge; please provide us with your +mailing address. +*/ + +#include "config.h" +#include "GIFImageReader.h" + +#include <string.h> +#include "GIFImageDecoder.h" + +using WebCore::GIFImageDecoder; + +// Define the Mozilla macro setup so that we can leave the macros alone. +#define PR_BEGIN_MACRO do { +#define PR_END_MACRO } while (0) + +/* + * GETN(n, s) requests at least 'n' bytes available from 'q', at start of state 's' + * + * Note, the hold will never need to be bigger than 256 bytes to gather up in the hold, + * as each GIF block (except colormaps) can never be bigger than 256 bytes. + * Colormaps are directly copied in the resp. global_colormap or dynamically allocated local_colormap. + * So a fixed buffer in GIFImageReader is good enough. + * This buffer is only needed to copy left-over data from one GifWrite call to the next + */ +#define GETN(n,s) \ + PR_BEGIN_MACRO \ + bytes_to_consume = (n); \ + state = (s); \ + PR_END_MACRO + +/* Get a 16-bit value stored in little-endian format */ +#define GETINT16(p) ((p)[1]<<8|(p)[0]) + +//****************************************************************************** +// Send the data to the display front-end. +void GIFImageReader::output_row() +{ + GIFFrameReader* gs = frame_reader; + + int drow_start, drow_end; + + drow_start = drow_end = gs->irow; + + /* + * Haeberli-inspired hack for interlaced GIFs: Replicate lines while + * displaying to diminish the "venetian-blind" effect as the image is + * loaded. Adjust pixel vertical positions to avoid the appearance of the + * image crawling up the screen as successive passes are drawn. + */ + if (gs->progressive_display && gs->interlaced && gs->ipass < 4) { + unsigned row_dup = 0, row_shift = 0; + + switch (gs->ipass) { + case 1: + row_dup = 7; + row_shift = 3; + break; + case 2: + row_dup = 3; + row_shift = 1; + break; + case 3: + row_dup = 1; + row_shift = 0; + break; + default: + break; + } + + drow_start -= row_shift; + drow_end = drow_start + row_dup; + + /* Extend if bottom edge isn't covered because of the shift upward. */ + if (((gs->height - 1) - drow_end) <= row_shift) + drow_end = gs->height - 1; + + /* Clamp first and last rows to upper and lower edge of image. */ + if (drow_start < 0) + drow_start = 0; + if ((unsigned)drow_end >= gs->height) + drow_end = gs->height - 1; + } + + /* Protect against too much image data */ + if ((unsigned)drow_start >= gs->height) + return; + + // CALLBACK: Let the client know we have decoded a row. + if (clientptr && frame_reader) + clientptr->haveDecodedRow(images_count - 1, frame_reader->rowbuf, frame_reader->rowend, + drow_start, drow_end - drow_start + 1, + gs->progressive_display && gs->interlaced && gs->ipass > 1); + + gs->rowp = gs->rowbuf; + + if (!gs->interlaced) + gs->irow++; + else { + do { + switch (gs->ipass) + { + case 1: + gs->irow += 8; + if (gs->irow >= gs->height) { + gs->ipass++; + gs->irow = 4; + } + break; + + case 2: + gs->irow += 8; + if (gs->irow >= gs->height) { + gs->ipass++; + gs->irow = 2; + } + break; + + case 3: + gs->irow += 4; + if (gs->irow >= gs->height) { + gs->ipass++; + gs->irow = 1; + } + break; + + case 4: + gs->irow += 2; + if (gs->irow >= gs->height){ + gs->ipass++; + gs->irow = 0; + } + break; + + default: + break; + } + } while (gs->irow > (gs->height - 1)); + } +} + +//****************************************************************************** +/* Perform Lempel-Ziv-Welch decoding */ +int GIFImageReader::do_lzw(const unsigned char *q) +{ + GIFFrameReader* gs = frame_reader; + if (!gs) + return 0; + + int code; + int incode; + const unsigned char *ch; + + /* Copy all the decoder state variables into locals so the compiler + * won't worry about them being aliased. The locals will be homed + * back into the GIF decoder structure when we exit. + */ + int avail = gs->avail; + int bits = gs->bits; + int cnt = count; + int codesize = gs->codesize; + int codemask = gs->codemask; + int oldcode = gs->oldcode; + int clear_code = gs->clear_code; + unsigned char firstchar = gs->firstchar; + int datum = gs->datum; + + if (!gs->prefix) { + gs->prefix = new unsigned short[MAX_BITS]; + memset(gs->prefix, 0, MAX_BITS * sizeof(short)); + } + + unsigned short *prefix = gs->prefix; + unsigned char *stackp = gs->stackp; + unsigned char *suffix = gs->suffix; + unsigned char *stack = gs->stack; + unsigned char *rowp = gs->rowp; + unsigned char *rowend = gs->rowend; + unsigned rows_remaining = gs->rows_remaining; + + if (rowp == rowend) + return 0; + +#define OUTPUT_ROW \ + PR_BEGIN_MACRO \ + output_row(); \ + rows_remaining--; \ + rowp = frame_reader->rowp; \ + if (!rows_remaining) \ + goto END; \ + PR_END_MACRO + + for (ch = q; cnt-- > 0; ch++) + { + /* Feed the next byte into the decoder's 32-bit input buffer. */ + datum += ((int) *ch) << bits; + bits += 8; + + /* Check for underflow of decoder's 32-bit input buffer. */ + while (bits >= codesize) + { + /* Get the leading variable-length symbol from the data stream */ + code = datum & codemask; + datum >>= codesize; + bits -= codesize; + + /* Reset the dictionary to its original state, if requested */ + if (code == clear_code) { + codesize = gs->datasize + 1; + codemask = (1 << codesize) - 1; + avail = clear_code + 2; + oldcode = -1; + continue; + } + + /* Check for explicit end-of-stream code */ + if (code == (clear_code + 1)) { + /* end-of-stream should only appear after all image data */ + if (rows_remaining != 0) + return -1; + return 0; + } + + if (oldcode == -1) { + *rowp++ = suffix[code]; + if (rowp == rowend) + OUTPUT_ROW; + + firstchar = oldcode = code; + continue; + } + + incode = code; + if (code >= avail) { + *stackp++ = firstchar; + code = oldcode; + + if (stackp == stack + MAX_BITS) + return -1; + } + + while (code >= clear_code) + { + if (code >= MAX_BITS || code == prefix[code]) + return -1; + + // Even though suffix[] only holds characters through suffix[avail - 1], + // allowing code >= avail here lets us be more tolerant of malformed + // data. As long as code < MAX_BITS, the only risk is a garbled image, + // which is no worse than refusing to display it. + *stackp++ = suffix[code]; + code = prefix[code]; + + if (stackp == stack + MAX_BITS) + return -1; + } + + *stackp++ = firstchar = suffix[code]; + + /* Define a new codeword in the dictionary. */ + if (avail < 4096) { + prefix[avail] = oldcode; + suffix[avail] = firstchar; + avail++; + + /* If we've used up all the codewords of a given length + * increase the length of codewords by one bit, but don't + * exceed the specified maximum codeword size of 12 bits. + */ + if (((avail & codemask) == 0) && (avail < 4096)) { + codesize++; + codemask += avail; + } + } + oldcode = incode; + + /* Copy the decoded data out to the scanline buffer. */ + do { + *rowp++ = *--stackp; + if (rowp == rowend) { + OUTPUT_ROW; + } + } while (stackp > stack); + } + } + + END: + + /* Home the local copies of the GIF decoder state variables */ + gs->avail = avail; + gs->bits = bits; + gs->codesize = codesize; + gs->codemask = codemask; + count = cnt; + gs->oldcode = oldcode; + gs->firstchar = firstchar; + gs->datum = datum; + gs->stackp = stackp; + gs->rowp = rowp; + gs->rows_remaining = rows_remaining; + + return 0; +} + + +/******************************************************************************/ +/* + * process data arriving from the stream for the gif decoder + */ + +bool GIFImageReader::read(const unsigned char *buf, unsigned len, + GIFImageDecoder::GIFQuery query, unsigned haltAtFrame) +{ + if (!len) { + // No new data has come in since the last call, just ignore this call. + return true; + } + + const unsigned char *q = buf; + + // Add what we have so far to the block + // If previous call to me left something in the hold first complete current block + // Or if we are filling the colormaps, first complete the colormap + unsigned char* p = 0; + if (state == gif_global_colormap) + p = global_colormap; + else if (state == gif_image_colormap) + p = frame_reader ? frame_reader->local_colormap : 0; + else if (bytes_in_hold) + p = hold; + else + p = 0; + + if (p || (state == gif_global_colormap) || (state == gif_image_colormap)) { + // Add what we have sofar to the block + unsigned l = len < bytes_to_consume ? len : bytes_to_consume; + if (p) + memcpy(p + bytes_in_hold, buf, l); + + if (l < bytes_to_consume) { + // Not enough in 'buf' to complete current block, get more + bytes_in_hold += l; + bytes_to_consume -= l; + if (clientptr) + clientptr->decodingHalted(0); + return true; + } + // Reset hold buffer count + bytes_in_hold = 0; + // Point 'q' to complete block in hold (or in colormap) + q = p; + } + + // Invariant: + // 'q' is start of current to be processed block (hold, colormap or buf) + // 'bytes_to_consume' is number of bytes to consume from 'buf' + // 'buf' points to the bytes to be consumed from the input buffer + // 'len' is number of bytes left in input buffer from position 'buf'. + // At entrance of the for loop will 'buf' will be moved 'bytes_to_consume' + // to point to next buffer, 'len' is adjusted accordingly. + // So that next round in for loop, q gets pointed to the next buffer. + + for (;len >= bytes_to_consume; q=buf) { + // Eat the current block from the buffer, q keeps pointed at current block + buf += bytes_to_consume; + len -= bytes_to_consume; + + switch (state) + { + case gif_lzw: + if (do_lzw(q) < 0) { + state = gif_error; + break; + } + GETN(1, gif_sub_block); + break; + + case gif_lzw_start: + { + /* Initialize LZW parser/decoder */ + int datasize = *q; + // Since we use a codesize of 1 more than the datasize, we need to ensure + // that our datasize is strictly less than the MAX_LZW_BITS value (12). + // This sets the largest possible codemask correctly at 4095. + if (datasize >= MAX_LZW_BITS) { + state = gif_error; + break; + } + int clear_code = 1 << datasize; + if (clear_code >= MAX_BITS) { + state = gif_error; + break; + } + + if (frame_reader) { + frame_reader->datasize = datasize; + frame_reader->clear_code = clear_code; + frame_reader->avail = frame_reader->clear_code + 2; + frame_reader->oldcode = -1; + frame_reader->codesize = frame_reader->datasize + 1; + frame_reader->codemask = (1 << frame_reader->codesize) - 1; + + frame_reader->datum = frame_reader->bits = 0; + + /* init the tables */ + if (!frame_reader->suffix) + frame_reader->suffix = new unsigned char[MAX_BITS]; + // Clearing the whole suffix table lets us be more tolerant of bad data. + memset(frame_reader->suffix, 0, MAX_BITS); + for (int i = 0; i < frame_reader->clear_code; i++) + frame_reader->suffix[i] = i; + + if (!frame_reader->stack) + frame_reader->stack = new unsigned char[MAX_BITS]; + frame_reader->stackp = frame_reader->stack; + } + + GETN(1, gif_sub_block); + } + break; + + /* All GIF files begin with "GIF87a" or "GIF89a" */ + case gif_type: + { + if (!strncmp((char*)q, "GIF89a", 6)) { + version = 89; + } else if (!strncmp((char*)q, "GIF87a", 6)) { + version = 87; + } else { + state = gif_error; + break; + } + GETN(7, gif_global_header); + } + break; + + case gif_global_header: + { + /* This is the height and width of the "screen" or + * frame into which images are rendered. The + * individual images can be smaller than the + * screen size and located with an origin anywhere + * within the screen. + */ + + screen_width = GETINT16(q); + screen_height = GETINT16(q + 2); + + // CALLBACK: Inform the decoderplugin of our size. + if (clientptr) { + if (!clientptr->sizeNowAvailable(screen_width, screen_height)) + return false; + } + + screen_bgcolor = q[5]; + global_colormap_size = 2<<(q[4]&0x07); + + if ((q[4] & 0x80) && global_colormap_size > 0) { /* global map */ + // Get the global colormap + const unsigned size = 3*global_colormap_size; + + // Malloc the color map, but only if we're not just counting frames. + if (query != GIFImageDecoder::GIFFrameCountQuery) + global_colormap = new unsigned char[size]; + + if (len < size) { + // Use 'hold' pattern to get the global colormap + GETN(size, gif_global_colormap); + break; + } + + // Copy everything and go directly to gif_image_start. + if (global_colormap) + memcpy(global_colormap, buf, size); + buf += size; + len -= size; + } + + GETN(1, gif_image_start); + + // q[6] = Pixel Aspect Ratio + // Not used + // float aspect = (float)((q[6] + 15) / 64.0); + } + break; + + case gif_global_colormap: + // Everything is already copied into global_colormap + GETN(1, gif_image_start); + break; + + case gif_image_start: + { + if (*q == ';') { /* terminator */ + state = gif_done; + break; + } + + if (*q == '!') { /* extension */ + GETN(2, gif_extension); + break; + } + + /* If we get anything other than ',' (image separator), '!' + * (extension), or ';' (trailer), there is extraneous data + * between blocks. The GIF87a spec tells us to keep reading + * until we find an image separator, but GIF89a says such + * a file is corrupt. We follow GIF89a and bail out. */ + if (*q != ',') { + if (images_decoded > 0) { + /* The file is corrupt, but one or more images have + * been decoded correctly. In this case, we proceed + * as if the file were correctly terminated and set + * the state to gif_done, so the GIF will display. + */ + state = gif_done; + } else { + /* No images decoded, there is nothing to display. */ + state = gif_error; + } + break; + } else + GETN(9, gif_image_header); + } + break; + + case gif_extension: + { + int len = count = q[1]; + gstate es = gif_skip_block; + + switch (*q) + { + case 0xf9: + es = gif_control_extension; + break; + + case 0x01: + // ignoring plain text extension + break; + + case 0xff: + es = gif_application_extension; + break; + + case 0xfe: + es = gif_consume_comment; + break; + } + + if (len) + GETN(len, es); + else + GETN(1, gif_image_start); + } + break; + + case gif_consume_block: + if (!*q) + GETN(1, gif_image_start); + else + GETN(*q, gif_skip_block); + break; + + case gif_skip_block: + GETN(1, gif_consume_block); + break; + + case gif_control_extension: + { + if (query != GIFImageDecoder::GIFFrameCountQuery) { + if (!frame_reader) + frame_reader = new GIFFrameReader(); + } + + if (frame_reader) { + if (*q & 0x1) { + frame_reader->tpixel = q[3]; + frame_reader->is_transparent = true; + } else { + frame_reader->is_transparent = false; + // ignoring gfx control extension + } + // NOTE: This relies on the values in the FrameDisposalMethod enum + // matching those in the GIF spec! + frame_reader->disposal_method = (WebCore::RGBA32Buffer::FrameDisposalMethod)(((*q) >> 2) & 0x7); + // Some specs say 3rd bit (value 4), other specs say value 3 + // Let's choose 3 (the more popular) + if (frame_reader->disposal_method == 4) + frame_reader->disposal_method = WebCore::RGBA32Buffer::DisposeOverwritePrevious; + frame_reader->delay_time = GETINT16(q + 1) * 10; + } + GETN(1, gif_consume_block); + } + break; + + case gif_comment_extension: + { + if (*q) + GETN(*q, gif_consume_comment); + else + GETN(1, gif_image_start); + } + break; + + case gif_consume_comment: + GETN(1, gif_comment_extension); + break; + + case gif_application_extension: + /* Check for netscape application extension */ + if (!strncmp((char*)q, "NETSCAPE2.0", 11) || + !strncmp((char*)q, "ANIMEXTS1.0", 11)) + GETN(1, gif_netscape_extension_block); + else + GETN(1, gif_consume_block); + break; + + /* Netscape-specific GIF extension: animation looping */ + case gif_netscape_extension_block: + if (*q) + GETN(*q, gif_consume_netscape_extension); + else + GETN(1, gif_image_start); + break; + + /* Parse netscape-specific application extensions */ + case gif_consume_netscape_extension: + { + int netscape_extension = q[0] & 7; + + /* Loop entire animation specified # of times. Only read the + loop count during the first iteration. */ + if (netscape_extension == 1) { + loop_count = GETINT16(q + 1); + + GETN(1, gif_netscape_extension_block); + } + /* Wait for specified # of bytes to enter buffer */ + else if (netscape_extension == 2) { + // Don't do this, this extension doesn't exist (isn't used at all) + // and doesn't do anything, as our streaming/buffering takes care of it all... + // See: http://semmix.pl/color/exgraf/eeg24.htm + GETN(1, gif_netscape_extension_block); + } else + state = gif_error; // 0,3-7 are yet to be defined netscape + // extension codes + + break; + } + + case gif_image_header: + { + unsigned height, width, x_offset, y_offset; + + /* Get image offsets, with respect to the screen origin */ + x_offset = GETINT16(q); + y_offset = GETINT16(q + 2); + + /* Get image width and height. */ + width = GETINT16(q + 4); + height = GETINT16(q + 6); + + /* Work around broken GIF files where the logical screen + * size has weird width or height. We assume that GIF87a + * files don't contain animations. + */ + if ((images_decoded == 0) && + ((screen_height < height) || (screen_width < width) || + (version == 87))) + { + screen_height = height; + screen_width = width; + x_offset = 0; + y_offset = 0; + + // CALLBACK: Inform the decoderplugin of our size. + if (clientptr) + clientptr->sizeNowAvailable(screen_width, screen_height); + } + + /* Work around more broken GIF files that have zero image + width or height */ + if (!height || !width) { + height = screen_height; + width = screen_width; + if (!height || !width) { + state = gif_error; + break; + } + } + + if (query == GIFImageDecoder::GIFSizeQuery || haltAtFrame == images_decoded) { + // The decoder needs to stop. Hand back the number of bytes we consumed from + // buffer minus 9 (the amount we consumed to read the header). + if (clientptr) + clientptr->decodingHalted(len + 9); + GETN(9, gif_image_header); + return true; + } + + images_count = images_decoded + 1; + + if (query == GIFImageDecoder::GIFFullQuery && !frame_reader) + frame_reader = new GIFFrameReader(); + + if (frame_reader) { + frame_reader->x_offset = x_offset; + frame_reader->y_offset = y_offset; + frame_reader->height = height; + frame_reader->width = width; + + /* This case will never be taken if this is the first image */ + /* being decoded. If any of the later images are larger */ + /* than the screen size, we need to reallocate buffers. */ + if (screen_width < width) { + /* XXX Deviant! */ + + delete []frame_reader->rowbuf; + screen_width = width; + frame_reader->rowbuf = new unsigned char[screen_width]; + } else if (!frame_reader->rowbuf) { + frame_reader->rowbuf = new unsigned char[screen_width]; + } + + if (!frame_reader->rowbuf) { + state = gif_oom; + break; + } + if (screen_height < height) + screen_height = height; + + if (q[8] & 0x40) { + frame_reader->interlaced = true; + frame_reader->ipass = 1; + } else { + frame_reader->interlaced = false; + frame_reader->ipass = 0; + } + + if (images_decoded == 0) { + frame_reader->progressive_display = true; + } else { + /* Overlaying interlaced, transparent GIFs over + existing image data using the Haeberli display hack + requires saving the underlying image in order to + avoid jaggies at the transparency edges. We are + unprepared to deal with that, so don't display such + images progressively */ + frame_reader->progressive_display = false; + } + + /* Clear state from last image */ + frame_reader->irow = 0; + frame_reader->rows_remaining = frame_reader->height; + frame_reader->rowend = frame_reader->rowbuf + frame_reader->width; + frame_reader->rowp = frame_reader->rowbuf; + + /* bits per pixel is q[8]&0x07 */ + } + + if (q[8] & 0x80) /* has a local colormap? */ + { + int num_colors = 2 << (q[8] & 0x7); + const unsigned size = 3*num_colors; + unsigned char *map = frame_reader ? frame_reader->local_colormap : 0; + if (frame_reader && (!map || (num_colors > frame_reader->local_colormap_size))) { + delete []map; + map = new unsigned char[size]; + if (!map) { + state = gif_oom; + break; + } + } + + /* Switch to the new local palette after it loads */ + if (frame_reader) { + frame_reader->local_colormap = map; + frame_reader->local_colormap_size = num_colors; + frame_reader->is_local_colormap_defined = true; + } + + if (len < size) { + // Use 'hold' pattern to get the image colormap + GETN(size, gif_image_colormap); + break; + } + // Copy everything and directly go to gif_lzw_start + if (frame_reader) + memcpy(frame_reader->local_colormap, buf, size); + buf += size; + len -= size; + } else if (frame_reader) { + /* Switch back to the global palette */ + frame_reader->is_local_colormap_defined = false; + } + GETN(1, gif_lzw_start); + } + break; + + case gif_image_colormap: + // Everything is already copied into local_colormap + GETN(1, gif_lzw_start); + break; + + case gif_sub_block: + { + if ((count = *q) != 0) + /* Still working on the same image: Process next LZW data block */ + { + /* Make sure there are still rows left. If the GIF data */ + /* is corrupt, we may not get an explicit terminator. */ + if (frame_reader && frame_reader->rows_remaining == 0) { + /* This is an illegal GIF, but we remain tolerant. */ + GETN(1, gif_sub_block); + } + GETN(count, gif_lzw); + } + else + /* See if there are any more images in this sequence. */ + { + images_decoded++; + + // CALLBACK: The frame is now complete. + if (clientptr && frame_reader) + clientptr->frameComplete(images_decoded - 1, frame_reader->delay_time, + frame_reader->disposal_method); + + /* Clear state from this image */ + if (frame_reader) { + frame_reader->is_local_colormap_defined = false; + frame_reader->is_transparent = false; + } + + GETN(1, gif_image_start); + } + } + break; + + case gif_done: + // When the GIF is done, we can stop. + if (clientptr) + clientptr->gifComplete(); + return true; + + // Handle out of memory errors + case gif_oom: + return false; + + // Handle general errors + case gif_error: + // nsGIFDecoder2::EndGIF(gs->clientptr, gs->loop_count); + return false; + + // We shouldn't ever get here. + default: + break; + } + } + + // Copy the leftover into gs->hold + bytes_in_hold = len; + if (len) { + // Add what we have sofar to the block + unsigned char* p; + if (state == gif_global_colormap) + p = global_colormap; + else if (state == gif_image_colormap) + p = frame_reader ? frame_reader->local_colormap : 0; + else + p = hold; + if (p) + memcpy(p, buf, len); + bytes_to_consume -= len; + } + + if (clientptr) + clientptr->decodingHalted(0); + return true; +} diff --git a/WebCore/platform/image-decoders/skia/GIFImageReader.h b/WebCore/platform/image-decoders/skia/GIFImageReader.h new file mode 100644 index 0000000..aa3d717 --- /dev/null +++ b/WebCore/platform/image-decoders/skia/GIFImageReader.h @@ -0,0 +1,215 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef GIFImageReader_h +#define GIFImageReader_h + +// Define ourselves as the clientPtr. Mozilla just hacked their C++ callback class into this old C decoder, +// so we will too. +#include "GIFImageDecoder.h" + +#define MAX_LZW_BITS 12 +#define MAX_BITS 4097 /* 2^MAX_LZW_BITS+1 */ +#define MAX_COLORS 256 +#define MAX_HOLD_SIZE 256 + +const int cLoopCountNotSeen = -2; + +/* gif2.h + The interface for the GIF87/89a decoder. +*/ +// List of possible parsing states +typedef enum { + gif_type, + gif_global_header, + gif_global_colormap, + gif_image_start, + gif_image_header, + gif_image_colormap, + gif_image_body, + gif_lzw_start, + gif_lzw, + gif_sub_block, + gif_extension, + gif_control_extension, + gif_consume_block, + gif_skip_block, + gif_done, + gif_oom, + gif_error, + gif_comment_extension, + gif_application_extension, + gif_netscape_extension_block, + gif_consume_netscape_extension, + gif_consume_comment +} gstate; + +struct GIFFrameReader { + /* LZW decoder state machine */ + unsigned char *stackp; /* Current stack pointer */ + int datasize; + int codesize; + int codemask; + int clear_code; /* Codeword used to trigger dictionary reset */ + int avail; /* Index of next available slot in dictionary */ + int oldcode; + unsigned char firstchar; + int bits; /* Number of unread bits in "datum" */ + int datum; /* 32-bit input buffer */ + + /* Output state machine */ + int ipass; /* Interlace pass; Ranges 1-4 if interlaced. */ + unsigned int rows_remaining; /* Rows remaining to be output */ + unsigned int irow; /* Current output row, starting at zero */ + unsigned char *rowbuf; /* Single scanline temporary buffer */ + unsigned char *rowend; /* Pointer to end of rowbuf */ + unsigned char *rowp; /* Current output pointer */ + + /* Parameters for image frame currently being decoded */ + unsigned int x_offset, y_offset; /* With respect to "screen" origin */ + unsigned int height, width; + int tpixel; /* Index of transparent pixel */ + WebCore::RGBA32Buffer::FrameDisposalMethod disposal_method; /* Restore to background, leave in place, etc.*/ + unsigned char *local_colormap; /* Per-image colormap */ + int local_colormap_size; /* Size of local colormap array. */ + + bool is_local_colormap_defined : 1; + bool progressive_display : 1; /* If TRUE, do Haeberli interlace hack */ + bool interlaced : 1; /* TRUE, if scanlines arrive interlaced order */ + bool is_transparent : 1; /* TRUE, if tpixel is valid */ + + unsigned delay_time; /* Display time, in milliseconds, + for this image in a multi-image GIF */ + + + unsigned short* prefix; /* LZW decoding tables */ + unsigned char* suffix; /* LZW decoding tables */ + unsigned char* stack; /* Base of LZW decoder stack */ + + + GIFFrameReader() { + stackp = 0; + datasize = codesize = codemask = clear_code = avail = oldcode = 0; + firstchar = 0; + bits = datum = 0; + ipass = 0; + rows_remaining = irow = 0; + rowbuf = rowend = rowp = 0; + + x_offset = y_offset = width = height = 0; + tpixel = 0; + disposal_method = WebCore::RGBA32Buffer::DisposeNotSpecified; + + local_colormap = 0; + local_colormap_size = 0; + is_local_colormap_defined = progressive_display = is_transparent = interlaced = false; + + delay_time = 0; + + prefix = 0; + suffix = stack = 0; + } + + ~GIFFrameReader() { + delete []rowbuf; + delete []local_colormap; + delete []prefix; + delete []suffix; + delete []stack; + } +}; + +struct GIFImageReader { + WebCore::GIFImageDecoder* clientptr; + /* Parsing state machine */ + gstate state; /* Current decoder master state */ + unsigned bytes_to_consume; /* Number of bytes to accumulate */ + unsigned bytes_in_hold; /* bytes accumulated so far*/ + unsigned char hold[MAX_HOLD_SIZE]; /* Accumulation buffer */ + unsigned char* global_colormap; /* (3* MAX_COLORS in size) Default colormap if local not supplied, 3 bytes for each color */ + + /* Global (multi-image) state */ + int screen_bgcolor; /* Logical screen background color */ + int version; /* Either 89 for GIF89 or 87 for GIF87 */ + unsigned screen_width; /* Logical screen width & height */ + unsigned screen_height; + int global_colormap_size; /* Size of global colormap array. */ + unsigned int images_decoded; /* Counts completed frames for animated GIFs */ + int images_count; /* Counted all frames seen so far (including incomplete frames) */ + int loop_count; /* Netscape specific extension block to control + the number of animation loops a GIF renders. */ + + // Not really global, but convenient to locate here. + int count; /* Remaining # bytes in sub-block */ + + GIFFrameReader* frame_reader; + + GIFImageReader(WebCore::GIFImageDecoder* client = 0) { + clientptr = client; + state = gif_type; + bytes_to_consume = 6; + bytes_in_hold = 0; + frame_reader = 0; + global_colormap = 0; + + screen_bgcolor = version = 0; + screen_width = screen_height = 0; + global_colormap_size = images_decoded = images_count = 0; + loop_count = cLoopCountNotSeen; + count = 0; + } + + ~GIFImageReader() { + close(); + } + + void close() { + delete []global_colormap; + global_colormap = 0; + delete frame_reader; + frame_reader = 0; + } + + bool read(const unsigned char * buf, unsigned int numbytes, + WebCore::GIFImageDecoder::GIFQuery query = WebCore::GIFImageDecoder::GIFFullQuery, unsigned haltAtFrame = -1); + +private: + void output_row(); + int do_lzw(const unsigned char *q); +}; + +#endif diff --git a/WebCore/platform/image-decoders/skia/ICOImageDecoder.cpp b/WebCore/platform/image-decoders/skia/ICOImageDecoder.cpp new file mode 100644 index 0000000..c340896 --- /dev/null +++ b/WebCore/platform/image-decoders/skia/ICOImageDecoder.cpp @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2008, 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 "ICOImageDecoder.h" + +namespace WebCore { + +// Number of bits in .ICO/.CUR used to store the directory and its entries, +// respectively (doesn't match sizeof values for member structs since we omit +// some fields). +static const size_t sizeOfDirectory = 6; +static const size_t sizeOfDirEntry = 16; + +void ICOImageDecoder::decodeImage(SharedBuffer* data) +{ + // Read and process directory. + if ((m_decodedOffset < sizeOfDirectory) && !processDirectory(data)) + return; + + // Read and process directory entries. + if ((m_decodedOffset < (sizeOfDirectory + (m_directory.idCount * sizeOfDirEntry))) + && !processDirectoryEntries(data)) + return; + + // Check if this entry is a PNG; we need 4 bytes to check the magic number. + if (m_imageType == Unknown) { + if (data->size() < (m_dirEntry.dwImageOffset + 4)) + return; + m_imageType = + strncmp(&data->data()[m_dirEntry.dwImageOffset], "\x89PNG", 4) ? + BMP : PNG; + } + + // Decode selected entry. + if (m_imageType == PNG) + decodePNG(data); + else { + // Note that we don't try to limit the bytes we give to the decoder to + // just the size specified in the icon directory. If the size given in + // the directory is insufficient to decode the whole image, the image is + // corrupt anyway, so whatever we do may be wrong. The easiest choice + // (which we do here) is to simply aggressively consume bytes until we + // run out of bytes, finish decoding, or hit a sequence that makes the + // decoder fail. + decodeBMP(data); + } +} + +RGBA32Buffer* ICOImageDecoder::frameBufferAtIndex(size_t index) +{ + return (m_imageType == PNG) ? m_pngDecoder.frameBufferAtIndex(0) : + BMPImageReader::frameBufferAtIndex(0); +} + +bool ICOImageDecoder::isSizeAvailable() const +{ + return (m_imageType == PNG) ? m_pngDecoder.isSizeAvailable() : + BMPImageReader::isSizeAvailable(); +} + +IntSize ICOImageDecoder::size() const +{ + return (m_imageType == PNG) ? m_pngDecoder.size() : BMPImageReader::size(); +} + +bool ICOImageDecoder::processDirectory(SharedBuffer* data) +{ + // Read directory. + ASSERT(!m_decodedOffset); + if (data->size() < sizeOfDirectory) + return false; + const uint16_t fileType = readUint16(data, 2); + m_directory.idCount = readUint16(data, 4); + m_decodedOffset = sizeOfDirectory; + + // See if this is an icon filetype we understand, and make sure we have at + // least one entry in the directory. + enum { + ICON = 1, + CURSOR = 2, + }; + if (((fileType != ICON) && (fileType != CURSOR)) || + (m_directory.idCount == 0)) + m_failed = true; + + return !m_failed; +} + +bool ICOImageDecoder::processDirectoryEntries(SharedBuffer* data) +{ + // Read directory entries. + ASSERT(m_decodedOffset == sizeOfDirectory); + if ((m_decodedOffset > data->size()) || (data->size() - m_decodedOffset) < + (m_directory.idCount * sizeOfDirEntry)) + return false; + for (int i = 0; i < m_directory.idCount; ++i) { + const IconDirectoryEntry dirEntry = readDirectoryEntry(data); + if ((i == 0) || isBetterEntry(dirEntry)) + m_dirEntry = dirEntry; + } + + // Make sure the specified image offset is past the end of the directory + // entries, and that the offset isn't so large that it overflows when we add + // 4 bytes to it (which we do in decodeImage() while ensuring it's safe to + // examine the first 4 bytes of the image data). + if ((m_dirEntry.dwImageOffset < m_decodedOffset) || + ((m_dirEntry.dwImageOffset + 4) < m_dirEntry.dwImageOffset)) { + m_failed = true; + return false; + } + + // Ready to decode the image at the specified offset. + m_decodedOffset = m_headerOffset = m_dirEntry.dwImageOffset; + return true; +} + +ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry( + SharedBuffer* data) +{ + // Read icon data. + IconDirectoryEntry entry; + entry.bWidth = static_cast<uint8_t>(data->data()[m_decodedOffset]); + if (entry.bWidth == 0) + entry.bWidth = 256; + entry.bHeight = static_cast<uint8_t>(data->data()[m_decodedOffset + 1]); + if (entry.bHeight == 0) + entry.bHeight = 256; + entry.wBitCount = readUint16(data, 6); + entry.dwImageOffset = readUint32(data, 12); + + // Some icons don't have a bit depth, only a color count. Convert the + // color count to the minimum necessary bit depth. It doesn't matter if + // 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.wBitCount) { + uint8_t colorCount = data->data()[m_decodedOffset + 2]; + if (colorCount) { + for (--colorCount; colorCount; colorCount >>= 1) + ++entry.wBitCount; + } + } + + m_decodedOffset += sizeOfDirEntry; + return entry; +} + +bool ICOImageDecoder::isBetterEntry(const IconDirectoryEntry& entry) const +{ + const IntSize entrySize(entry.bWidth, entry.bHeight); + const IntSize dirEntrySize(m_dirEntry.bWidth, m_dirEntry.bHeight); + const int entryArea = entry.bWidth * entry.bHeight; + const int dirEntryArea = m_dirEntry.bWidth * m_dirEntry.bHeight; + + if ((entrySize != dirEntrySize) && !m_preferredIconSize.isEmpty()) { + // An icon of exactly the preferred size is best. + if (entrySize == m_preferredIconSize) + return true; + if (dirEntrySize == m_preferredIconSize) + return false; + + // The icon closest to the preferred area without being smaller is + // better. + if (entryArea != dirEntryArea) { + return (entryArea < dirEntryArea) + && (entryArea >= (m_preferredIconSize.width() * m_preferredIconSize.height())); + } + } + + // Larger icons are better. + if (entryArea != dirEntryArea) + return (entryArea > dirEntryArea); + + // Higher bit-depth icons are better. + return (entry.wBitCount > m_dirEntry.wBitCount); +} + +void ICOImageDecoder::decodePNG(SharedBuffer* data) +{ + // Copy out PNG data to a separate vector and instantiate PNG decoder. + // It would be nice to save this copy, if I could figure out how to just + // offset the perceived start of |data| by |m_dirEntry.dwImageOffset| when + // passing it to setData()... + RefPtr<SharedBuffer> pngData( + SharedBuffer::create(&data->data()[m_dirEntry.dwImageOffset], + data->size() - m_dirEntry.dwImageOffset)); + m_pngDecoder.setData(pngData.get(), true); + + // Decode PNG as a side effect of asking for the frame. Strangely, it's + // seemingly unsafe to call decode() or isSizeAvailable() before calling + // this, as this is the only function that enlarges the framebuffer to + // nonzero size, and before this happens any decoded image data is silently + // thrown away and never decoded again (!). + m_pngDecoder.frameBufferAtIndex(0); + m_failed = m_pngDecoder.failed(); + + // Sanity-check that the size is what we expected. + if (isSizeAvailable() && ((size().width() != m_dirEntry.bWidth) || + (size().height() != m_dirEntry.bHeight))) + m_failed = true; +} + +} diff --git a/WebCore/platform/image-decoders/skia/ICOImageDecoder.h b/WebCore/platform/image-decoders/skia/ICOImageDecoder.h new file mode 100644 index 0000000..f0e1acc --- /dev/null +++ b/WebCore/platform/image-decoders/skia/ICOImageDecoder.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2008, 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 ICOImageDecoder_h +#define ICOImageDecoder_h + +#include "BMPImageReader.h" +#include "PNGImageDecoder.h" + +namespace WebCore { + + // This class decodes the ICO and CUR image formats. + class ICOImageDecoder : public BMPImageReader { + public: + // See comments on |m_preferredIconSize| below. + ICOImageDecoder(const IntSize& preferredIconSize) + : m_preferredIconSize(preferredIconSize) + , m_imageType(Unknown) + { + m_andMaskState = NotYetDecoded; + } + + virtual String filenameExtension() const { return "ico"; } + + // BMPImageReader + virtual void decodeImage(SharedBuffer* data); + virtual RGBA32Buffer* frameBufferAtIndex(size_t index); + + // ImageDecoder + virtual bool isSizeAvailable() const; + virtual IntSize size() const; + + private: + enum ImageType { + Unknown, + BMP, + PNG, + }; + + // These are based on the Windows ICONDIR and ICONDIRENTRY structs, but + // with unnecessary entries removed. + struct IconDirectory { + uint16_t idCount; + }; + struct IconDirectoryEntry { + uint16_t bWidth; // 16 bits so we can represent 256 as 256, not 0 + uint16_t bHeight; // " + uint16_t wBitCount; + uint32_t dwImageOffset; + }; + + // Processes the ICONDIR at the beginning of the data. Returns true if the + // directory could be decoded. + bool processDirectory(SharedBuffer*); + + // Processes the ICONDIRENTRY records after the directory. Keeps the + // "best" entry as the one we'll decode. Returns true if the entries could + // be decoded. + bool processDirectoryEntries(SharedBuffer*); + + // Reads and returns a directory entry from the current offset into |data|. + IconDirectoryEntry readDirectoryEntry(SharedBuffer*); + + // Returns true if |entry| is a preferable icon entry to m_dirEntry. + // Larger sizes, or greater bitdepths at the same size, are preferable. + bool isBetterEntry(const IconDirectoryEntry&) const; + + // Called when the image to be decoded is a PNG rather than a BMP. + // Instantiates a PNGImageDecoder, decodes the image, and copies the + // results locally. + void decodePNG(SharedBuffer*); + + // The entry size we should prefer. If this is empty, we choose the + // largest available size. If no entries of the desired size are + // available, we pick the next larger size. + IntSize m_preferredIconSize; + + // The headers for the ICO. + IconDirectory m_directory; + IconDirectoryEntry m_dirEntry; + + // The PNG decoder, if we need to use one. + PNGImageDecoder m_pngDecoder; + + // What kind of image data is stored at the entry we're decoding. + ImageType m_imageType; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/image-decoders/skia/ImageDecoder.h b/WebCore/platform/image-decoders/skia/ImageDecoder.h new file mode 100644 index 0000000..9988a3e --- /dev/null +++ b/WebCore/platform/image-decoders/skia/ImageDecoder.h @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008, 2009 Google, 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. + */ + +#ifndef ImageDecoder_h +#define ImageDecoder_h + +#include "IntRect.h" +#include "ImageSource.h" +#include "NativeImageSkia.h" +#include "PlatformString.h" +#include "SharedBuffer.h" +#include <wtf/Assertions.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +#include "SkBitmap.h" + +namespace WebCore { + + class RefCountedNativeImageSkia : public RefCounted<RefCountedNativeImageSkia> { + public: + static PassRefPtr<RefCountedNativeImageSkia> create() + { + return adoptRef(new RefCountedNativeImageSkia); + } + + const NativeImageSkia& bitmap() const { return m_bitmap; } + NativeImageSkia& bitmap() { return m_bitmap; } + + private: + RefCountedNativeImageSkia() {} + NativeImageSkia m_bitmap; + }; + + // The RGBA32Buffer object represents the decoded image data in RGBA32 format. + // This buffer is what all decoders write a single frame into. Frames are then + // instantiated for drawing by being handed this buffer. + // + // The image data of an RGBA32Buffer is kept in an SkBitmapRef, a refcounting + // container for an SkBitmap. In all normal cases, the refcount should be + // exactly one. The exception happens when resizing the vector<RGBA32Buffer> in + // ImageDecoder::m_frameBufferCache, which copies all the buffers to the new + // vector, thus transiently incrementing the refcount to two. + // + // The choice to use an SkBitmapRef instead of an SkBitmap is not because of + // performance concerns -- SkBitmap refcounts its internal data anyway. Rather, + // we need the aforementioned vector resize to preserve the exact underlying + // SkBitmap object, since we may have already given its address to + // BitmapImage::m_frames. Using an SkBitmap would mean that after ImageDecoder + // resizes its vector, BitmapImage would be holding a pointer to garbage. + class RGBA32Buffer { + public: + enum FrameStatus { FrameEmpty, FramePartial, FrameComplete }; + + enum FrameDisposalMethod { + // If you change the numeric values of these, make sure you audit all + // users, as some users may cast raw values to/from these constants. + DisposeNotSpecified, // Leave frame in framebuffer + DisposeKeep, // Leave frame in framebuffer + DisposeOverwriteBgcolor, // Clear frame to transparent + DisposeOverwritePrevious, // Clear frame to previous framebuffer contents + }; + + RGBA32Buffer() + : m_status(FrameEmpty) + , m_duration(0) + , m_disposalMethod(DisposeNotSpecified) + { + m_bitmapRef = RefCountedNativeImageSkia::create(); + } + + // This constructor doesn't create a new copy of the image data, it only + // increases the ref count of the existing bitmap. + RGBA32Buffer(const RGBA32Buffer& other) + { + m_bitmapRef = RefCountedNativeImageSkia::create(); + operator=(other); + } + + ~RGBA32Buffer() + { + } + + // Initialize with another buffer. This function doesn't create a new copy + // of the image data, it only increases the refcount of the existing bitmap. + // + // Normal callers should not generally be using this function. If you want + // to create a copy on which you can modify the image data independently, + // use copyBitmapData() instead. + RGBA32Buffer& operator=(const RGBA32Buffer& other) + { + if (this == &other) + return *this; + + m_bitmapRef = other.m_bitmapRef; + setRect(other.rect()); + setStatus(other.status()); + setDuration(other.duration()); + setDisposalMethod(other.disposalMethod()); + setHasAlpha(other.hasAlpha()); + return *this; + } + + void clear() + { + m_bitmapRef = RefCountedNativeImageSkia::create(); + m_rect = IntRect(); + m_status = FrameEmpty; + m_duration = 0; + m_disposalMethod = DisposeNotSpecified; + } + + // This function creates a new copy of the image data in |other|, so the + // two images can be modified independently. + void copyBitmapData(const RGBA32Buffer& other) + { + if (this == &other) + return; + + m_bitmapRef = RefCountedNativeImageSkia::create(); + SkBitmap& bmp = bitmap(); + const SkBitmap& otherBmp = other.bitmap(); + bmp.setConfig(SkBitmap::kARGB_8888_Config, other.width(), + other.height(), otherBmp.rowBytes()); + bmp.allocPixels(); + if (width() > 0 && height() > 0) { + memcpy(bmp.getAddr32(0, 0), + otherBmp.getAddr32(0, 0), + otherBmp.rowBytes() * height()); + } + } + + NativeImageSkia& bitmap() { return m_bitmapRef->bitmap(); } + const NativeImageSkia& bitmap() const { return m_bitmapRef->bitmap(); } + + // Must be called before any pixels are written. Will return true on + // success, false if the memory allocation fails. + bool setSize(int width, int height) + { + // This function should only be called once, it will leak memory + // otherwise. + SkBitmap& bmp = bitmap(); + ASSERT(bmp.width() == 0 && bmp.height() == 0); + bmp.setConfig(SkBitmap::kARGB_8888_Config, width, height); + if (!bmp.allocPixels()) + return false; // Allocation failure, maybe the bitmap was too big. + + // Clear the image. + bmp.eraseARGB(0, 0, 0, 0); + + return true; + } + + int width() const { return bitmap().width(); } + int height() const { return bitmap().height(); } + + const IntRect& rect() const { return m_rect; } + FrameStatus status() const { return m_status; } + unsigned duration() const { return m_duration; } + FrameDisposalMethod disposalMethod() const { return m_disposalMethod; } + bool hasAlpha() const { return !bitmap().isOpaque(); } + + void setRect(const IntRect& r) { m_rect = r; } + void setStatus(FrameStatus s) + { + if (s == FrameComplete) + m_bitmapRef->bitmap().setDataComplete(); // Tell the bitmap it's done. + m_status = s; + } + void setDuration(unsigned duration) { m_duration = duration; } + void setDisposalMethod(FrameDisposalMethod method) { m_disposalMethod = method; } + void setHasAlpha(bool alpha) { bitmap().setIsOpaque(!alpha); } + + static void setRGBA(uint32_t* dest, uint8_t r, uint8_t g, uint8_t b, uint8_t a) + { + // We store this data pre-multiplied. + if (a == 0) + *dest = 0; + else { + if (a < 255) { + float alphaPercent = a / 255.0f; + r = static_cast<unsigned>(r * alphaPercent); + g = static_cast<unsigned>(g * alphaPercent); + b = static_cast<unsigned>(b * alphaPercent); + } + *dest = (a << 24 | r << 16 | g << 8 | b); + } + } + + void setRGBA(int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t a) + { + setRGBA(bitmap().getAddr32(x, y), r, g, b, a); + } + + private: + RefPtr<RefCountedNativeImageSkia> m_bitmapRef; + 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 + // whose original rect was smaller than the overall image size. + FrameStatus m_status; // Whether or not this frame is completely finished decoding. + unsigned m_duration; // The animation delay. + FrameDisposalMethod m_disposalMethod; // What to do with this frame's data when initializing the next frame. + }; + + // The ImageDecoder class represents a base class for specific image format decoders + // (e.g., GIF, JPG, PNG, ICO) to derive from. All decoders decode into RGBA32 format + // and the base class manages the RGBA32 frame cache. + class ImageDecoder { + public: + ImageDecoder() : m_failed(false), m_sizeAvailable(false) {} + virtual ~ImageDecoder() {} + + // The the filename extension usually associated with an undecoded image of this type. + virtual String filenameExtension() const = 0; + + // All specific decoder plugins must do something with the data they are given. + virtual void setData(SharedBuffer* data, bool allDataReceived) { m_data = data; } + + // Whether or not the size information has been decoded yet. This default + // implementation just returns true if the size has been set and we have not + // seen a failure. Decoders may want to override this to lazily decode + // enough of the image to get the size. + virtual bool isSizeAvailable() const + { + return !m_failed && m_sizeAvailable; + } + + // Requests the size. + virtual IntSize size() const + { + // Requesting the size of an invalid bitmap is meaningless. + ASSERT(!m_failed); + return m_size; + } + + // The total number of frames for the image. Classes that support multiple frames + // will scan the image data for the answer if they need to (without necessarily + // decoding all of the individual frames). + virtual int frameCount() { return 1; } + + // The number of repetitions to perform for an animation loop. + virtual int repetitionCount() const { return cAnimationNone; } + + // Called to obtain the RGBA32Buffer full of decoded data for rendering. The + // decoder plugin will decode as much of the frame as it can before handing + // back the buffer. + virtual RGBA32Buffer* frameBufferAtIndex(size_t index) = 0; + + // Whether or not the underlying image format even supports alpha transparency. + virtual bool supportsAlpha() const { return true; } + + bool failed() const { return m_failed; } + void setFailed() { m_failed = true; } + + // Wipe out frames in the frame buffer cache before |clearBeforeFrame|, + // assuming this can be done without breaking decoding. Different decoders + // place different restrictions on what frames are safe to destroy, so this + // is left to them to implement. + // For convenience's sake, we provide a default (empty) implementation, + // since in practice only GIFs will ever use this. + virtual void clearFrameBufferCache(size_t clearBeforeFrame) { } + + protected: + // Called by the image decoders to set their decoded size, this also check + // the size for validity. It will return true if the size was set, or false + // if there is an error. On error, the m_failed flag will be set and the + // caller should immediately stop decoding. + bool setSize(unsigned width, unsigned height) + { + if (isOverSize(width, height)) { + m_failed = true; + return false; + } + m_size = IntSize(width, height); + m_sizeAvailable = true; + return true; + } + + RefPtr<SharedBuffer> m_data; // The encoded data. + Vector<RGBA32Buffer> m_frameBufferCache; + mutable bool m_failed; + + private: + // This function allows us to make sure the image is not too large. Very + // large images, even if the allocation succeeds, can take a very long time + // to process, giving the appearance of a DoS. + // + // WebKit also seems to like to ask for the size before data is available + // and in some cases when the failed flag is set. Some of these code paths + // such as BitmapImage::resetAnimation then compute the size of the image + // based on the width and height. Because of this, our total computed image + // byte size must never overflow an int. + static bool isOverSize(unsigned width, unsigned height) + { + unsigned long long total_size = static_cast<unsigned long long>(width) + * static_cast<unsigned long long>(height); + if (total_size > 32 * 1024 * 1024) // 32M = 128MB memory total (32 bpp). + return true; + return false; + } + + IntSize m_size; + bool m_sizeAvailable; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/image-decoders/skia/JPEGImageDecoder.cpp b/WebCore/platform/image-decoders/skia/JPEGImageDecoder.cpp new file mode 100644 index 0000000..98f622e --- /dev/null +++ b/WebCore/platform/image-decoders/skia/JPEGImageDecoder.cpp @@ -0,0 +1,512 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2008, 2009 Google, Inc. + * + * Portions are Copyright (C) 2001-6 mozilla.org + * + * Other contributors: + * Stuart Parmenter <stuart@mozilla.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * + * Alternatively, the contents of this file may be used under the terms + * of either the Mozilla Public License Version 1.1, found at + * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public + * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html + * (the "GPL"), in which case the provisions of the MPL or the GPL are + * applicable instead of those above. If you wish to allow use of your + * version of this file only under the terms of one of those two + * licenses (the MPL or the GPL) and not to allow others to use your + * version of this file under the LGPL, indicate your decision by + * deletingthe provisions above and replace them with the notice and + * other provisions required by the MPL or the GPL, as the case may be. + * If you do not delete the provisions above, a recipient may use your + * version of this file under any of the LGPL, the MPL or the GPL. + */ + +#include "config.h" +#include "JPEGImageDecoder.h" +#include <assert.h> + +extern "C" { +#include "jpeglib.h" +} + +#include <setjmp.h> + +namespace WebCore { + +struct decoder_error_mgr { + struct jpeg_error_mgr pub; /* "public" fields for IJG library*/ + jmp_buf setjmp_buffer; /* For handling catastropic errors */ +}; + +enum jstate { + JPEG_HEADER, /* Reading JFIF headers */ + JPEG_START_DECOMPRESS, + JPEG_DECOMPRESS_PROGRESSIVE, /* Output progressive pixels */ + JPEG_DECOMPRESS_SEQUENTIAL, /* Output sequential pixels */ + JPEG_DONE, + JPEG_SINK_NON_JPEG_TRAILER, /* Some image files have a */ + /* non-JPEG trailer */ + JPEG_ERROR +}; + +void init_source(j_decompress_ptr jd); +boolean fill_input_buffer(j_decompress_ptr jd); +void skip_input_data(j_decompress_ptr jd, long num_bytes); +void term_source(j_decompress_ptr jd); +void error_exit(j_common_ptr cinfo); + +/* + * Implementation of a JPEG src object that understands our state machine + */ +struct decoder_source_mgr { + /* public fields; must be first in this struct! */ + struct jpeg_source_mgr pub; + + JPEGImageReader *decoder; +}; + +class JPEGImageReader +{ +public: + JPEGImageReader(JPEGImageDecoder* decoder) + : m_decoder(decoder) + , m_bufferLength(0) + , m_bytesToSkip(0) + , m_state(JPEG_HEADER) + , m_samples(0) + { + memset(&m_info, 0, sizeof(jpeg_decompress_struct)); + + /* We set up the normal JPEG error routines, then override error_exit. */ + m_info.err = jpeg_std_error(&m_err.pub); + m_err.pub.error_exit = error_exit; + + /* Allocate and initialize JPEG decompression object */ + jpeg_create_decompress(&m_info); + + decoder_source_mgr* src = NULL; + if (!m_info.src) { + src = (decoder_source_mgr*)fastCalloc(sizeof(decoder_source_mgr), 1); + if (!src) { + m_state = JPEG_ERROR; + return; + } + } + + m_info.src = (jpeg_source_mgr*)src; + + /* Set up callback functions. */ + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; + src->pub.term_source = term_source; + src->decoder = this; + } + + ~JPEGImageReader() + { + close(); + } + + void close() { + decoder_source_mgr* src = (decoder_source_mgr*)m_info.src; + if (src) + fastFree(src); + m_info.src = 0; + + jpeg_destroy_decompress(&m_info); + } + + void skipBytes(long num_bytes) { + decoder_source_mgr* src = (decoder_source_mgr*)m_info.src; + long bytesToSkip = std::min(num_bytes, (long)src->pub.bytes_in_buffer); + src->pub.bytes_in_buffer -= (size_t)bytesToSkip; + src->pub.next_input_byte += bytesToSkip; + + if (num_bytes > bytesToSkip) + m_bytesToSkip = (size_t)(num_bytes - bytesToSkip); + else + m_bytesToSkip = 0; + } + + bool decode(const Vector<char>& data, bool sizeOnly) { + m_decodingSizeOnly = sizeOnly; + + unsigned newByteCount = data.size() - m_bufferLength; + unsigned readOffset = m_bufferLength - m_info.src->bytes_in_buffer; + + m_info.src->bytes_in_buffer += newByteCount; + m_info.src->next_input_byte = (JOCTET*)(data.data()) + readOffset; + + // If we still have bytes to skip, try to skip those now. + if (m_bytesToSkip) + skipBytes(m_bytesToSkip); + + m_bufferLength = data.size(); + + // We need to do the setjmp here. Otherwise bad things will happen + if (setjmp(m_err.setjmp_buffer)) { + m_state = JPEG_SINK_NON_JPEG_TRAILER; + close(); + return false; + } + + switch (m_state) { + case JPEG_HEADER: + { + /* Read file parameters with jpeg_read_header() */ + if (jpeg_read_header(&m_info, true) == JPEG_SUSPENDED) + return true; /* I/O suspension */ + + /* let libjpeg take care of gray->RGB and YCbCr->RGB conversions */ + switch (m_info.jpeg_color_space) { + case JCS_GRAYSCALE: + case JCS_RGB: + case JCS_YCbCr: + m_info.out_color_space = JCS_RGB; + break; + case JCS_CMYK: + case JCS_YCCK: + default: + m_state = JPEG_ERROR; + return false; + } + + /* + * Don't allocate a giant and superfluous memory buffer + * when the image is a sequential JPEG. + */ + m_info.buffered_image = jpeg_has_multiple_scans(&m_info); + + /* Used to set up image size so arrays can be allocated */ + jpeg_calc_output_dimensions(&m_info); + + /* + * Make a one-row-high sample array that will go away + * when done with image. Always make it big enough to + * hold an RGB row. Since this uses the IJG memory + * manager, it must be allocated before the call to + * jpeg_start_compress(). + */ + int row_stride = m_info.output_width * 4; // RGBA buffer + + + m_samples = (*m_info.mem->alloc_sarray)((j_common_ptr) &m_info, + JPOOL_IMAGE, + row_stride, 1); + + m_state = JPEG_START_DECOMPRESS; + + // We can fill in the size now that the header is available. + if (!m_decoder->setSize(m_info.image_width, m_info.image_height)) { + m_state = JPEG_ERROR; + return false; + } + + if (m_decodingSizeOnly) { + // We can stop here. + // Reduce our buffer length and available data. + m_bufferLength -= m_info.src->bytes_in_buffer; + m_info.src->bytes_in_buffer = 0; + return true; + } + } + + case JPEG_START_DECOMPRESS: + { + /* Set parameters for decompression */ + /* FIXME -- Should reset dct_method and dither mode + * for final pass of progressive JPEG + */ + m_info.dct_method = JDCT_ISLOW; + m_info.dither_mode = JDITHER_FS; + m_info.do_fancy_upsampling = true; + m_info.enable_2pass_quant = false; + m_info.do_block_smoothing = true; + + /* Start decompressor */ + if (!jpeg_start_decompress(&m_info)) + return true; /* I/O suspension */ + + /* If this is a progressive JPEG ... */ + m_state = (m_info.buffered_image) ? JPEG_DECOMPRESS_PROGRESSIVE : JPEG_DECOMPRESS_SEQUENTIAL; + } + + case JPEG_DECOMPRESS_SEQUENTIAL: + { + if (m_state == JPEG_DECOMPRESS_SEQUENTIAL) { + + if (!m_decoder->outputScanlines()) + return true; /* I/O suspension */ + + /* If we've completed image output ... */ + assert(m_info.output_scanline == m_info.output_height); + m_state = JPEG_DONE; + } + } + + case JPEG_DECOMPRESS_PROGRESSIVE: + { + if (m_state == JPEG_DECOMPRESS_PROGRESSIVE) { + int status; + do { + status = jpeg_consume_input(&m_info); + } while ((status != JPEG_SUSPENDED) && + (status != JPEG_REACHED_EOI)); + + for (;;) { + if (m_info.output_scanline == 0) { + int scan = m_info.input_scan_number; + + /* if we haven't displayed anything yet (output_scan_number==0) + and we have enough data for a complete scan, force output + of the last full scan */ + if ((m_info.output_scan_number == 0) && + (scan > 1) && + (status != JPEG_REACHED_EOI)) + scan--; + + if (!jpeg_start_output(&m_info, scan)) + return true; /* I/O suspension */ + } + + if (m_info.output_scanline == 0xffffff) + m_info.output_scanline = 0; + + if (!m_decoder->outputScanlines()) { + if (m_info.output_scanline == 0) + /* didn't manage to read any lines - flag so we don't call + jpeg_start_output() multiple times for the same scan */ + m_info.output_scanline = 0xffffff; + return true; /* I/O suspension */ + } + + if (m_info.output_scanline == m_info.output_height) { + if (!jpeg_finish_output(&m_info)) + return true; /* I/O suspension */ + + if (jpeg_input_complete(&m_info) && + (m_info.input_scan_number == m_info.output_scan_number)) + break; + + m_info.output_scanline = 0; + } + } + + m_state = JPEG_DONE; + } + } + + case JPEG_DONE: + { + /* Finish decompression */ + if (!jpeg_finish_decompress(&m_info)) + return true; /* I/O suspension */ + + m_state = JPEG_SINK_NON_JPEG_TRAILER; + + /* we're done */ + break; + } + + case JPEG_SINK_NON_JPEG_TRAILER: + break; + + case JPEG_ERROR: + break; + } + + return true; + } + + jpeg_decompress_struct* info() { return &m_info; } + JSAMPARRAY samples() const { return m_samples; } + JPEGImageDecoder* decoder() { return m_decoder; } + +private: + JPEGImageDecoder* m_decoder; + unsigned m_bufferLength; + int m_bytesToSkip; + bool m_decodingSizeOnly; + bool m_initialized; + + jpeg_decompress_struct m_info; + decoder_error_mgr m_err; + jstate m_state; + + JSAMPARRAY m_samples; +}; + +/* Override the standard error method in the IJG JPEG decoder code. */ +void error_exit(j_common_ptr cinfo) +{ + /* Return control to the setjmp point. */ + decoder_error_mgr *err = (decoder_error_mgr *) cinfo->err; + longjmp(err->setjmp_buffer, -1); +} + +void init_source(j_decompress_ptr jd) +{ +} + +void skip_input_data(j_decompress_ptr jd, long num_bytes) +{ + decoder_source_mgr *src = (decoder_source_mgr *)jd->src; + src->decoder->skipBytes(num_bytes); +} + +boolean fill_input_buffer(j_decompress_ptr jd) +{ + // Our decode step always sets things up properly, so if this method is ever + // called, then we have hit the end of the buffer. A return value of FALSE indicates + // that we have no data to supply yet. + return false; +} + +void term_source (j_decompress_ptr jd) +{ + decoder_source_mgr *src = (decoder_source_mgr *)jd->src; + src->decoder->decoder()->jpegComplete(); +} + +JPEGImageDecoder::JPEGImageDecoder() +: m_reader(0) +{} + +JPEGImageDecoder::~JPEGImageDecoder() +{ + delete m_reader; +} + +// Take the data and store it. +void JPEGImageDecoder::setData(SharedBuffer* data, bool allDataReceived) +{ + if (m_failed) + return; + + // Cache our new data. + ImageDecoder::setData(data, allDataReceived); + + // Create the JPEG reader. + if (!m_reader && !m_failed) + m_reader = new JPEGImageReader(this); +} + +// Whether or not the size information has been decoded yet. +bool JPEGImageDecoder::isSizeAvailable() const +{ + // If we have pending data to decode, send it to the JPEG reader now. + if (!ImageDecoder::isSizeAvailable() && m_reader) { + if (m_failed) + return false; + + // The decoder will go ahead and aggressively consume everything up until the + // size is encountered. + decode(true); + } + + return !m_failed && ImageDecoder::isSizeAvailable(); +} + +RGBA32Buffer* JPEGImageDecoder::frameBufferAtIndex(size_t index) +{ + if (index) + return 0; + + if (m_frameBufferCache.isEmpty()) + m_frameBufferCache.resize(1); + + RGBA32Buffer& frame = m_frameBufferCache[0]; + if (frame.status() != RGBA32Buffer::FrameComplete && m_reader) + // Decode this frame. + decode(); + return &frame; +} + +// Feed data to the JPEG reader. +void JPEGImageDecoder::decode(bool sizeOnly) const +{ + if (m_failed) + return; + + m_failed = !m_reader->decode(m_data->buffer(), sizeOnly); + + if (m_failed || (!m_frameBufferCache.isEmpty() && m_frameBufferCache[0].status() == RGBA32Buffer::FrameComplete)) { + delete m_reader; + m_reader = 0; + } +} + +bool JPEGImageDecoder::outputScanlines() +{ + if (m_frameBufferCache.isEmpty()) + return false; + + // Resize to the width and height of the image. + RGBA32Buffer& buffer = m_frameBufferCache[0]; + if (buffer.status() == RGBA32Buffer::FrameEmpty) { + // Let's resize our buffer now to the correct width/height. This will + // also initialize it to transparent. + if (!buffer.setSize(size().width(), size().height())) { + m_failed = true; + buffer.setStatus(RGBA32Buffer::FrameComplete); + return false; + } + + // Update our status to be partially complete. + buffer.setStatus(RGBA32Buffer::FramePartial); + + // For JPEGs, the frame always fills the entire image. + buffer.setRect(IntRect(0, 0, size().width(), size().height())); + + // We don't have alpha (this is the default when the buffer is constructed). + } + + jpeg_decompress_struct* info = m_reader->info(); + JSAMPARRAY samples = m_reader->samples(); + + while (info->output_scanline < info->output_height) { + /* Request one scanline. Returns 0 or 1 scanlines. */ + if (jpeg_read_scanlines(info, samples, 1) != 1) + return false; + JSAMPLE *j1 = samples[0]; + for (unsigned x = 0; x < info->output_width; ++x) { + unsigned r = *j1++; + unsigned g = *j1++; + unsigned b = *j1++; + // read_scanlines has increased the scanline counter, so we + // actually mean the previous one. + buffer.setRGBA(x, info->output_scanline - 1, r, g, b, 0xFF); + } + } + + return true; +} + +void JPEGImageDecoder::jpegComplete() +{ + if (m_frameBufferCache.isEmpty()) + return; + + // Hand back an appropriately sized buffer, even if the image ended up being empty. + RGBA32Buffer& buffer = m_frameBufferCache[0]; + buffer.setStatus(RGBA32Buffer::FrameComplete); +} + +} diff --git a/WebCore/platform/qt/SharedTimerQt.h b/WebCore/platform/image-decoders/skia/JPEGImageDecoder.h index 30e1e21..51dd050 100644 --- a/WebCore/platform/qt/SharedTimerQt.h +++ b/WebCore/platform/image-decoders/skia/JPEGImageDecoder.h @@ -1,7 +1,6 @@ /* - * Copyright (C) 2006 George Staikos <staikos@kde.org> - * - * All rights reserved. + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008, 2009 Google, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,67 +24,45 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SharedTimerQt_h -#define SharedTimerQt_h - -#include "SharedTimerQt.h" -#include "SystemTime.h" +#ifndef JPEGImageDecoder_h +#define JPEGImageDecoder_h -#include <QTimer> -#include <QCoreApplication> +#include "ImageDecoder.h" namespace WebCore { -class SharedTimerQt : public QTimer { -Q_OBJECT -protected: - SharedTimerQt() - : QTimer() - , m_timerFunction(0) - { - connect(this, SIGNAL(timeout()), this, SLOT(fire())); - setSingleShot(true); - } + class JPEGImageReader; - ~SharedTimerQt() - { - } + // This class decodes the JPEG image format. + class JPEGImageDecoder : public ImageDecoder { + public: + JPEGImageDecoder(); + ~JPEGImageDecoder(); -public: - static void cleanup() - { - if (s_self->isActive()) - s_self->fire(); + virtual String filenameExtension() const { return "jpg"; } - delete s_self; - s_self = 0; - } + // Take the data and store it. + virtual void setData(SharedBuffer* data, bool allDataReceived); - static SharedTimerQt* inst() - { - if (!s_self) { - s_self = new SharedTimerQt(); - qAddPostRoutine(SharedTimerQt::cleanup); - } + // Whether or not the size information has been decoded yet. + virtual bool isSizeAvailable() const; - return s_self; - } + virtual RGBA32Buffer* frameBufferAtIndex(size_t index); + + virtual bool supportsAlpha() const { return false; } - void (*m_timerFunction)(); + void decode(bool sizeOnly = false) const; -public Q_SLOTS: - void fire() - { - if (m_timerFunction) - (m_timerFunction)(); - } + JPEGImageReader* reader() { return m_reader; } -private: - static SharedTimerQt* s_self; -}; + bool outputScanlines(); + void jpegComplete(); -} + private: + friend class JPEGImageReader; + mutable JPEGImageReader* m_reader; + }; -#endif +} // namespace WebCore -// vim: ts=4 sw=4 et +#endif diff --git a/WebCore/platform/image-decoders/skia/PNGImageDecoder.cpp b/WebCore/platform/image-decoders/skia/PNGImageDecoder.cpp new file mode 100644 index 0000000..ec1ebbe --- /dev/null +++ b/WebCore/platform/image-decoders/skia/PNGImageDecoder.cpp @@ -0,0 +1,412 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2008, 2009 Google, Inc. + * + * Portions are Copyright (C) 2001 mozilla.org + * + * Other contributors: + * Stuart Parmenter <stuart@mozilla.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 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 + * + * Alternatively, the contents of this file may be used under the terms + * of either the Mozilla Public License Version 1.1, found at + * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public + * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html + * (the "GPL"), in which case the provisions of the MPL or the GPL are + * applicable instead of those above. If you wish to allow use of your + * version of this file only under the terms of one of those two + * licenses (the MPL or the GPL) and not to allow others to use your + * version of this file under the LGPL, indicate your decision by + * deletingthe provisions above and replace them with the notice and + * other provisions required by the MPL or the GPL, as the case may be. + * If you do not delete the provisions above, a recipient may use your + * version of this file under any of the LGPL, the MPL or the GPL. + */ + +#include "config.h" +#include "PNGImageDecoder.h" +#include "png.h" +#include "assert.h" + +namespace WebCore { + +// Gamma constants. +const double cMaxGamma = 21474.83; +const double cDefaultGamma = 2.2; +const double cInverseGamma = 0.45455; + +// Protect against large PNGs. See Mozilla's bug #251381 for more info. +const unsigned long cMaxPNGSize = 1000000UL; + +// Called if the decoding of the image fails. +static void PNGAPI decodingFailed(png_structp png_ptr, png_const_charp error_msg); + +// Callbacks given to the read struct. The first is for warnings (we want to treat a particular warning +// as an error, which is why we have to register this callback. +static void PNGAPI decodingWarning(png_structp png_ptr, png_const_charp warning_msg); + +// Called when we have obtained the header information (including the size). +static void PNGAPI headerAvailable(png_structp png_ptr, png_infop info_ptr); + +// Called when a row is ready. +static void PNGAPI rowAvailable(png_structp png_ptr, png_bytep new_row, + png_uint_32 row_num, int pass); + +// Called when we have completely finished decoding the image. +static void PNGAPI pngComplete(png_structp png_ptr, png_infop info_ptr); + +class PNGImageReader +{ +public: + PNGImageReader(PNGImageDecoder* decoder) + : m_readOffset(0), m_decodingSizeOnly(false), m_interlaceBuffer(0), m_hasAlpha(0) + { + m_png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, decodingFailed, decodingWarning); + m_info = png_create_info_struct(m_png); + png_set_progressive_read_fn(m_png, decoder, headerAvailable, rowAvailable, pngComplete); + } + + ~PNGImageReader() + { + close(); + } + + void close() { + if (m_png && m_info) + png_destroy_read_struct(&m_png, &m_info, 0); // Will zero the pointers. + delete []m_interlaceBuffer; + m_interlaceBuffer = 0; + m_readOffset = 0; + } + + void decode(const Vector<char>& data, bool sizeOnly) + { + m_decodingSizeOnly = sizeOnly; + + // We need to do the setjmp here. Otherwise bad things will happen + if (setjmp(m_png->jmpbuf)) { + close(); + return; + } + + // Go ahead and assume we consumed all the data. If we consume less, the + // callback will adjust our read offset accordingly. Do not attempt to adjust the + // offset after png_process_data returns. + unsigned offset = m_readOffset; + unsigned remaining = data.size() - m_readOffset; + m_readOffset = data.size(); + png_process_data(m_png, m_info, (png_bytep)(data.data()) + offset, remaining); + } + + bool decodingSizeOnly() const { return m_decodingSizeOnly; } + png_structp pngPtr() const { return m_png; } + png_infop infoPtr() const { return m_info; } + png_bytep interlaceBuffer() const { return m_interlaceBuffer; } + bool hasAlpha() const { return m_hasAlpha; } + + void setReadOffset(unsigned offset) { m_readOffset = offset; } + void setHasAlpha(bool b) { m_hasAlpha = b; } + + void createInterlaceBuffer(int size) { + m_interlaceBuffer = new png_byte[size]; + } + +private: + unsigned m_readOffset; + bool m_decodingSizeOnly; + png_structp m_png; + png_infop m_info; + png_bytep m_interlaceBuffer; + bool m_hasAlpha; +}; + +PNGImageDecoder::PNGImageDecoder() +: m_reader(0) +{} + +PNGImageDecoder::~PNGImageDecoder() +{ + delete m_reader; +} + +// Take the data and store it. +void PNGImageDecoder::setData(SharedBuffer* data, bool allDataReceived) +{ + if (m_failed) + return; + + // Cache our new data. + ImageDecoder::setData(data, allDataReceived); + + // Create the PNG reader. + if (!m_reader && !m_failed) + m_reader = new PNGImageReader(this); +} + +// Whether or not the size information has been decoded yet. +bool PNGImageDecoder::isSizeAvailable() const +{ + // If we have pending data to decode, send it to the PNG reader now. + if (!ImageDecoder::isSizeAvailable() && m_reader) { + if (m_failed) + return false; + + // The decoder will go ahead and aggressively consume everything up until the + // size is encountered. + decode(true); + } + + return !m_failed && ImageDecoder::isSizeAvailable(); +} + +RGBA32Buffer* PNGImageDecoder::frameBufferAtIndex(size_t index) +{ + if (index) + return 0; + + if (m_frameBufferCache.isEmpty()) + m_frameBufferCache.resize(1); + + RGBA32Buffer& frame = m_frameBufferCache[0]; + if (frame.status() != RGBA32Buffer::FrameComplete && m_reader) + // Decode this frame. + decode(); + return &frame; +} + +// Feed data to the PNG reader. +void PNGImageDecoder::decode(bool sizeOnly) const +{ + if (m_failed) + return; + + m_reader->decode(m_data->buffer(), sizeOnly); + + if (m_failed || (!m_frameBufferCache.isEmpty() && m_frameBufferCache[0].status() == RGBA32Buffer::FrameComplete)) { + delete m_reader; + m_reader = 0; + } +} + +void decodingFailed(png_structp png, png_const_charp errorMsg) +{ + static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->decodingFailed(); + longjmp(png->jmpbuf, 1); +} + +void decodingWarning(png_structp png, png_const_charp warningMsg) +{ + // Mozilla did this, so we will too. + // Convert a tRNS warning to be an error (documented in bugzilla.mozilla.org bug #251381) + if (!strncmp(warningMsg, "Missing PLTE before tRNS", 24)) + png_error(png, warningMsg); +} + +void headerAvailable(png_structp png, png_infop info) +{ + static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->headerAvailable(); +} + +void PNGImageDecoder::decodingFailed() { + m_failed = true; +} + +void PNGImageDecoder::headerAvailable() +{ + png_structp png = reader()->pngPtr(); + png_infop info = reader()->infoPtr(); + png_uint_32 width = png->width; + png_uint_32 height = png->height; + + // Protect against large images. + if (png->width > cMaxPNGSize || png->height > cMaxPNGSize) { + m_failed = true; + longjmp(png->jmpbuf, 1); + return; + } + + // We can fill in the size now that the header is available. + if (!ImageDecoder::isSizeAvailable()) { + if (!setSize(width, height)) { + // Size unreasonable, bail out. + longjmp(png->jmpbuf, 1); + return; + } + } + + int bitDepth, colorType, interlaceType, compressionType, filterType, channels; + png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType, + &interlaceType, &compressionType, &filterType); + + // The options we set here match what Mozilla does. + + // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA. + if (colorType == PNG_COLOR_TYPE_PALETTE || + (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)) + png_set_expand(png); + + png_bytep trns = 0; + int trnsCount = 0; + if (png_get_valid(png, info, PNG_INFO_tRNS)) { + png_get_tRNS(png, info, &trns, &trnsCount, 0); + png_set_expand(png); + } + + if (bitDepth == 16) + png_set_strip_16(png); + + if (colorType == PNG_COLOR_TYPE_GRAY || + colorType == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png); + + // Deal with gamma and keep it under our control. + double gamma; + if (png_get_gAMA(png, info, &gamma)) { + if ((gamma <= 0.0) || (gamma > cMaxGamma)) { + gamma = cInverseGamma; + png_set_gAMA(png, info, gamma); + } + png_set_gamma(png, cDefaultGamma, gamma); + } + else + png_set_gamma(png, cDefaultGamma, cInverseGamma); + + // Tell libpng to send us rows for interlaced pngs. + if (interlaceType == PNG_INTERLACE_ADAM7) + png_set_interlace_handling(png); + + // Update our info now + png_read_update_info(png, info); + channels = png_get_channels(png, info); + assert(channels == 3 || channels == 4); + + reader()->setHasAlpha(channels == 4); + + if (reader()->decodingSizeOnly()) { + // If we only needed the size, halt the reader. + reader()->setReadOffset(m_data->size() - png->buffer_size); + png->buffer_size = 0; + } +} + +void rowAvailable(png_structp png, png_bytep rowBuffer, + png_uint_32 rowIndex, int interlacePass) +{ + static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->rowAvailable( + rowBuffer, rowIndex, interlacePass); +} + +void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, int interlacePass) +{ + if (m_frameBufferCache.isEmpty()) + return; + + // Resize to the width and height of the image. + RGBA32Buffer& buffer = m_frameBufferCache[0]; + if (buffer.status() == RGBA32Buffer::FrameEmpty) { + // Let's resize our buffer now to the correct width/height. + if (!buffer.setSize(size().width(), size().height())) { + // Error allocating the bitmap. We should not continue. + static_cast<PNGImageDecoder*>(png_get_progressive_ptr(reader()->pngPtr()))->decodingFailed(); + longjmp(reader()->pngPtr()->jmpbuf, 1); + return; + } + + // Update our status to be partially complete. + buffer.setStatus(RGBA32Buffer::FramePartial); + + // For PNGs, the frame always fills the entire image. + buffer.setRect(IntRect(0, 0, size().width(), size().height())); + + if (reader()->pngPtr()->interlaced) + reader()->createInterlaceBuffer((reader()->hasAlpha() ? 4 : 3) * size().width() * size().height()); + } + + if (rowBuffer == 0) + return; + + /* libpng comments (pasted in here to explain what follows) + * + * this function is called for every row in the image. If the + * image is interlacing, and you turned on the interlace handler, + * this function will be called for every row in every pass. + * Some of these rows will not be changed from the previous pass. + * When the row is not changed, the new_row variable will be NULL. + * The rows and passes are called in order, so you don't really + * need the row_num and pass, but I'm supplying them because it + * may make your life easier. + * + * For the non-NULL rows of interlaced images, you must call + * png_progressive_combine_row() passing in the row and the + * old row. You can call this function for NULL rows (it will + * just return) and for non-interlaced images (it just does the + * memcpy for you) if it will make the code easier. Thus, you + * can just do this for all cases: + * + * png_progressive_combine_row(png_ptr, old_row, new_row); + * + * where old_row is what was displayed for previous rows. Note + * that the first pass (pass == 0 really) will completely cover + * the old row, so the rows do not have to be initialized. After + * the first pass (and only for interlaced images), you will have + * 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; + png_bytep row; + png_bytep interlaceBuffer = reader()->interlaceBuffer(); + if (interlaceBuffer) { + row = interlaceBuffer + (rowIndex * colorChannels * size().width()); + png_progressive_combine_row(png, row, rowBuffer); + } + else + row = rowBuffer; + + // Copy the data into our buffer. + int width = size().width(); + bool sawAlpha = false; + for (int x = 0; x < width; x++) { + unsigned red = *row++; + unsigned green = *row++; + unsigned blue = *row++; + unsigned alpha = (hasAlpha ? *row++ : 255); + buffer.setRGBA(x, rowIndex, red, green, blue, alpha); + if (!sawAlpha && alpha < 255) { + sawAlpha = true; + buffer.setHasAlpha(true); + } + } +} + +void pngComplete(png_structp png, png_infop info) +{ + static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->pngComplete(); +} + +void PNGImageDecoder::pngComplete() +{ + if (m_frameBufferCache.isEmpty()) + return; + + // Hand back an appropriately sized buffer, even if the image ended up being empty. + RGBA32Buffer& buffer = m_frameBufferCache[0]; + buffer.setStatus(RGBA32Buffer::FrameComplete); +} + +} // namespace WebCore diff --git a/WebCore/platform/image-decoders/skia/PNGImageDecoder.h b/WebCore/platform/image-decoders/skia/PNGImageDecoder.h new file mode 100644 index 0000000..83cf343 --- /dev/null +++ b/WebCore/platform/image-decoders/skia/PNGImageDecoder.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008, 2009 Google, 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. + */ + +#ifndef PNGImageDecoder_h +#define PNGImageDecoder_h + +#include "ImageDecoder.h" + +namespace WebCore { + + class PNGImageReader; + + // This class decodes the PNG image format. + class PNGImageDecoder : public ImageDecoder { + public: + PNGImageDecoder(); + ~PNGImageDecoder(); + + virtual String filenameExtension() const { return "png"; } + + // Take the data and store it. + virtual void setData(SharedBuffer* data, bool allDataReceived); + + // Whether or not the size information has been decoded yet. + virtual bool isSizeAvailable() const; + + virtual RGBA32Buffer* frameBufferAtIndex(size_t index); + + void decode(bool sizeOnly = false) const; + + PNGImageReader* reader() { return m_reader; } + + // Callbacks from libpng + void decodingFailed(); + void headerAvailable(); + void rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, int interlacePass); + void pngComplete(); + + private: + mutable PNGImageReader* m_reader; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/image-decoders/skia/XBMImageDecoder.cpp b/WebCore/platform/image-decoders/skia/XBMImageDecoder.cpp new file mode 100644 index 0000000..8908504 --- /dev/null +++ b/WebCore/platform/image-decoders/skia/XBMImageDecoder.cpp @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2008, 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 "XBMImageDecoder.h" + +#include <algorithm> + +namespace WebCore { + +XBMImageDecoder::XBMImageDecoder() + : m_decodeOffset(0) + , m_allDataReceived(false) + , m_decodedHeader(false) + , m_dataType(Unknown) + , m_bitsDecoded(0) +{ +} + +void XBMImageDecoder::setData(SharedBuffer* data, bool allDataReceived) +{ + ImageDecoder::setData(data, allDataReceived); + + const Vector<char>& buf = m_data->buffer(); + if (buf.size() > m_xbmString.size()) + m_xbmString.append(&buf[m_xbmString.size()], buf.size() - m_xbmString.size()); + + m_allDataReceived = allDataReceived; +} + +bool XBMImageDecoder::isSizeAvailable() const +{ + // This method should either (a) not be const, or (b) not be expected to + // do anything that changes m_sizeAvailable. The png and jpeg decoders + // get around this with callbacks from external libraries. + // + // FIXME: Find out if we can patch webkit to take care of this. + if (!ImageDecoder::isSizeAvailable() && !m_failed) + const_cast<XBMImageDecoder*>(this)->decodeXBM(true); + + return !m_failed && ImageDecoder::isSizeAvailable(); +} + +RGBA32Buffer* XBMImageDecoder::frameBufferAtIndex(size_t index) +{ + // Allocate a framebuffer if necessary. New framebuffers have their status + // initialized to RGBA32Buffer::FrameEmpty. + if (m_frameBufferCache.isEmpty()) + m_frameBufferCache.resize(1); + + RGBA32Buffer& frame = m_frameBufferCache[0]; + + // Attempt to get the size if we don't have it yet. + if (!ImageDecoder::isSizeAvailable()) + decodeXBM(true); + + // Size the framebuffer once we know the right size. + if (ImageDecoder::isSizeAvailable() && + frame.status() == RGBA32Buffer::FrameEmpty) { + if (!frame.setSize(size().width(), size().height())) { + m_failed = true; + frame.setStatus(RGBA32Buffer::FrameComplete); + return 0; + } + frame.setStatus(RGBA32Buffer::FramePartial); + } + + // Keep trying to decode until we've got the entire image. + if (frame.status() != RGBA32Buffer::FrameComplete) + decodeXBM(false); + + return &frame; +} + +bool XBMImageDecoder::decodeHeader() +{ + ASSERT(m_decodeOffset <= m_xbmString.size()); + ASSERT(!m_decodedHeader); + + const char* input = m_xbmString.c_str(); + + // At least 2 "#define <string> <unsigned>" sequences are required. These + // specify the width and height of the image. + int width, height; + if (!ImageDecoder::isSizeAvailable()) { + int count; + if (sscanf(&input[m_decodeOffset], "#define %*s %i #define %*s %i%n", + &width, &height, &count) != 2) + return false; + + // The width and height need to follow some rules. + if (width < 0 || width > maxDimension || height < 0 || height > maxDimension) { + // If this happens, decoding should not continue. + setFailed(); + return false; + } + + if (!setSize(width, height)) { + setFailed(); + return false; + } + m_decodeOffset += count; + ASSERT(m_decodeOffset <= m_xbmString.size()); + } + + ASSERT(ImageDecoder::isSizeAvailable()); + + // Now we're looking for something that tells us that we've seen all of the + // "#define <string> <unsigned>" sequences that we're going to. Mozilla + // just looks for " char " or " short ". We'll do the same. + if (m_dataType == Unknown) { + const char* x11hint = " char "; + const char* x11HintLocation = strstr(&input[m_decodeOffset], x11hint); + if (x11HintLocation) { + m_dataType = X11; + m_decodeOffset += ((x11HintLocation - &input[m_decodeOffset]) + strlen(x11hint)); + } else { + const char* x10hint = " short "; + const char* x10HintLocation = strstr(&input[m_decodeOffset], x10hint); + if (x10HintLocation) { + m_dataType = X10; + m_decodeOffset += ((x10HintLocation - &input[m_decodeOffset]) + strlen(x10hint)); + } else + return false; + } + ASSERT(m_decodeOffset <= m_xbmString.size()); + } + + // Find the start of the data. Again, we do what mozilla does and just + // look for a '{' in the input. + const char* found = strchr(&input[m_decodeOffset], '{'); + if (!found) + return false; + + // Advance to character after the '{' + m_decodeOffset += ((found - &input[m_decodeOffset]) + 1); + ASSERT(m_decodeOffset <= m_xbmString.size()); + m_decodedHeader = true; + + return true; +} + +// The data in an XBM file is provided as an array of either "char" or "short" +// values. These values are decoded one at a time using strtoul() and the bits +// are used to set the alpha value for the image. +// +// The value for the color is always set to RGB(0,0,0), the alpha value takes +// care of whether or not the pixel shows up. +// +// Since the data may arrive in chunks, and many prefixes of valid numbers are +// themselves valid numbers, this code needs to check to make sure that the +// value is not truncated. This is done by consuming space after the value +// read until a ',' or a '}' occurs. In a valid XBM, one of these characters +// will occur after each value. +// +// The checks after strtoul are based on Mozilla's nsXBMDecoder.cpp. +bool XBMImageDecoder::decodeDatum(uint16_t* result) +{ + const char* input = m_xbmString.c_str(); + char* endPtr; + const uint16_t value = strtoul(&input[m_decodeOffset], &endPtr, 0); + + // End of input or couldn't decode anything, can't go any further. + if (endPtr == &input[m_decodeOffset] || !*endPtr) + return false; + + // Possibly a hex value truncated at "0x". Need more data. + if (value == 0 && (*endPtr == 'x' || *endPtr == 'X')) + return false; + + // Skip whitespace + while (*endPtr && isspace(*endPtr)) + ++endPtr; + + // Out of input, don't know what comes next. + if (!*endPtr) + return false; + + // If the next non-whitespace character is not one of these, it's an error. + // Every valid entry in the data array needs to be followed by ',' or '}'. + if (*endPtr != ',' && *endPtr != '}') { + setFailed(); + return false; + } + + // At this point we have a value. + *result = value; + + // Skip over the decoded value plus the delimiter (',' or '}'). + m_decodeOffset += ((endPtr - &input[m_decodeOffset]) + 1); + ASSERT(m_decodeOffset <= m_xbmString.size()); + + return true; +} + +bool XBMImageDecoder::decodeData() +{ + ASSERT(m_decodeOffset <= m_xbmString.size()); + ASSERT(m_decodedHeader && !m_frameBufferCache.isEmpty()); + + RGBA32Buffer& frame = m_frameBufferCache[0]; + + ASSERT(frame.status() == RGBA32Buffer::FramePartial); + + const int bitsPerRow = size().width(); + + ASSERT(m_dataType != Unknown); + + while (m_bitsDecoded < (size().width() * size().height())) { + uint16_t value; + if (!decodeDatum(&value)) + return false; + + int x = m_bitsDecoded % bitsPerRow; + const int y = m_bitsDecoded / bitsPerRow; + + // How many bits will be written? + const int bits = std::min(bitsPerRow - x, (m_dataType == X11) ? 8 : 16); + + // Only the alpha channel matters here, so the color values are always + // set to 0. + for (int i = 0; i < bits; ++i) + frame.setRGBA(x++, y, 0, 0, 0, value & (1 << i) ? 255 : 0); + + m_bitsDecoded += bits; + } + + frame.setStatus(RGBA32Buffer::FrameComplete); + + return true; +} + +// Decode as much as we can of the XBM file. +void XBMImageDecoder::decodeXBM(bool sizeOnly) +{ + if (failed()) + return; + + bool decodeResult = false; + + if (!m_decodedHeader) + decodeResult = decodeHeader(); + + if (m_decodedHeader && !sizeOnly) + decodeResult = decodeData(); + + // The header or the data could not be decoded, but there is no more + // data: decoding has failed. + if (!decodeResult && m_allDataReceived) + setFailed(); +} + +} // namespace WebCore diff --git a/WebCore/platform/image-decoders/skia/XBMImageDecoder.h b/WebCore/platform/image-decoders/skia/XBMImageDecoder.h new file mode 100644 index 0000000..44c6be2 --- /dev/null +++ b/WebCore/platform/image-decoders/skia/XBMImageDecoder.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2008, 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 XBMImageDecoder_h +#define XBMImageDecoder_h + +#include "config.h" +#include <string> +#include "ImageDecoder.h" + +namespace WebCore { + + // This class decodes the XBM image format. + class XBMImageDecoder : public ImageDecoder { + public: + XBMImageDecoder(); + virtual ~XBMImageDecoder() {} + + virtual String filenameExtension() const { return "xbm"; } + + virtual void setData(SharedBuffer* data, bool allDataReceived); + // Whether or not the size information has been decoded yet. + virtual bool isSizeAvailable() const; + virtual RGBA32Buffer* frameBufferAtIndex(size_t index); + + private: + // Restricts image size to something "reasonable". + // This protects agains ridiculously large XBMs and prevents bad things + // like overflow of m_bitsDecoded. + static const int maxDimension = 65535; + + // In X10, an array of type "short" is used to declare the image bits, + // but in X11, the type is "char". + enum DataType { + Unknown, + X10, + X11, + }; + + bool decodeHeader(); + bool decodeDatum(uint16_t* result); + bool decodeData(); + void decodeXBM(bool sizeOnly); + + std::string m_xbmString; // Null-terminated copy of the XBM data. + size_t m_decodeOffset; // The current offset in m_xbmString for decoding. + bool m_allDataReceived; + bool m_decodedHeader; + enum DataType m_dataType; + int m_bitsDecoded; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/image-decoders/xbm/XBMImageDecoder.h b/WebCore/platform/image-decoders/xbm/XBMImageDecoder.h index 7c693f4..dc6d8d4 100644 --- a/WebCore/platform/image-decoders/xbm/XBMImageDecoder.h +++ b/WebCore/platform/image-decoders/xbm/XBMImageDecoder.h @@ -36,6 +36,8 @@ class XBMImageReader; class XBMImageDecoder : public ImageDecoder { public: + virtual String filenameExtension() const { return "xbm"; } + // Whether or not the size information has been decoded yet. virtual bool isSizeAvailable() const; diff --git a/WebCore/platform/mac/ClipboardMac.mm b/WebCore/platform/mac/ClipboardMac.mm index 8117b2b..cfa334b 100644 --- a/WebCore/platform/mac/ClipboardMac.mm +++ b/WebCore/platform/mac/ClipboardMac.mm @@ -36,6 +36,7 @@ #import "Page.h" #import "Pasteboard.h" #import "RenderImage.h" +#import "SecurityOrigin.h" #import "WebCoreSystemInterface.h" namespace WebCore { @@ -211,7 +212,7 @@ bool ClipboardMac::setData(const String &type, const String &data) NSURL *url = [[NSURL alloc] initWithString:cocoaData]; [url writeToPasteboard:m_pasteboard.get()]; - if ([url isFileURL]) { + if ([url isFileURL] && m_frame->document()->securityOrigin()->canLoadLocalResources()) { [m_pasteboard.get() addTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:nil]; NSArray *fileList = [NSArray arrayWithObject:[url path]]; [m_pasteboard.get() setPropertyList:fileList forType:NSFilenamesPboardType]; diff --git a/WebCore/platform/mac/CookieJar.mm b/WebCore/platform/mac/CookieJar.mm index 5fe7a63..94b7d77 100644 --- a/WebCore/platform/mac/CookieJar.mm +++ b/WebCore/platform/mac/CookieJar.mm @@ -34,53 +34,77 @@ typedef unsigned NSUInteger; #endif +@interface NSHTTPCookie (WebCoreHTTPOnlyCookies) +- (BOOL)isHTTPOnly; +@end + namespace WebCore { -String cookies(const Document* /*document*/, const KURL& url) +static bool isHTTPOnly(NSHTTPCookie *cookie) { - BEGIN_BLOCK_OBJC_EXCEPTIONS; + // Once we require a newer version of Foundation with the isHTTPOnly method, + // we can eliminate the instancesRespondToSelector: check. + static bool supportsHTTPOnlyCookies = [NSHTTPCookie instancesRespondToSelector:@selector(isHTTPOnly)]; + return supportsHTTPOnlyCookies && [cookie isHTTPOnly]; +} - NSURL *cookieURL = url; - NSArray *cookiesForURL = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:cookieURL]; +static RetainPtr<NSArray> filterCookies(NSArray *unfilteredCookies) +{ + NSUInteger count = [unfilteredCookies count]; + RetainPtr<NSMutableArray> filteredCookies(AdoptNS, [[NSMutableArray alloc] initWithCapacity:count]); - // <rdar://problem/5632883> On 10.5, NSHTTPCookieStorage would happily store an empty cookie, which would be sent as "Cookie: =". - // We have a workaround in setCookies() to prevent that, but we also need to avoid sending cookies that were previously stored. - NSUInteger count = [cookiesForURL count]; - RetainPtr<NSMutableArray> cookiesForURLFilteredCopy(AdoptNS, [[NSMutableArray alloc] initWithCapacity:count]); for (NSUInteger i = 0; i < count; ++i) { - NSHTTPCookie *cookie = (NSHTTPCookie *)[cookiesForURL objectAtIndex:i]; - if ([[cookie name] length] != 0) - [cookiesForURLFilteredCopy.get() addObject:cookie]; + NSHTTPCookie *cookie = (NSHTTPCookie *)[unfilteredCookies objectAtIndex:i]; + + // <rdar://problem/5632883> On 10.5, NSHTTPCookieStorage would store an empty cookie, + // which would be sent as "Cookie: =". We have a workaround in setCookies() to prevent + // that, but we also need to avoid sending cookies that were previously stored, and + // there's no harm to doing this check because such a cookie is never valid. + if (![[cookie name] length]) + continue; + + if (isHTTPOnly(cookie)) + continue; + + [filteredCookies.get() addObject:cookie]; } - NSDictionary *header = [NSHTTPCookie requestHeaderFieldsWithCookies:cookiesForURLFilteredCopy.get()]; - return [header objectForKey:@"Cookie"]; + return filteredCookies; +} + +String cookies(const Document*, const KURL& url) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + + NSURL *cookieURL = url; + NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:cookieURL]; + return [[NSHTTPCookie requestHeaderFieldsWithCookies:filterCookies(cookies).get()] objectForKey:@"Cookie"]; END_BLOCK_OBJC_EXCEPTIONS; return String(); } -void setCookies(Document* /*document*/, const KURL& url, const KURL& policyBaseURL, const String& cookieStr) +void setCookies(Document*, const KURL& url, const KURL& policyBaseURL, const String& cookieStr) { BEGIN_BLOCK_OBJC_EXCEPTIONS; - // <rdar://problem/5632883> On 10.5, NSHTTPCookieStorage would happily store an empty cookie, which would be sent as "Cookie: =". + // <rdar://problem/5632883> On 10.5, NSHTTPCookieStorage would store an empty cookie, + // which would be sent as "Cookie: =". if (cookieStr.isEmpty()) return; - NSURL *cookieURL = url; - // <http://bugs.webkit.org/show_bug.cgi?id=6531>, <rdar://4409034> // cookiesWithResponseHeaderFields doesn't parse cookies without a value String cookieString = cookieStr.contains('=') ? cookieStr : cookieStr + "="; - + + NSURL *cookieURL = url; NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:[NSDictionary dictionaryWithObject:cookieString forKey:@"Set-Cookie"] forURL:cookieURL]; - [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:cookies forURL:cookieURL mainDocumentURL:policyBaseURL]; + [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:filterCookies(cookies).get() forURL:cookieURL mainDocumentURL:policyBaseURL]; END_BLOCK_OBJC_EXCEPTIONS; } -bool cookiesEnabled(const Document* /*document*/) +bool cookiesEnabled(const Document*) { BEGIN_BLOCK_OBJC_EXCEPTIONS; diff --git a/WebCore/platform/mac/CursorMac.mm b/WebCore/platform/mac/CursorMac.mm index b07964b..c28f149 100644 --- a/WebCore/platform/mac/CursorMac.mm +++ b/WebCore/platform/mac/CursorMac.mm @@ -30,6 +30,7 @@ #import "FoundationExtras.h" #import "Image.h" #import "IntPoint.h" +#import <wtf/StdLibExtras.h> @interface WebCoreCursorBundle : NSObject { } @end @@ -72,7 +73,7 @@ static NSCursor* leakNamedCursor(const char* name, int x, int y) } return cursor; END_BLOCK_OBJC_EXCEPTIONS; - return 0; + return nil; } Cursor::Cursor(Image* image, const IntPoint& hotspot) @@ -105,193 +106,193 @@ Cursor::Cursor(NSCursor* c) const Cursor& pointerCursor() { - static Cursor c = [NSCursor arrowCursor]; + DEFINE_STATIC_LOCAL(Cursor, c, ([NSCursor arrowCursor])); return c; } const Cursor& crossCursor() { - static Cursor c = leakNamedCursor("crossHairCursor", 11, 11); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("crossHairCursor", 11, 11))); return c; } const Cursor& handCursor() { - static Cursor c = leakNamedCursor("linkCursor", 6, 1); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("linkCursor", 6, 1))); return c; } const Cursor& moveCursor() { - static Cursor c = leakNamedCursor("moveCursor", 7, 7); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("moveCursor", 7, 7))); return c; } const Cursor& verticalTextCursor() { - static Cursor c = leakNamedCursor("verticalTextCursor", 7, 7); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("verticalTextCursor", 7, 7))); return c; } const Cursor& cellCursor() { - static Cursor c = leakNamedCursor("cellCursor", 7, 7); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("cellCursor", 7, 7))); return c; } const Cursor& contextMenuCursor() { - static Cursor c = leakNamedCursor("contextMenuCursor", 3, 2); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("contextMenuCursor", 3, 2))); return c; } const Cursor& aliasCursor() { - static Cursor c = leakNamedCursor("aliasCursor", 11, 3); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("aliasCursor", 11, 3))); return c; } const Cursor& zoomInCursor() { - static Cursor c = leakNamedCursor("zoomInCursor", 7, 7); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("zoomInCursor", 7, 7))); return c; } const Cursor& zoomOutCursor() { - static Cursor c = leakNamedCursor("zoomOutCursor", 7, 7); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("zoomOutCursor", 7, 7))); return c; } const Cursor& copyCursor() { - static Cursor c = leakNamedCursor("copyCursor", 3, 2); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("copyCursor", 3, 2))); return c; } const Cursor& noneCursor() { - static Cursor c = leakNamedCursor("noneCursor", 7, 7); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("noneCursor", 7, 7))); return c; } const Cursor& progressCursor() { - static Cursor c = leakNamedCursor("progressCursor", 3, 2); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("progressCursor", 3, 2))); return c; } const Cursor& noDropCursor() { - static Cursor c = leakNamedCursor("noDropCursor", 3, 1); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("noDropCursor", 3, 1))); return c; } const Cursor& notAllowedCursor() { - static Cursor c = leakNamedCursor("notAllowedCursor", 11, 11); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("notAllowedCursor", 11, 11))); return c; } const Cursor& iBeamCursor() { - static Cursor c = [NSCursor IBeamCursor]; + DEFINE_STATIC_LOCAL(Cursor, c, ([NSCursor IBeamCursor])); return c; } const Cursor& waitCursor() { - static Cursor c = leakNamedCursor("waitCursor", 7, 7); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("waitCursor", 7, 7))); return c; } const Cursor& helpCursor() { - static Cursor c = leakNamedCursor("helpCursor", 8, 8); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("helpCursor", 8, 8))); return c; } const Cursor& eastResizeCursor() { - static Cursor c = leakNamedCursor("eastResizeCursor", 14, 7); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("eastResizeCursor", 14, 7))); return c; } const Cursor& northResizeCursor() { - static Cursor c = leakNamedCursor("northResizeCursor", 7, 1); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("northResizeCursor", 7, 1))); return c; } const Cursor& northEastResizeCursor() { - static Cursor c = leakNamedCursor("northEastResizeCursor", 14, 1); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("northEastResizeCursor", 14, 1))); return c; } const Cursor& northWestResizeCursor() { - static Cursor c = leakNamedCursor("northWestResizeCursor", 0, 0); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("northWestResizeCursor", 0, 0))); return c; } const Cursor& southResizeCursor() { - static Cursor c = leakNamedCursor("southResizeCursor", 7, 14); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("southResizeCursor", 7, 14))); return c; } const Cursor& southEastResizeCursor() { - static Cursor c = leakNamedCursor("southEastResizeCursor", 14, 14); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("southEastResizeCursor", 14, 14))); return c; } const Cursor& southWestResizeCursor() { - static Cursor c = leakNamedCursor("southWestResizeCursor", 1, 14); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("southWestResizeCursor", 1, 14))); return c; } const Cursor& westResizeCursor() { - static Cursor c = leakNamedCursor("westResizeCursor", 1, 7); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("westResizeCursor", 1, 7))); return c; } const Cursor& northSouthResizeCursor() { - static Cursor c = leakNamedCursor("northSouthResizeCursor", 7, 7); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("northSouthResizeCursor", 7, 7))); return c; } const Cursor& eastWestResizeCursor() { - static Cursor c = leakNamedCursor("eastWestResizeCursor", 7, 7); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("eastWestResizeCursor", 7, 7))); return c; } const Cursor& northEastSouthWestResizeCursor() { - static Cursor c = leakNamedCursor("northEastSouthWestResizeCursor", 7, 7); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("northEastSouthWestResizeCursor", 7, 7))); return c; } const Cursor& northWestSouthEastResizeCursor() { - static Cursor c = leakNamedCursor("northWestSouthEastResizeCursor", 7, 7); + DEFINE_STATIC_LOCAL(Cursor, c, (leakNamedCursor("northWestSouthEastResizeCursor", 7, 7))); return c; } const Cursor& columnResizeCursor() { - static Cursor c = [NSCursor resizeLeftRightCursor]; + DEFINE_STATIC_LOCAL(Cursor, c, ([NSCursor resizeLeftRightCursor])); return c; } const Cursor& rowResizeCursor() { - static Cursor c = [NSCursor resizeUpDownCursor]; + DEFINE_STATIC_LOCAL(Cursor, c, ([NSCursor resizeUpDownCursor])); return c; } @@ -342,13 +343,13 @@ const Cursor& westPanningCursor() const Cursor& grabCursor() { - static Cursor c = [NSCursor openHandCursor]; + DEFINE_STATIC_LOCAL(Cursor, c, ([NSCursor openHandCursor])); return c; } const Cursor& grabbingCursor() { - static Cursor c = [NSCursor closedHandCursor]; + DEFINE_STATIC_LOCAL(Cursor, c, ([NSCursor closedHandCursor])); return c; } diff --git a/WebCore/platform/mac/DragDataMac.mm b/WebCore/platform/mac/DragDataMac.mm index bd66787..5cf2e14 100644 --- a/WebCore/platform/mac/DragDataMac.mm +++ b/WebCore/platform/mac/DragDataMac.mm @@ -122,7 +122,7 @@ String DragData::asURL(String* title) const return m_pasteboardHelper->urlFromPasteboard([m_platformDragData draggingPasteboard], title); } -PassRefPtr<DocumentFragment> DragData::asFragment(Document* doc) const +PassRefPtr<DocumentFragment> DragData::asFragment(Document*) const { return [m_pasteboardHelper->fragmentFromPasteboard([m_platformDragData draggingPasteboard]) _documentFragment]; } diff --git a/WebCore/platform/mac/DragImageMac.mm b/WebCore/platform/mac/DragImageMac.mm index 098a548..842e6d4 100644 --- a/WebCore/platform/mac/DragImageMac.mm +++ b/WebCore/platform/mac/DragImageMac.mm @@ -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 @@ -22,31 +22,29 @@ * (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 "DragImage.h" #import "CachedImage.h" #import "Image.h" #import "KURL.h" -#import "PlatformString.h" #import "ResourceResponse.h" -#import <FoundationExtras.h> namespace WebCore { - - -IntSize dragImageSize(DragImageRef image) +IntSize dragImageSize(RetainPtr<NSImage> image) { return (IntSize)[image.get() size]; } -void deleteDragImage(DragImageRef image) +void deleteDragImage(RetainPtr<NSImage>) { - //DragImageRef is a RetainPtr, so we don't need to explicitly delete it + // Since this is a RetainPtr, there's nothing additional we need to do to + // delete it. It will be released when it falls out of scope. } -DragImageRef scaleDragImage(DragImageRef image, FloatSize scale) +RetainPtr<NSImage> scaleDragImage(RetainPtr<NSImage> image, FloatSize scale) { NSSize originalSize = [image.get() size]; NSSize newSize = NSMakeSize((originalSize.width * scale.width()), (originalSize.height * scale.height())); @@ -57,7 +55,7 @@ DragImageRef scaleDragImage(DragImageRef image, FloatSize scale) return image; } -DragImageRef dissolveDragImageToFraction(DragImageRef image, float delta) +RetainPtr<NSImage> dissolveDragImageToFraction(RetainPtr<NSImage> image, float delta) { RetainPtr<NSImage> dissolvedImage(AdoptNS, [[NSImage alloc] initWithSize:[image.get() size]]); @@ -77,14 +75,14 @@ DragImageRef dissolveDragImageToFraction(DragImageRef image, float delta) return image; } -DragImageRef createDragImageFromImage(Image* image) +RetainPtr<NSImage> createDragImageFromImage(Image* image) { - DragImageRef dragImage(AdoptNS, [image->getNSImage() copy]); + RetainPtr<NSImage> dragImage(AdoptNS, [image->getNSImage() copy]); [dragImage.get() setSize:(NSSize)(image->size())]; return dragImage; } -DragImageRef createDragImageIconForCachedImage(CachedImage* image) +RetainPtr<NSImage> createDragImageIconForCachedImage(CachedImage* image) { const String& filename = image->response().suggestedFilename(); NSString *extension = nil; @@ -92,12 +90,12 @@ DragImageRef createDragImageIconForCachedImage(CachedImage* image) if (dotIndex > 0 && dotIndex < (int)(filename.length() - 1)) // require that a . exists after the first character and before the last extension = filename.substring(dotIndex + 1); - else - //It might be worth doing a further look up to pull the extension from the mimetype + else { + // It might be worth doing a further lookup to pull the extension from the MIME type. extension = @""; + } - return DragImageRef([[NSWorkspace sharedWorkspace] iconForFileType:extension]); - + return [[NSWorkspace sharedWorkspace] iconForFileType:extension]; } } diff --git a/WebCore/platform/mac/LocalizedStringsMac.mm b/WebCore/platform/mac/LocalizedStringsMac.mm index d458778..d465758 100644 --- a/WebCore/platform/mac/LocalizedStringsMac.mm +++ b/WebCore/platform/mac/LocalizedStringsMac.mm @@ -401,6 +401,14 @@ String contextMenuItemTagWritingDirectionMenu() return String(); } +String contextMenuItemTagTextDirectionMenu() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS; + return [[WebCoreViewFactory sharedFactory] contextMenuItemTagTextDirectionMenu]; + END_BLOCK_OBJC_EXCEPTIONS; + return String(); +} + String contextMenuItemTagDefaultDirection() { BEGIN_BLOCK_OBJC_EXCEPTIONS; diff --git a/WebCore/platform/mac/MIMETypeRegistryMac.mm b/WebCore/platform/mac/MIMETypeRegistryMac.mm index c67b891..7d43505 100644 --- a/WebCore/platform/mac/MIMETypeRegistryMac.mm +++ b/WebCore/platform/mac/MIMETypeRegistryMac.mm @@ -31,16 +31,6 @@ namespace WebCore { -String getMIMETypeForUTI(const String & uti) -{ - CFStringRef utiref = uti.createCFString(); - CFStringRef mime = UTTypeCopyPreferredTagWithClass(utiref, kUTTagClassMIMEType); - String mimeType = mime; - if (mime) - CFRelease(mime); - CFRelease(utiref); - return mimeType; -} String MIMETypeRegistry::getMIMETypeForExtension(const String &ext) { diff --git a/WebCore/platform/mac/PasteboardMac.mm b/WebCore/platform/mac/PasteboardMac.mm index 4e15ad0..de369fc 100644 --- a/WebCore/platform/mac/PasteboardMac.mm +++ b/WebCore/platform/mac/PasteboardMac.mm @@ -44,7 +44,9 @@ #import "WebCoreNSStringExtras.h" #import "markup.h" +#import <wtf/StdLibExtras.h> #import <wtf/RetainPtr.h> +#import <wtf/UnusedParam.h> @interface NSAttributedString (AppKitSecretsIKnowAbout) - (id)_initWithDOMRange:(DOMRange *)domRange; @@ -78,27 +80,27 @@ static NSArray* selectionPasteboardTypes(bool canSmartCopyOrDelete, bool selecti static NSArray* writableTypesForURL() { - static RetainPtr<NSArray> types = nil; - if (!types) { - types = [[NSArray alloc] initWithObjects: + DEFINE_STATIC_LOCAL(RetainPtr<NSArray>, types, ([[NSArray alloc] initWithObjects: WebURLsWithTitlesPboardType, NSURLPboardType, WebURLPboardType, WebURLNamePboardType, NSStringPboardType, - nil]; - } + nil])); return types.get(); } +static inline NSArray* createWritableTypesForImage() +{ + NSMutableArray *types = [[NSMutableArray alloc] initWithObjects:NSTIFFPboardType, nil]; + [types addObjectsFromArray:writableTypesForURL()]; + [types addObject:NSRTFDPboardType]; + return types; +} + static NSArray* writableTypesForImage() { - static RetainPtr<NSMutableArray> types = nil; - if (!types) { - types = [[NSMutableArray alloc] initWithObjects:NSTIFFPboardType, nil]; - [types.get() addObjectsFromArray:writableTypesForURL()]; - [types.get() addObject:NSRTFDPboardType]; - } + DEFINE_STATIC_LOCAL(RetainPtr<NSArray>, types, (createWritableTypesForImage())); return types.get(); } @@ -121,7 +123,7 @@ void Pasteboard::clear() static NSAttributedString *stripAttachmentCharacters(NSAttributedString *string) { const unichar attachmentCharacter = NSAttachmentCharacter; - static RetainPtr<NSString> attachmentCharacterString = [NSString stringWithCharacters:&attachmentCharacter length:1]; + DEFINE_STATIC_LOCAL(RetainPtr<NSString>, attachmentCharacterString, ([NSString stringWithCharacters:&attachmentCharacter length:1])); NSMutableAttributedString *result = [[string mutableCopy] autorelease]; NSRange attachmentRange = [[result string] rangeOfString:attachmentCharacterString.get()]; while (attachmentRange.location != NSNotFound) { @@ -142,7 +144,8 @@ void Pasteboard::writeSelection(NSPasteboard* pasteboard, Range* selectedRange, // 4930197: Mail overrides [WebHTMLView pasteboardTypesForSelection] in order to add another type to the pasteboard // after WebKit does. On Tiger we must call this function so that Mail code will be executed, meaning that // we can't call WebCore::Pasteboard's method for setting types. - + UNUSED_PARAM(canSmartCopyOrDelete); + NSArray *types = frame->editor()->client()->pasteboardTypesForSelection(frame); // Don't write RTFD to the pasteboard when the copied attributed string has no attachments. NSMutableArray *mutableTypes = nil; @@ -181,8 +184,7 @@ void Pasteboard::writeSelection(NSPasteboard* pasteboard, Range* selectedRange, if ([types containsObject:NSStringPboardType]) { // Map to a plain old space because this is better for source code, other browsers do it, // and because HTML forces you to do this any time you want two spaces in a row. - String text = selectedRange->text(); - text.replace('\\', frame->backslashAsCurrencySymbol()); + String text = frame->displayStringModifiedByEncoding(selectedRange->text()); NSMutableString *s = [[[(NSString*)text copy] autorelease] mutableCopy]; NSString *NonBreakingSpaceString = [NSString stringWithCharacters:&noBreakSpace length:1]; @@ -246,8 +248,7 @@ void Pasteboard::writeURL(const KURL& url, const String& titleStr, Frame* frame) static NSFileWrapper* fileWrapperForImage(CachedResource* resource, NSURL *url) { SharedBuffer* coreData = resource->data(); - NSData *data = [[[NSData alloc] initWithBytes:coreData->platformData() - length:coreData->platformDataSize()] autorelease]; + NSData *data = [[[NSData alloc] initWithBytes:coreData->data() length:coreData->size()] autorelease]; NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:data] autorelease]; String coreMIMEType = resource->response().mimeType(); NSString *MIMEType = nil; diff --git a/WebCore/platform/mac/PlatformMouseEventMac.mm b/WebCore/platform/mac/PlatformMouseEventMac.mm index af7415d..8979124 100644 --- a/WebCore/platform/mac/PlatformMouseEventMac.mm +++ b/WebCore/platform/mac/PlatformMouseEventMac.mm @@ -116,25 +116,6 @@ IntPoint globalPointForEvent(NSEvent *event) } } -int eventNumberForEvent(NSEvent *event) -{ - switch ([event type]) { - case NSLeftMouseDown: - case NSLeftMouseUp: - case NSLeftMouseDragged: - case NSRightMouseDown: - case NSRightMouseUp: - case NSRightMouseDragged: - case NSOtherMouseDown: - case NSOtherMouseUp: - case NSOtherMouseDragged: - case NSMouseMoved: - return [event eventNumber]; - default: - return 0; - } -} - static MouseEventType mouseEventForNSEvent(NSEvent* event) { switch ([event type]) { diff --git a/WebCore/platform/mac/PurgeableBufferMac.cpp b/WebCore/platform/mac/PurgeableBufferMac.cpp new file mode 100644 index 0000000..1b49de0 --- /dev/null +++ b/WebCore/platform/mac/PurgeableBufferMac.cpp @@ -0,0 +1,164 @@ +/* + * 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" + +#ifndef BUILDING_ON_TIGER + +#include "PurgeableBuffer.h" + +#include <mach/mach.h> +#include <wtf/Assertions.h> + +namespace WebCore { + +static const size_t minPurgeableBufferSize = 4096; // one page + +PurgeableBuffer::PurgeableBuffer(char* data, size_t size) + : m_data(data) + , m_size(size) + , m_purgePriority(PurgeDefault) + , m_state(NonVolatile) +{ +} + +PurgeableBuffer::~PurgeableBuffer() +{ + vm_deallocate(mach_task_self(), reinterpret_cast<vm_address_t>(m_data), m_size); +} + +PurgeableBuffer* PurgeableBuffer::create(const char* data, size_t size) +{ + if (size < minPurgeableBufferSize) + return 0; + + vm_address_t buffer = 0; + kern_return_t ret = vm_allocate(mach_task_self(), &buffer, size, VM_FLAGS_PURGABLE | VM_FLAGS_ANYWHERE); + + ASSERT(ret == KERN_SUCCESS); + if (ret != KERN_SUCCESS) + return 0; + + ret = vm_copy(mach_task_self(), reinterpret_cast<vm_address_t>(data), size, buffer); + + ASSERT(ret == KERN_SUCCESS); + if (ret != KERN_SUCCESS) { + vm_deallocate(mach_task_self(), buffer, size); + return 0; + } + + return new PurgeableBuffer(reinterpret_cast<char*>(buffer), size); +} + +bool PurgeableBuffer::makePurgeable(bool purgeable) +{ + if (purgeable) { + if (m_state != NonVolatile) + return true; + + int volatileGroup; + if (m_purgePriority == PurgeFirst) + volatileGroup = VM_VOLATILE_GROUP_0; + else if (m_purgePriority == PurgeMiddle) + volatileGroup = VM_VOLATILE_GROUP_4; + else + volatileGroup = VM_VOLATILE_GROUP_7; + + int state = VM_PURGABLE_VOLATILE | volatileGroup; + // So apparently "purgeable" is the correct spelling and the API here is misspelled. + kern_return_t ret = vm_purgable_control(mach_task_self(), reinterpret_cast<vm_address_t>(m_data), VM_PURGABLE_SET_STATE, &state); + + if (ret != KERN_SUCCESS) { + // If that failed we have no clue what state we are in so assume purged. + m_state = Purged; + return true; + } + + m_state = Volatile; + return true; + } + + if (m_state == NonVolatile) + return true; + if (m_state == Purged) + return false; + + int state = VM_PURGABLE_NONVOLATILE; + kern_return_t ret = vm_purgable_control(mach_task_self(), reinterpret_cast<vm_address_t>(m_data), VM_PURGABLE_SET_STATE, &state); + + if (ret != KERN_SUCCESS) { + // If that failed we have no clue what state we are in so assume purged. + m_state = Purged; + return false; + } + + m_state = state & VM_PURGABLE_EMPTY ? Purged : NonVolatile; + return m_state == NonVolatile; +} + +bool PurgeableBuffer::wasPurged() const +{ + if (m_state == NonVolatile) + return false; + if (m_state == Purged) + return true; + + int state; + kern_return_t ret = vm_purgable_control(mach_task_self(), reinterpret_cast<vm_address_t>(m_data), VM_PURGABLE_GET_STATE, &state); + + if (ret != KERN_SUCCESS) { + // If that failed we have no clue what state we are in so assume purged. + m_state = Purged; + return true; + } + + if (state & VM_PURGABLE_EMPTY) { + m_state = Purged; + return true; + } + + return false; +} + +void PurgeableBuffer::setPurgePriority(PurgePriority priority) +{ + if (priority == m_purgePriority) + return; + m_purgePriority = priority; + if (m_state != Volatile) + return; + m_state = NonVolatile; + makePurgeable(true); +} + +const char* PurgeableBuffer::data() const +{ + ASSERT(m_state == NonVolatile); + return m_data; +} + +} + +#endif // BUILDING_ON_TIGER diff --git a/WebCore/platform/mac/ScrollViewMac.mm b/WebCore/platform/mac/ScrollViewMac.mm index 6d477e2..5ff0ff5 100644 --- a/WebCore/platform/mac/ScrollViewMac.mm +++ b/WebCore/platform/mac/ScrollViewMac.mm @@ -92,14 +92,19 @@ void ScrollView::platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode [scrollView() scrollingModes:&horizontal vertical:&vertical]; END_BLOCK_OBJC_EXCEPTIONS; } - -void ScrollView::platformSetCanBlitOnScroll() + +void ScrollView::platformSetCanBlitOnScroll(bool canBlitOnScroll) { BEGIN_BLOCK_OBJC_EXCEPTIONS; - [[scrollView() contentView] setCopiesOnScroll:canBlitOnScroll()]; + [[scrollView() contentView] setCopiesOnScroll:canBlitOnScroll]; END_BLOCK_OBJC_EXCEPTIONS; } +bool ScrollView::platformCanBlitOnScroll() const +{ + return [[scrollView() contentView] copiesOnScroll]; +} + IntRect ScrollView::platformVisibleContentRect(bool includeScrollbars) const { BEGIN_BLOCK_OBJC_EXCEPTIONS; @@ -152,7 +157,7 @@ bool ScrollView::platformScroll(ScrollDirection, ScrollGranularity) { // FIXME: It would be nice to implement this so that all of the code in WebFrameView could go away. notImplemented(); - return true; + return false; } void ScrollView::platformRepaintContentRectangle(const IntRect& rect, bool now) diff --git a/WebCore/platform/mac/ScrollbarThemeMac.mm b/WebCore/platform/mac/ScrollbarThemeMac.mm index dd2c233..22bfe46 100644 --- a/WebCore/platform/mac/ScrollbarThemeMac.mm +++ b/WebCore/platform/mac/ScrollbarThemeMac.mm @@ -34,8 +34,9 @@ #include "Scrollbar.h" #include "ScrollbarClient.h" #include "Settings.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. @@ -57,8 +58,10 @@ static HashSet<Scrollbar*>* gScrollbars; @implementation ScrollbarPrefsObserver -+ (void)appearancePrefsChanged:(NSNotification*)theNotification ++ (void)appearancePrefsChanged:(NSNotification*)unusedNotification { + UNUSED_PARAM(unusedNotification); + static_cast<ScrollbarThemeMac*>(ScrollbarTheme::nativeTheme())->preferencesChanged(); if (!gScrollbars) return; @@ -69,8 +72,10 @@ static HashSet<Scrollbar*>* gScrollbars; } } -+ (void)behaviorPrefsChanged:(NSNotification*)theNotification ++ (void)behaviorPrefsChanged:(NSNotification*)unusedNotification { + UNUSED_PARAM(unusedNotification); + static_cast<ScrollbarThemeMac*>(ScrollbarTheme::nativeTheme())->preferencesChanged(); } @@ -86,7 +91,7 @@ namespace WebCore { ScrollbarTheme* ScrollbarTheme::nativeTheme() { - static ScrollbarThemeMac theme; + DEFINE_STATIC_LOCAL(ScrollbarThemeMac, theme, ()); return &theme; } diff --git a/WebCore/platform/mac/SharedBufferMac.mm b/WebCore/platform/mac/SharedBufferMac.mm index ecf01c7..f1d9517 100644 --- a/WebCore/platform/mac/SharedBufferMac.mm +++ b/WebCore/platform/mac/SharedBufferMac.mm @@ -24,9 +24,10 @@ */ #include "config.h" -#include "FoundationExtras.h" #include "SharedBuffer.h" + #include "WebCoreObjCExtras.h" +#include <runtime/InitializeThreading.h> #include <string.h> #include <wtf/PassRefPtr.h> @@ -46,12 +47,13 @@ using namespace WebCore; @implementation WebCoreSharedBufferData -#ifndef BUILDING_ON_TIGER + (void)initialize { + JSC::initializeThreading(); +#ifndef BUILDING_ON_TIGER WebCoreObjCFinalizeOnMainThread(self); -} #endif +} - (void)dealloc { @@ -113,7 +115,7 @@ CFDataRef SharedBuffer::createCFData() return m_cfData.get(); } - return (CFDataRef)HardRetainWithNSRelease([[WebCoreSharedBufferData alloc] initWithSharedBuffer:this]); + return (CFDataRef)RetainPtr<WebCoreSharedBufferData>(AdoptNS, [[WebCoreSharedBufferData alloc] initWithSharedBuffer:this]).releaseRef(); } PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String& filePath) diff --git a/WebCore/platform/mac/SharedTimerMac.mm b/WebCore/platform/mac/SharedTimerMac.mm index 991f527..b9eaaef 100644 --- a/WebCore/platform/mac/SharedTimerMac.mm +++ b/WebCore/platform/mac/SharedTimerMac.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 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,8 +26,8 @@ #import "config.h" #import "SharedTimer.h" -#include <Foundation/Foundation.h> -#include <wtf/Assertions.h> +#import <wtf/Assertions.h> +#import <wtf/UnusedParam.h> @class WebCorePowerNotifier; @@ -58,8 +58,10 @@ static void timerFired(CFRunLoopTimerRef, void*); return self; } -- (void)didWake:(NSNotification *)notification +- (void)didWake:(NSNotification *)unusedNotification { + UNUSED_PARAM(unusedNotification); + if (WebCore::sharedTimer) { WebCore::stopSharedTimer(); WebCore::timerFired(0, 0); diff --git a/WebCore/platform/mac/SystemTimeMac.cpp b/WebCore/platform/mac/SystemTimeMac.cpp index dd5e500..1b2aae0 100644 --- a/WebCore/platform/mac/SystemTimeMac.cpp +++ b/WebCore/platform/mac/SystemTimeMac.cpp @@ -31,11 +31,6 @@ namespace WebCore { -double currentTime() -{ - return CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970; -} - float userIdleTime() { return static_cast<float>(CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGAnyInputEventType)); diff --git a/WebCore/platform/mac/ThemeMac.mm b/WebCore/platform/mac/ThemeMac.mm index 3b1da55..a3e743f 100644 --- a/WebCore/platform/mac/ThemeMac.mm +++ b/WebCore/platform/mac/ThemeMac.mm @@ -30,6 +30,7 @@ #import "LocalCurrentGraphicsContext.h" #import "ScrollView.h" #import "WebCoreSystemInterface.h" +#include <wtf/StdLibExtras.h> using namespace std; @@ -46,7 +47,7 @@ enum { Theme* platformTheme() { - static ThemeMac themeMac; + DEFINE_STATIC_LOCAL(ThemeMac, themeMac, ()); return &themeMac; } diff --git a/WebCore/platform/mac/ThreadCheck.mm b/WebCore/platform/mac/ThreadCheck.mm index 6320c70..b862598 100644 --- a/WebCore/platform/mac/ThreadCheck.mm +++ b/WebCore/platform/mac/ThreadCheck.mm @@ -28,6 +28,7 @@ #import "StringHash.h" #import <wtf/HashSet.h> +#import <wtf/StdLibExtras.h> namespace WebCore { @@ -79,7 +80,7 @@ void reportThreadViolation(const char* function) void WebCoreReportThreadViolation(const char* function) { using namespace WebCore; - static HashSet<String> loggedFunctions; + DEFINE_STATIC_LOCAL(HashSet<String>, loggedFunctions, ()); switch (threadViolationBehavior) { case NoThreadCheck: break; diff --git a/WebCore/platform/mac/WebCoreKeyGenerator.m b/WebCore/platform/mac/WebCoreKeyGenerator.m index c1004a7..a1e780c 100644 --- a/WebCore/platform/mac/WebCoreKeyGenerator.m +++ b/WebCore/platform/mac/WebCoreKeyGenerator.m @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2003 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,6 +27,7 @@ #import "WebCoreKeyGenerator.h" #import <wtf/Assertions.h> +#import <wtf/UnusedParam.h> static WebCoreKeyGenerator *sharedGenerator; @@ -50,8 +51,12 @@ static WebCoreKeyGenerator *sharedGenerator; return nil; } -- (NSString *)signedPublicKeyAndChallengeStringWithStrengthIndex:(unsigned)index challenge:(NSString *)challenge pageURL:(NSURL *)pageURL +- (NSString *)signedPublicKeyAndChallengeStringWithStrengthIndex:(unsigned)unusedIndex challenge:(NSString *)unusedChallenge pageURL:(NSURL *)unusedPageURL { + UNUSED_PARAM(unusedIndex); + UNUSED_PARAM(unusedChallenge); + UNUSED_PARAM(unusedPageURL); + return nil; } diff --git a/WebCore/platform/mac/WebCoreNSStringExtras.h b/WebCore/platform/mac/WebCoreNSStringExtras.h index 95d2031..f040f16 100644 --- a/WebCore/platform/mac/WebCoreNSStringExtras.h +++ b/WebCore/platform/mac/WebCoreNSStringExtras.h @@ -26,15 +26,25 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#import <Cocoa/Cocoa.h> +#include <ApplicationServices/ApplicationServices.h> +#include <objc/objc.h> + +#ifdef __OBJC__ +#include <Foundation/Foundation.h> +@class NSString; +#else +typedef struct NSString NSString; +#endif #ifdef __cplusplus extern "C" { #endif +BOOL stringIsCaseInsensitiveEqualToString(NSString *first, NSString *second); BOOL hasCaseInsensitiveSuffix(NSString *string, NSString *suffix); BOOL hasCaseInsensitiveSubstring(NSString *string, NSString *substring); NSString *filenameByFixingIllegalCharacters(NSString *string); +CFStringEncoding stringEncodingForResource(Handle resource); #ifdef __cplusplus } diff --git a/WebCore/platform/mac/WebCoreNSStringExtras.mm b/WebCore/platform/mac/WebCoreNSStringExtras.mm index a2b0a28..b7087f1 100644 --- a/WebCore/platform/mac/WebCoreNSStringExtras.mm +++ b/WebCore/platform/mac/WebCoreNSStringExtras.mm @@ -29,6 +29,11 @@ #import "config.h" #import "WebCoreNSStringExtras.h" +BOOL stringIsCaseInsensitiveEqualToString(NSString *first, NSString *second) +{ + return [first compare:second options:(NSCaseInsensitiveSearch|NSLiteralSearch)] == NSOrderedSame; +} + BOOL hasCaseInsensitiveSuffix(NSString *string, NSString *suffix) { return [string rangeOfString:suffix options:(NSCaseInsensitiveSearch | NSBackwardsSearch | NSAnchoredSearch)].location != NSNotFound; @@ -60,3 +65,55 @@ NSString *filenameByFixingIllegalCharacters(NSString *string) return filename; } + +CFStringEncoding stringEncodingForResource(Handle resource) +{ + short resRef = HomeResFile(resource); + 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) { + return NSMacOSRomanStringEncoding; + } + + CFURLRef URL = CFURLCreateFromFSRef(NULL, &fref); + if (URL == NULL) { + return NSMacOSRomanStringEncoding; + } + + NSString *path = [(NSURL *)URL path]; + CFRelease(URL); + + // Get the lproj directory name + path = [path stringByDeletingLastPathComponent]; + if (!stringIsCaseInsensitiveEqualToString([path pathExtension], @"lproj")) { + return NSMacOSRomanStringEncoding; + } + + NSString *directoryName = [[path stringByDeletingPathExtension] lastPathComponent]; + CFStringRef locale = CFLocaleCreateCanonicalLocaleIdentifierFromString(NULL, (CFStringRef)directoryName); + if (locale == NULL) { + return NSMacOSRomanStringEncoding; + } + + LangCode lang; + RegionCode region; + error = LocaleStringToLangAndRegionCodes([(NSString *)locale UTF8String], &lang, ®ion); + CFRelease(locale); + if (error != noErr) { + return NSMacOSRomanStringEncoding; + } + + TextEncoding encoding; + error = UpgradeScriptInfoToTextEncoding(kTextScriptDontCare, lang, region, NULL, &encoding); + if (error != noErr) { + return NSMacOSRomanStringEncoding; + } + + return encoding; +} + diff --git a/WebCore/platform/mac/WebCoreObjCExtras.mm b/WebCore/platform/mac/WebCoreObjCExtras.mm index 105c462..cb8d504 100644 --- a/WebCore/platform/mac/WebCoreObjCExtras.mm +++ b/WebCore/platform/mac/WebCoreObjCExtras.mm @@ -34,17 +34,17 @@ #include <wtf/Assertions.h> #include <wtf/MainThread.h> #include <wtf/Threading.h> +#include <wtf/UnusedParam.h> void WebCoreObjCFinalizeOnMainThread(Class cls) { + // This method relies on threading being initialized by the caller, otherwise + // WebCoreObjCScheduleDeallocateOnMainThread will crash. #if !defined(BUILDING_ON_TIGER) && !defined(DONT_FINALIZE_ON_MAIN_THREAD) objc_finalizeOnMainThread(cls); +#else + UNUSED_PARAM(cls); #endif - - // The reason we call initializeThreading here is that we'd like to have - // threading initialized early, otherwise WebCoreObjCScheduleDeallocateOnMainThread - // will crash - WTF::initializeThreading(); } #ifdef BUILDING_ON_TIGER diff --git a/WebCore/platform/mac/WebCoreSystemInterface.h b/WebCore/platform/mac/WebCoreSystemInterface.h index 6085483..14d1713 100644 --- a/WebCore/platform/mac/WebCoreSystemInterface.h +++ b/WebCore/platform/mac/WebCoreSystemInterface.h @@ -95,15 +95,8 @@ extern void (*wkDrawFocusRing)(CGContextRef, CGColorRef, int radius); extern NSFont* (*wkGetFontInLanguageForRange)(NSFont*, NSString*, NSRange); extern NSFont* (*wkGetFontInLanguageForCharacter)(NSFont*, UniChar); extern BOOL (*wkGetGlyphTransformedAdvances)(CGFontRef, NSFont*, CGAffineTransform*, ATSGlyphRef*, CGSize* advance); -extern void (*wkDrawMediaFullscreenButton)(CGContextRef context, CGRect rect, BOOL active); -extern void (*wkDrawMediaMuteButton)(CGContextRef context, CGRect rect, BOOL active); -extern void (*wkDrawMediaPauseButton)(CGContextRef context, CGRect rect, BOOL active); -extern void (*wkDrawMediaPlayButton)(CGContextRef context, CGRect rect, BOOL active); -extern void (*wkDrawMediaSeekBackButton)(CGContextRef context, CGRect rect, BOOL active); -extern void (*wkDrawMediaSeekForwardButton)(CGContextRef context, CGRect rect, BOOL active); -extern void (*wkDrawMediaSliderTrack)(CGContextRef context, CGRect rect, float percentLoaded); -extern void (*wkDrawMediaSliderThumb)(CGContextRef context, CGRect rect, BOOL active); -extern void (*wkDrawMediaUnMuteButton)(CGContextRef context, CGRect rect, BOOL active); +extern void (*wkDrawMediaSliderTrack)(int themeStyle, CGContextRef context, CGRect rect, float timeLoaded, float currentTime, float duration); +extern void (*wkDrawMediaUIPart)(int part, int themeStyle, CGContextRef context, CGRect rect, BOOL active); extern NSString* (*wkGetPreferredExtensionForMIMEType)(NSString*); extern NSArray* (*wkGetExtensionsForMIMEType)(NSString*); extern NSString* (*wkGetMIMETypeForExtension)(NSString*); @@ -112,6 +105,8 @@ extern double (*wkGetNSURLResponseCalculatedExpiration)(NSURLResponse *response) extern NSDate *(*wkGetNSURLResponseLastModifiedDate)(NSURLResponse *response); extern BOOL (*wkGetNSURLResponseMustRevalidate)(NSURLResponse *response); extern void (*wkGetWheelEventDeltas)(NSEvent*, float* deltaX, float* deltaY, BOOL* continuous); +extern BOOL (*wkHitTestMediaUIPart)(int part, int themeStyle, CGRect bounds, CGPoint point); +extern void (*wkMeasureMediaUIPart)(int part, int themeStyle, CGRect *bounds, CGSize *naturalSize); extern void (*wkPopupMenu)(NSMenu*, NSPoint location, float width, NSView*, int selectedItem, NSFont*); extern int (*wkQTMovieDataRate)(QTMovie*); extern float (*wkQTMovieMaxTimeLoaded)(QTMovie*); @@ -147,6 +142,8 @@ extern void (*wkReleaseStyleGroup)(void* group); extern BOOL (*wkSupportsMultipartXMixedReplace)(NSMutableURLRequest *); #endif +extern BOOL (*wkUseSharedMediaUI)(); + #ifdef __cplusplus } #endif diff --git a/WebCore/platform/mac/WebCoreSystemInterface.mm b/WebCore/platform/mac/WebCoreSystemInterface.mm index c0305ae..b629b4e 100644 --- a/WebCore/platform/mac/WebCoreSystemInterface.mm +++ b/WebCore/platform/mac/WebCoreSystemInterface.mm @@ -38,15 +38,10 @@ void (*wkDrawFocusRing)(CGContextRef, CGColorRef, int radius); NSFont* (*wkGetFontInLanguageForRange)(NSFont*, NSString*, NSRange); NSFont* (*wkGetFontInLanguageForCharacter)(NSFont*, UniChar); BOOL (*wkGetGlyphTransformedAdvances)(CGFontRef, NSFont*, CGAffineTransform*, ATSGlyphRef*, CGSize* advance); -void (*wkDrawMediaFullscreenButton)(CGContextRef context, CGRect rect, BOOL active); -void (*wkDrawMediaMuteButton)(CGContextRef context, CGRect rect, BOOL active); -void (*wkDrawMediaPauseButton)(CGContextRef context, CGRect rect, BOOL active); -void (*wkDrawMediaPlayButton)(CGContextRef context, CGRect rect, BOOL active); -void (*wkDrawMediaSeekBackButton)(CGContextRef context, CGRect rect, BOOL active); -void (*wkDrawMediaSeekForwardButton)(CGContextRef context, CGRect rect, BOOL active); -void (*wkDrawMediaSliderTrack)(CGContextRef context, CGRect rect, float percentLoaded); -void (*wkDrawMediaSliderThumb)(CGContextRef context, CGRect rect, BOOL active); -void (*wkDrawMediaUnMuteButton)(CGContextRef context, CGRect rect, BOOL active); +void (*wkDrawMediaSliderTrack)(int themeStyle, CGContextRef context, CGRect rect, float timeLoaded, float currentTime, float duration); +BOOL (*wkHitTestMediaUIPart)(int part, int themeStyle, CGRect bounds, CGPoint point); +void (*wkDrawMediaUIPart)(int part, int themeStyle, CGContextRef context, CGRect rect, BOOL active); +void (*wkMeasureMediaUIPart)(int part, int themeStyle, CGRect *bounds, CGSize *naturalSize); NSString* (*wkGetPreferredExtensionForMIMEType)(NSString*); NSArray* (*wkGetExtensionsForMIMEType)(NSString*); NSString* (*wkGetMIMETypeForExtension)(NSString*); diff --git a/WebCore/platform/mac/WebFontCache.mm b/WebCore/platform/mac/WebFontCache.mm index 84f60b5..6cf1ef4 100644 --- a/WebCore/platform/mac/WebFontCache.mm +++ b/WebCore/platform/mac/WebFontCache.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com> * * Redistribution and use in source and binary forms, with or without @@ -28,9 +28,9 @@ */ #import "config.h" -#import "FontTraitsMask.h" #import "WebFontCache.h" +#import "FontTraitsMask.h" #import <math.h> using namespace WebCore; @@ -51,7 +51,7 @@ typedef int NSInteger; | NSSmallCapsFontMask \ ) -static BOOL acceptableChoice(NSFontTraitMask desiredTraits, int desiredWeight, NSFontTraitMask candidateTraits, int candidateWeight) +static BOOL acceptableChoice(NSFontTraitMask desiredTraits, NSFontTraitMask candidateTraits) { desiredTraits &= ~SYNTHESIZED_FONT_TRAITS; return (candidateTraits & desiredTraits) == desiredTraits; @@ -61,7 +61,7 @@ static BOOL betterChoice(NSFontTraitMask desiredTraits, int desiredWeight, NSFontTraitMask chosenTraits, int chosenWeight, NSFontTraitMask candidateTraits, int candidateWeight) { - if (!acceptableChoice(desiredTraits, desiredWeight, candidateTraits, candidateWeight)) + if (!acceptableChoice(desiredTraits, candidateTraits)) return NO; // A list of the traits we care about. @@ -230,7 +230,7 @@ static inline FontTraitsMask toTraitsMask(NSFontTraitMask appKitTraits, NSIntege BOOL newWinner; if (!choseFont) - newWinner = acceptableChoice(desiredTraits, desiredWeight, fontTraits, fontWeight); + newWinner = acceptableChoice(desiredTraits, fontTraits); else newWinner = betterChoice(desiredTraits, desiredWeight, chosenTraits, chosenWeight, fontTraits, fontWeight); diff --git a/WebCore/platform/mac/WidgetMac.mm b/WebCore/platform/mac/WidgetMac.mm index 3fe8e0d..ecd4f30 100644 --- a/WebCore/platform/mac/WidgetMac.mm +++ b/WebCore/platform/mac/WidgetMac.mm @@ -26,6 +26,10 @@ #import "config.h" #import "Widget.h" +#ifdef BUILDING_ON_TIGER +#import "AutodrainedPool.h" +#endif + #import "BlockExceptions.h" #import "Cursor.h" #import "Document.h" @@ -38,7 +42,6 @@ #import "ScrollView.h" #import "WebCoreFrameView.h" #import "WebCoreView.h" - #import <wtf/RetainPtr.h> @interface NSWindow (WebWindowDetails) @@ -218,8 +221,13 @@ void Widget::paint(GraphicsContext* p, const IntRect& r) CGContextScaleCTM(cgContext, 1, -1); BEGIN_BLOCK_OBJC_EXCEPTIONS; - NSGraphicsContext *nsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:cgContext flipped:YES]; - [view displayRectIgnoringOpacity:[view convertRect:r fromView:[view superview]] inContext:nsContext]; + { +#ifdef BUILDING_ON_TIGER + AutodrainedPool pool; +#endif + NSGraphicsContext *nsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:cgContext flipped:YES]; + [view displayRectIgnoringOpacity:[view convertRect:r fromView:[view superview]] inContext:nsContext]; + } END_BLOCK_OBJC_EXCEPTIONS; CGContextRestoreGState(cgContext); @@ -252,10 +260,10 @@ void Widget::removeFromSuperview() } } -void Widget::beforeMouseDown(NSView *view, Widget* widget) +void Widget::beforeMouseDown(NSView *unusedView, Widget* widget) { if (widget) { - ASSERT(view == widget->getOuterView()); + ASSERT_UNUSED(unusedView, unusedView == widget->getOuterView()); ASSERT(!widget->m_data->mustStayInWindow); widget->m_data->mustStayInWindow = true; } diff --git a/WebCore/platform/network/AuthenticationChallengeBase.h b/WebCore/platform/network/AuthenticationChallengeBase.h index 5810a6d..9d85866 100644 --- a/WebCore/platform/network/AuthenticationChallengeBase.h +++ b/WebCore/platform/network/AuthenticationChallengeBase.h @@ -52,7 +52,7 @@ public: protected: // The AuthenticationChallenge subclass may "shadow" this method to compare platform specific fields - static bool platformCompare(const AuthenticationChallengeBase& a, const AuthenticationChallengeBase& b) { return true; } + static bool platformCompare(const AuthenticationChallengeBase&, const AuthenticationChallengeBase&) { return true; } bool m_isNull; ProtectionSpace m_protectionSpace; diff --git a/WebCore/platform/network/FormData.cpp b/WebCore/platform/network/FormData.cpp index 0d31856..3cac168 100644 --- a/WebCore/platform/network/FormData.cpp +++ b/WebCore/platform/network/FormData.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Google 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 @@ -90,6 +91,28 @@ PassRefPtr<FormData> FormData::copy() const return adoptRef(new FormData(*this)); } +PassRefPtr<FormData> FormData::deepCopy() const +{ + RefPtr<FormData> formData(create()); + + formData->m_alwaysStream = m_alwaysStream; + + size_t n = m_elements.size(); + formData->m_elements.reserveCapacity(n); + for (size_t i = 0; i < n; ++i) { + const FormDataElement& e = m_elements[i]; + switch (e.m_type) { + case FormDataElement::data: + formData->m_elements.append(FormDataElement(e.m_data)); + break; + case FormDataElement::encodedFile: + formData->m_elements.append(FormDataElement(e.m_filename, e.m_shouldGenerateFile)); + break; + } + } + return formData.release(); +} + void FormData::appendData(const void* data, size_t size) { if (m_elements.isEmpty() || m_elements.last().m_type != FormDataElement::data) diff --git a/WebCore/platform/network/FormData.h b/WebCore/platform/network/FormData.h index cb91fab..5998b1b 100644 --- a/WebCore/platform/network/FormData.h +++ b/WebCore/platform/network/FormData.h @@ -68,6 +68,7 @@ public: static PassRefPtr<FormData> create(const CString&); static PassRefPtr<FormData> create(const Vector<char>&); PassRefPtr<FormData> copy() const; + PassRefPtr<FormData> deepCopy() const; ~FormData(); void appendData(const void* data, size_t); diff --git a/WebCore/platform/network/FormDataBuilder.cpp b/WebCore/platform/network/FormDataBuilder.cpp new file mode 100644 index 0000000..27bdee3 --- /dev/null +++ b/WebCore/platform/network/FormDataBuilder.cpp @@ -0,0 +1,238 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * (C) 2006 Alexey Proskuryakov (ap@nypop.com) + * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.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 "FormDataBuilder.h" + +#include "CString.h" +#include "Document.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "TextEncoding.h" + +#include <limits> +#include <wtf/Assertions.h> +#include <wtf/RandomNumber.h> + +namespace WebCore { + +FormDataBuilder::FormDataBuilder() + : m_isPostMethod(false) + , m_isMultiPartForm(false) + , m_encodingType("application/x-www-form-urlencoded") +{ +} + +FormDataBuilder::~FormDataBuilder() +{ +} + +void FormDataBuilder::parseEncodingType(const String& type) +{ + if (type.contains("multipart", false) || type.contains("form-data", false)) { + m_encodingType = "multipart/form-data"; + m_isMultiPartForm = true; + } else if (type.contains("text", false) || type.contains("plain", false)) { + m_encodingType = "text/plain"; + m_isMultiPartForm = false; + } else { + m_encodingType = "application/x-www-form-urlencoded"; + m_isMultiPartForm = false; + } +} + +void FormDataBuilder::parseMethodType(const String& type) +{ + if (equalIgnoringCase(type, "post")) + m_isPostMethod = true; + else if (equalIgnoringCase(type, "get")) + m_isPostMethod = false; +} + +TextEncoding FormDataBuilder::dataEncoding(Document* document) const +{ + String acceptCharset = m_acceptCharset; + acceptCharset.replace(',', ' '); + + Vector<String> charsets; + acceptCharset.split(' ', charsets); + + TextEncoding encoding; + + Vector<String>::const_iterator end = charsets.end(); + for (Vector<String>::const_iterator it = charsets.begin(); it != end; ++it) { + if ((encoding = TextEncoding(*it)).isValid()) + return encoding; + } + + if (Frame* frame = document->frame()) + return frame->loader()->encoding(); + + return Latin1Encoding(); +} + +// Helper functions +static inline void append(Vector<char>& buffer, char string) +{ + buffer.append(string); +} + +static inline void append(Vector<char>& buffer, const char* string) +{ + buffer.append(string, strlen(string)); +} + +static inline void append(Vector<char>& buffer, const CString& string) +{ + buffer.append(string.data(), string.length()); +} + +Vector<char> FormDataBuilder::generateUniqueBoundaryString() +{ + Vector<char> boundary; + + // The RFC 2046 spec says the alphanumeric characters plus the + // following characters are legal for boundaries: '()+_,-./:=? + // However the following characters, though legal, cause some sites + // to fail: (),./:= (http://bugs.webkit.org/show_bug.cgi?id=13352) + static const char alphaNumericEncodingMap[64] = { + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, + 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, + 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, + 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x41 + // FIXME <rdar://problem/5252577> gmail does not accept legal characters in the form boundary + // As stated above, some legal characters cause, sites to fail. Specifically + // the / character which was the last character in the above array. I have + // replaced the last character with another character already in the array + // (notice the first and last values are both 0x41, A). Instead of picking + // another unique legal character for boundary strings that, because it has + // never been tested, may or may not break other sites, I simply + // replaced / with A. This means A is twice as likely to occur in our boundary + // strings than any other character but I think this is fine for the time being. + // The FIXME here is about restoring the / character once the aforementioned + // radar has been resolved. + }; + + // Start with an informative prefix. + append(boundary, "----WebKitFormBoundary"); + + // Append 16 random 7bit ascii AlphaNumeric characters. + Vector<char> randomBytes; + + for (unsigned i = 0; i < 4; ++i) { + unsigned randomness = static_cast<unsigned>(WTF::randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)); + randomBytes.append(alphaNumericEncodingMap[(randomness >> 24) & 0x3F]); + randomBytes.append(alphaNumericEncodingMap[(randomness >> 16) & 0x3F]); + randomBytes.append(alphaNumericEncodingMap[(randomness >> 8) & 0x3F]); + randomBytes.append(alphaNumericEncodingMap[randomness & 0x3F]); + } + + boundary.append(randomBytes); + boundary.append(0); // Add a 0 at the end so we can use this as a C-style string. + return boundary; +} + +void FormDataBuilder::beginMultiPartHeader(Vector<char>& buffer, const CString& boundary, const CString& name) +{ + addBoundaryToMultiPartHeader(buffer, boundary); + + append(buffer, "Content-Disposition: form-data; name=\""); + append(buffer, name); + append(buffer, '"'); +} + +void FormDataBuilder::addBoundaryToMultiPartHeader(Vector<char>& buffer, const CString& boundary, bool isLastBoundary) +{ + append(buffer, "--"); + append(buffer, boundary); + + if (isLastBoundary) + append(buffer, "--"); + + append(buffer, "\r\n"); +} + +void FormDataBuilder::addFilenameToMultiPartHeader(Vector<char>& buffer, const TextEncoding& encoding, const String& filename) +{ + // FIXME: This won't work if the filename includes a " mark, + // or control characters like CR or LF. This also does strange + // things if the filename includes characters you can't encode + // in the website's character set. + append(buffer, "; filename=\""); + append(buffer, encoding.encode(filename.characters(), filename.length(), QuestionMarksForUnencodables)); + append(buffer, '"'); +} + +void FormDataBuilder::addContentTypeToMultiPartHeader(Vector<char>& buffer, const CString& mimeType) +{ + append(buffer, "\r\nContent-Type: "); + append(buffer, mimeType); +} + +void FormDataBuilder::finishMultiPartHeader(Vector<char>& buffer) +{ + append(buffer, "\r\n\r\n"); +} + +void FormDataBuilder::addKeyValuePairAsFormData(Vector<char>& buffer, const CString& key, const CString& value) +{ + if (!buffer.isEmpty()) + append(buffer, '&'); + + encodeStringAsFormData(buffer, key); + append(buffer, '='); + encodeStringAsFormData(buffer, value); +} + +void FormDataBuilder::encodeStringAsFormData(Vector<char>& buffer, const CString& string) +{ + static const char hexDigits[17] = "0123456789ABCDEF"; + + // Same safe characters as Netscape for compatibility. + static const char safeCharacters[] = "-._*"; + + // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1 + unsigned length = string.length(); + for (unsigned i = 0; i < length; ++i) { + unsigned char c = string.data()[i]; + + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || strchr(safeCharacters, c)) + append(buffer, c); + else if (c == ' ') + append(buffer, '+'); + else if (c == '\n' || (c == '\r' && (i + 1 >= length || string.data()[i + 1] != '\n'))) + append(buffer, "%0D%0A"); + else if (c != '\r') { + append(buffer, '%'); + append(buffer, hexDigits[c >> 4]); + append(buffer, hexDigits[c & 0xF]); + } + } +} + +} diff --git a/WebCore/platform/network/FormDataBuilder.h b/WebCore/platform/network/FormDataBuilder.h new file mode 100644 index 0000000..666f0c1 --- /dev/null +++ b/WebCore/platform/network/FormDataBuilder.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.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 FormDataBuilder_h +#define FormDataBuilder_h + +#include "PlatformString.h" +#include <wtf/Noncopyable.h> + +namespace WebCore { + +class CString; +class Document; +class TextEncoding; + +class FormDataBuilder : Noncopyable { +public: + FormDataBuilder(); + ~FormDataBuilder(); + + bool isPostMethod() const { return m_isPostMethod; } + void setIsPostMethod(bool value) { m_isPostMethod = value; } + + bool isMultiPartForm() const { return m_isMultiPartForm; } + void setIsMultiPartForm(bool value) { m_isMultiPartForm = value; } + + String encodingType() const { return m_encodingType; } + void setEncodingType(const String& value) { m_encodingType = value; } + + String acceptCharset() const { return m_acceptCharset; } + void setAcceptCharset(const String& value) { m_acceptCharset = value; } + + void parseEncodingType(const String&); + void parseMethodType(const String&); + + TextEncoding dataEncoding(Document*) const; + + // Helper functions used by HTMLFormElement/WMLGoElement for multi-part form data + static Vector<char> generateUniqueBoundaryString(); + static void beginMultiPartHeader(Vector<char>&, const CString& boundary, const CString& name); + static void addBoundaryToMultiPartHeader(Vector<char>&, const CString& boundary, bool isLastBoundary = false); + static void addFilenameToMultiPartHeader(Vector<char>&, const TextEncoding&, const String& filename); + static void addContentTypeToMultiPartHeader(Vector<char>&, const CString& mimeType); + static void finishMultiPartHeader(Vector<char>&); + + // Helper functions used by HTMLFormElement/WMLGoElement for non multi-part form data + static void addKeyValuePairAsFormData(Vector<char>&, const CString& key, const CString& value); + static void encodeStringAsFormData(Vector<char>&, const CString&); + +private: + bool m_isPostMethod; + bool m_isMultiPartForm; + + String m_encodingType; + String m_acceptCharset; +}; + +} + +#endif diff --git a/WebCore/platform/network/HTTPHeaderMap.cpp b/WebCore/platform/network/HTTPHeaderMap.cpp new file mode 100644 index 0000000..aa9c5fa --- /dev/null +++ b/WebCore/platform/network/HTTPHeaderMap.cpp @@ -0,0 +1,63 @@ +/* + * 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 "HTTPHeaderMap.h" + +#include <memory> +#include <utility> + +using namespace std; + +namespace WebCore { + +auto_ptr<CrossThreadHTTPHeaderMapData> HTTPHeaderMap::copyData() const +{ + auto_ptr<CrossThreadHTTPHeaderMapData> data(new CrossThreadHTTPHeaderMapData()); + data->reserveCapacity(size()); + + 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())); + } + return data; +} + +void HTTPHeaderMap::adopt(auto_ptr<CrossThreadHTTPHeaderMapData> data) +{ + clear(); + size_t dataSize = data->size(); + for (size_t index = 0; index < dataSize; ++index) { + pair<String, String>& header = (*data)[index]; + set(header.first, header.second); + } +} + +} // namespace WebCore diff --git a/WebCore/platform/network/HTTPHeaderMap.h b/WebCore/platform/network/HTTPHeaderMap.h index dc204cb..6da1b90 100644 --- a/WebCore/platform/network/HTTPHeaderMap.h +++ b/WebCore/platform/network/HTTPHeaderMap.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2006 Apple Computer, 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 @@ -26,12 +27,25 @@ #ifndef HTTPHeaderMap_h #define HTTPHeaderMap_h +#include "AtomicString.h" +#include "AtomicStringHash.h" #include "StringHash.h" +#include <memory> +#include <utility> #include <wtf/HashMap.h> +#include <wtf/Vector.h> namespace WebCore { - typedef HashMap<String, String, CaseFoldingHash> HTTPHeaderMap; + typedef Vector<std::pair<String, String> > CrossThreadHTTPHeaderMapData; + + class HTTPHeaderMap : public HashMap<AtomicString, String, CaseFoldingHash> { + public: + // Gets a copy of the data suitable for passing to another thread. + std::auto_ptr<CrossThreadHTTPHeaderMapData> copyData() const; + + void adopt(std::auto_ptr<CrossThreadHTTPHeaderMapData>); + }; } // namespace WebCore diff --git a/WebCore/platform/network/NetworkStateNotifier.cpp b/WebCore/platform/network/NetworkStateNotifier.cpp index d39fc30..7638478 100644 --- a/WebCore/platform/network/NetworkStateNotifier.cpp +++ b/WebCore/platform/network/NetworkStateNotifier.cpp @@ -27,14 +27,16 @@ #include "NetworkStateNotifier.h" #include <wtf/Assertions.h> +#include <wtf/StdLibExtras.h> +#include <wtf/Threading.h> namespace WebCore { NetworkStateNotifier& networkStateNotifier() { - static NetworkStateNotifier networkStateNotifier; + AtomicallyInitializedStatic(NetworkStateNotifier*, networkStateNotifier = new NetworkStateNotifier); - return networkStateNotifier; + return *networkStateNotifier; } void NetworkStateNotifier::setNetworkStateChangedFunction(void(*function)()) diff --git a/WebCore/platform/network/NetworkStateNotifier.h b/WebCore/platform/network/NetworkStateNotifier.h index 53ab4c8..f918be6 100644 --- a/WebCore/platform/network/NetworkStateNotifier.h +++ b/WebCore/platform/network/NetworkStateNotifier.h @@ -89,6 +89,7 @@ public: inline NetworkStateNotifier::NetworkStateNotifier() : m_isOnLine(true) + , m_networkStateChangedFunction(0) { } diff --git a/WebCore/platform/network/ResourceErrorBase.h b/WebCore/platform/network/ResourceErrorBase.h index b2aac67..4631324 100644 --- a/WebCore/platform/network/ResourceErrorBase.h +++ b/WebCore/platform/network/ResourceErrorBase.h @@ -70,7 +70,7 @@ protected: void platformLazyInit() {} // The ResourceError subclass may "shadow" this method to compare platform specific fields - static bool platformCompare(const ResourceError& a, const ResourceError& b) { return true; } + static bool platformCompare(const ResourceError&, const ResourceError&) { return true; } String m_domain; int m_errorCode; diff --git a/WebCore/platform/network/ResourceHandle.h b/WebCore/platform/network/ResourceHandle.h index 304bdbe..c981483 100644 --- a/WebCore/platform/network/ResourceHandle.h +++ b/WebCore/platform/network/ResourceHandle.h @@ -83,8 +83,6 @@ class ResourceRequest; class ResourceResponse; class SchedulePair; class SharedBuffer; -class SubresourceLoader; -class SubresourceLoaderClient; template <typename T> class Timer; @@ -109,6 +107,9 @@ public: ~ResourceHandle(); +#if PLATFORM(MAC) || USE(CFNETWORK) + bool shouldUseCredentialStorage(); +#endif #if PLATFORM(MAC) || USE(CFNETWORK) || USE(CURL) void didReceiveAuthenticationChallenge(const AuthenticationChallenge&); void receivedCredential(const AuthenticationChallenge&, const Credential&); diff --git a/WebCore/platform/network/ResourceHandleClient.h b/WebCore/platform/network/ResourceHandleClient.h index 08e06a2..3668d88 100644 --- a/WebCore/platform/network/ResourceHandleClient.h +++ b/WebCore/platform/network/ResourceHandleClient.h @@ -63,11 +63,11 @@ namespace WebCore { virtual ~ResourceHandleClient() { } // request may be modified - virtual void willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse& redirectResponse) { } - virtual void didSendData(ResourceHandle*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent) { } + virtual void willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse& /*redirectResponse*/) { } + virtual void didSendData(ResourceHandle*, unsigned long long /*bytesSent*/, unsigned long long /*totalBytesToBeSent*/) { } virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&) { } - virtual void didReceiveData(ResourceHandle*, const char*, int, int lengthReceived) { } + virtual void didReceiveData(ResourceHandle*, const char*, int, int /*lengthReceived*/) { } virtual void didFinishLoading(ResourceHandle*) { } virtual void didFail(ResourceHandle*, const ResourceError&) { } virtual void wasBlocked(ResourceHandle*) { } @@ -75,6 +75,7 @@ namespace WebCore { virtual void willCacheResponse(ResourceHandle*, CacheStoragePolicy&) { } + virtual bool shouldUseCredentialStorage(ResourceHandle*) { return false; } virtual void didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge&) { } virtual void didCancelAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge&) { } virtual void receivedCredential(ResourceHandle*, const AuthenticationChallenge&, const Credential&) { } diff --git a/WebCore/platform/network/ResourceHandleInternal.h b/WebCore/platform/network/ResourceHandleInternal.h index 0bfa9da..cc90cc8 100644 --- a/WebCore/platform/network/ResourceHandleInternal.h +++ b/WebCore/platform/network/ResourceHandleInternal.h @@ -122,6 +122,7 @@ namespace WebCore { , m_buffer(0) , m_bufsize(0) , m_total(0) + , m_idleHandler(0) #endif #if PLATFORM(QT) , m_job(0) @@ -194,6 +195,7 @@ namespace WebCore { GCancellable* m_cancellable; char* m_buffer; gsize m_bufsize, m_total; + guint m_idleHandler; #endif #if PLATFORM(QT) #if QT_VERSION < 0x040400 diff --git a/WebCore/platform/network/ResourceRequestBase.cpp b/WebCore/platform/network/ResourceRequestBase.cpp index 4784bbe..15469a0 100644 --- a/WebCore/platform/network/ResourceRequestBase.cpp +++ b/WebCore/platform/network/ResourceRequestBase.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2003, 2006 Apple Computer, 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 @@ -26,6 +27,8 @@ #include "ResourceRequestBase.h" #include "ResourceRequest.h" +using namespace std; + namespace WebCore { inline const ResourceRequest& ResourceRequestBase::asResourceRequest() const @@ -33,6 +36,57 @@ inline const ResourceRequest& ResourceRequestBase::asResourceRequest() const return *static_cast<const ResourceRequest*>(this); } +auto_ptr<ResourceRequest> ResourceRequestBase::adopt(auto_ptr<CrossThreadResourceRequestData> data) +{ + auto_ptr<ResourceRequest> request(new ResourceRequest()); + request->setURL(data->m_url); + request->setCachePolicy(data->m_cachePolicy); + request->setTimeoutInterval(data->m_timeoutInterval); + request->setMainDocumentURL(data->m_mainDocumentURL); + request->setHTTPMethod(data->m_httpMethod); + + request->updateResourceRequest(); + request->m_httpHeaderFields.adopt(auto_ptr<CrossThreadHTTPHeaderMapData>(data->m_httpHeaders.release())); + + size_t encodingCount = data->m_responseContentDispositionEncodingFallbackArray.size(); + if (encodingCount > 0) { + String encoding1 = data->m_responseContentDispositionEncodingFallbackArray[0]; + String encoding2; + String encoding3; + if (encodingCount > 1) { + encoding2 = data->m_responseContentDispositionEncodingFallbackArray[1]; + if (encodingCount > 2) + encoding3 = data->m_responseContentDispositionEncodingFallbackArray[2]; + } + ASSERT(encodingCount <= 3); + request->setResponseContentDispositionEncodingFallbackArray(encoding1, encoding2, encoding3); + } + request->setHTTPBody(data->m_httpBody); + request->setAllowHTTPCookies(data->m_allowHTTPCookies); + return request; +} + +auto_ptr<CrossThreadResourceRequestData> ResourceRequestBase::copyData() const +{ + auto_ptr<CrossThreadResourceRequestData> data(new CrossThreadResourceRequestData()); + data->m_url = url().copy(); + data->m_cachePolicy = cachePolicy(); + data->m_timeoutInterval = timeoutInterval(); + data->m_mainDocumentURL = mainDocumentURL().copy(); + data->m_httpMethod = httpMethod().copy(); + data->m_httpHeaders.adopt(httpHeaderFields().copyData()); + + data->m_responseContentDispositionEncodingFallbackArray.reserveCapacity(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()); + } + if (m_httpBody) + data->m_httpBody = m_httpBody->deepCopy(); + data->m_allowHTTPCookies = m_allowHTTPCookies; + return data; +} + bool ResourceRequestBase::isEmpty() const { updateResourceRequest(); @@ -134,14 +188,14 @@ const HTTPHeaderMap& ResourceRequestBase::httpHeaderFields() const return m_httpHeaderFields; } -String ResourceRequestBase::httpHeaderField(const String& name) const +String ResourceRequestBase::httpHeaderField(const AtomicString& name) const { updateResourceRequest(); return m_httpHeaderFields.get(name); } -void ResourceRequestBase::setHTTPHeaderField(const String& name, const String& value) +void ResourceRequestBase::setHTTPHeaderField(const AtomicString& name, const String& value) { updateResourceRequest(); @@ -150,6 +204,21 @@ void ResourceRequestBase::setHTTPHeaderField(const String& name, const String& v m_platformRequestUpdated = false; } +void ResourceRequestBase::setResponseContentDispositionEncodingFallbackArray(const String& encoding1, const String& encoding2, const String& encoding3) +{ + updateResourceRequest(); + + m_responseContentDispositionEncodingFallbackArray.clear(); + if (!encoding1.isNull()) + m_responseContentDispositionEncodingFallbackArray.append(encoding1); + if (!encoding2.isNull()) + m_responseContentDispositionEncodingFallbackArray.append(encoding2); + if (!encoding3.isNull()) + m_responseContentDispositionEncodingFallbackArray.append(encoding3); + + m_platformRequestUpdated = false; +} + FormData* ResourceRequestBase::httpBody() const { updateResourceRequest(); @@ -182,7 +251,7 @@ void ResourceRequestBase::setAllowHTTPCookies(bool allowHTTPCookies) m_platformRequestUpdated = false; } -void ResourceRequestBase::addHTTPHeaderField(const String& name, const String& value) +void ResourceRequestBase::addHTTPHeaderField(const AtomicString& name, const String& value) { updateResourceRequest(); pair<HTTPHeaderMap::iterator, bool> result = m_httpHeaderFields.add(name, value); diff --git a/WebCore/platform/network/ResourceRequestBase.h b/WebCore/platform/network/ResourceRequestBase.h index 32a3384..0f6bb47 100644 --- a/WebCore/platform/network/ResourceRequestBase.h +++ b/WebCore/platform/network/ResourceRequestBase.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * 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 @@ -31,6 +32,9 @@ #include "KURL.h" #include "HTTPHeaderMap.h" +#include <memory> +#include <wtf/OwnPtr.h> + namespace WebCore { enum ResourceRequestCachePolicy { @@ -43,10 +47,16 @@ namespace WebCore { const int unspecifiedTimeoutInterval = INT_MAX; class ResourceRequest; + struct CrossThreadResourceRequestData; // Do not use this type directly. Use ResourceRequest instead. class ResourceRequestBase { public: + static std::auto_ptr<ResourceRequest> adopt(std::auto_ptr<CrossThreadResourceRequestData>); + + // Gets a copy of the data suitable for passing to another thread. + std::auto_ptr<CrossThreadResourceRequestData> copyData() const; + bool isNull() const; bool isEmpty() const; @@ -66,9 +76,9 @@ namespace WebCore { void setHTTPMethod(const String& httpMethod); const HTTPHeaderMap& httpHeaderFields() const; - String httpHeaderField(const String& name) const; - void setHTTPHeaderField(const String& name, const String& value); - void addHTTPHeaderField(const String& name, const String& value); + String httpHeaderField(const AtomicString& name) const; + void setHTTPHeaderField(const AtomicString& name, const String& value); + void addHTTPHeaderField(const AtomicString& name, const String& value); void addHTTPHeaderFields(const HTTPHeaderMap& headerFields); String httpContentType() const { return httpHeaderField("Content-Type"); } @@ -88,6 +98,8 @@ namespace WebCore { String httpAccept() const { return httpHeaderField("Accept"); } void setHTTPAccept(const String& httpAccept) { setHTTPHeaderField("Accept", httpAccept); } + void setResponseContentDispositionEncodingFallbackArray(const String& encoding1, const String& encoding2 = String(), const String& encoding3 = String()); + FormData* httpBody() const; void setHTTPBody(PassRefPtr<FormData> httpBody); @@ -125,6 +137,7 @@ namespace WebCore { KURL m_mainDocumentURL; String m_httpMethod; HTTPHeaderMap m_httpHeaderFields; + Vector<String> m_responseContentDispositionEncodingFallbackArray; RefPtr<FormData> m_httpBody; bool m_allowHTTPCookies; mutable bool m_resourceRequestUpdated; @@ -139,6 +152,20 @@ namespace WebCore { bool operator==(const ResourceRequestBase&, const ResourceRequestBase&); inline bool operator!=(ResourceRequestBase& a, const ResourceRequestBase& b) { return !(a == b); } + struct CrossThreadResourceRequestData { + KURL m_url; + + ResourceRequestCachePolicy m_cachePolicy; + double m_timeoutInterval; + KURL m_mainDocumentURL; + + String m_httpMethod; + OwnPtr<CrossThreadHTTPHeaderMapData> m_httpHeaders; + Vector<String> m_responseContentDispositionEncodingFallbackArray; + RefPtr<FormData> m_httpBody; + bool m_allowHTTPCookies; + }; + } // namespace WebCore #endif // ResourceRequestBase_h diff --git a/WebCore/platform/network/ResourceResponseBase.cpp b/WebCore/platform/network/ResourceResponseBase.cpp index a9ddc30..f84e97d 100644 --- a/WebCore/platform/network/ResourceResponseBase.cpp +++ b/WebCore/platform/network/ResourceResponseBase.cpp @@ -1,5 +1,6 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006, 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 @@ -25,10 +26,58 @@ #include "config.h" #include "ResourceResponseBase.h" + #include "ResourceResponse.h" +using namespace std; + namespace WebCore { +static void parseCacheHeader(const String& header, Vector<pair<String, String> >& result); +static void parseCacheControlDirectiveValues(const String& directives, Vector<String>& result); + +auto_ptr<ResourceResponse> ResourceResponseBase::adopt(auto_ptr<CrossThreadResourceResponseData> data) +{ + auto_ptr<ResourceResponse> response(new ResourceResponse()); + response->setUrl(data->m_url); + response->setMimeType(data->m_mimeType); + response->setExpectedContentLength(data->m_expectedContentLength); + response->setTextEncodingName(data->m_textEncodingName); + response->setSuggestedFilename(data->m_suggestedFilename); + + response->setHTTPStatusCode(data->m_httpStatusCode); + response->setHTTPStatusText(data->m_httpStatusText); + + response->lazyInit(); + response->m_httpHeaderFields.adopt(std::auto_ptr<CrossThreadHTTPHeaderMapData>(data->m_httpHeaders.release())); + + response->setExpirationDate(data->m_expirationDate); + response->setLastModifiedDate(data->m_lastModifiedDate); + response->m_haveParsedCacheControl = data->m_haveParsedCacheControl; + response->m_cacheControlContainsMustRevalidate = data->m_cacheControlContainsMustRevalidate; + response->m_cacheControlContainsNoCache = data->m_cacheControlContainsNoCache; + return response; +} + +auto_ptr<CrossThreadResourceResponseData> ResourceResponseBase::copyData() const +{ + auto_ptr<CrossThreadResourceResponseData> data(new CrossThreadResourceResponseData()); + data->m_url = url().copy(); + data->m_mimeType = mimeType().copy(); + data->m_expectedContentLength = expectedContentLength(); + data->m_textEncodingName = textEncodingName().copy(); + data->m_suggestedFilename = suggestedFilename().copy(); + data->m_httpStatusCode = httpStatusCode(); + data->m_httpStatusText = httpStatusText().copy(); + data->m_httpHeaders.adopt(httpHeaderFields().copyData()); + data->m_expirationDate = expirationDate(); + data->m_lastModifiedDate = lastModifiedDate(); + data->m_haveParsedCacheControl = m_haveParsedCacheControl; + data->m_cacheControlContainsMustRevalidate = m_cacheControlContainsMustRevalidate; + data->m_cacheControlContainsNoCache = m_cacheControlContainsNoCache; + return data; +} + bool ResourceResponseBase::isHTTP() const { lazyInit(); @@ -142,17 +191,19 @@ void ResourceResponseBase::setHTTPStatusText(const String& statusText) m_httpStatusText = statusText; } -String ResourceResponseBase::httpHeaderField(const String& name) const +String ResourceResponseBase::httpHeaderField(const AtomicString& name) const { lazyInit(); return m_httpHeaderFields.get(name); } -void ResourceResponseBase::setHTTPHeaderField(const String& name, const String& value) +void ResourceResponseBase::setHTTPHeaderField(const AtomicString& name, const String& value) { lazyInit(); + if (equalIgnoringCase(name, "cache-control")) + m_haveParsedCacheControl = false; m_httpHeaderFields.set(name, value); } @@ -160,7 +211,42 @@ const HTTPHeaderMap& ResourceResponseBase::httpHeaderFields() const { lazyInit(); - return m_httpHeaderFields; + return m_httpHeaderFields; +} + +void ResourceResponseBase::parseCacheControlDirectives() const +{ + ASSERT(!m_haveParsedCacheControl); + + lazyInit(); + + m_haveParsedCacheControl = true; + m_cacheControlContainsMustRevalidate = false; + m_cacheControlContainsNoCache = false; + + String cacheControlValue = httpHeaderField("cache-control"); + if (cacheControlValue.isEmpty()) + return; + + // FIXME: It would probably be much more efficient to parse this without creating all these data structures. + + Vector<pair<String, String> > directives; + parseCacheHeader(cacheControlValue, directives); + + size_t directivesSize = directives.size(); + for (size_t i = 0; i < directivesSize; ++i) { + Vector<String> directiveValues; + if ((equalIgnoringCase(directives[i].first, "private") || equalIgnoringCase(directives[i].first, "no-cache")) && !directives[i].second.isEmpty()) + parseCacheControlDirectiveValues(directives[i].second, directiveValues); + else + directiveValues.append(directives[i].second); + for (size_t i = 0; i < directiveValues.size(); ++i) { + if (equalIgnoringCase(directiveValues[i], "no-cache")) + m_cacheControlContainsNoCache = true; + else if (equalIgnoringCase(directiveValues[i], "must-revalidate")) + m_cacheControlContainsMustRevalidate = true; + } + } } bool ResourceResponseBase::isAttachment() const @@ -233,4 +319,107 @@ bool ResourceResponseBase::compare(const ResourceResponse& a, const ResourceResp return ResourceResponse::platformCompare(a, b); } +static bool isCacheHeaderSeparator(UChar c) +{ + // See RFC 2616, Section 2.2 + switch (c) { + case '(': + case ')': + case '<': + case '>': + case '@': + case ',': + case ';': + case ':': + case '\\': + case '"': + case '/': + case '[': + case ']': + case '?': + case '=': + case '{': + case '}': + case ' ': + case '\t': + return true; + default: + return false; + } +} + +static bool isControlCharacter(UChar c) +{ + return c < ' ' || c == 127; +} + +static inline String trimToNextSeparator(const String& str) +{ + return str.substring(0, str.find(isCacheHeaderSeparator, 0)); +} + +static void parseCacheHeader(const String& header, Vector<pair<String, String> >& result) +{ + const String safeHeader = header.removeCharacters(isControlCharacter); + unsigned max = safeHeader.length(); + for (unsigned pos = 0; pos < max; /* pos incremented in loop */) { + int nextCommaPosition = safeHeader.find(',', pos); + int nextEqualSignPosition = safeHeader.find('=', pos); + if (nextEqualSignPosition >= 0 && (nextEqualSignPosition < nextCommaPosition || nextCommaPosition < 0)) { + // Get directive name, parse right hand side of equal sign, then add to map + String directive = trimToNextSeparator(safeHeader.substring(pos, nextEqualSignPosition - pos).stripWhiteSpace()); + pos += nextEqualSignPosition - pos + 1; + + String value = safeHeader.substring(pos, max - pos).stripWhiteSpace(); + if (value[0] == '"') { + // The value is a quoted string + int nextDoubleQuotePosition = value.find('"', 1); + if (nextDoubleQuotePosition >= 0) { + // Store the value as a quoted string without quotes + result.append(pair<String, String>(directive, value.substring(1, nextDoubleQuotePosition - 1).stripWhiteSpace())); + pos += (safeHeader.find('"', pos) - pos) + nextDoubleQuotePosition + 1; + // Move past next comma, if there is one + int nextCommaPosition2 = safeHeader.find(',', pos); + if (nextCommaPosition2 >= 0) + pos += nextCommaPosition2 - pos + 1; + else + return; // Parse error if there is anything left with no comma + } else { + // Parse error; just use the rest as the value + result.append(pair<String, String>(directive, trimToNextSeparator(value.substring(1, value.length() - 1).stripWhiteSpace()))); + return; + } + } else { + // The value is a token until the next comma + int nextCommaPosition2 = value.find(',', 0); + if (nextCommaPosition2 >= 0) { + // The value is delimited by the next comma + result.append(pair<String, String>(directive, trimToNextSeparator(value.substring(0, nextCommaPosition2).stripWhiteSpace()))); + pos += (safeHeader.find(',', pos) - pos) + 1; + } else { + // The rest is the value; no change to value needed + result.append(pair<String, String>(directive, trimToNextSeparator(value))); + return; + } + } + } else if (nextCommaPosition >= 0 && (nextCommaPosition < nextEqualSignPosition || nextEqualSignPosition < 0)) { + // Add directive to map with empty string as value + result.append(pair<String, String>(trimToNextSeparator(safeHeader.substring(pos, nextCommaPosition - pos).stripWhiteSpace()), "")); + pos += nextCommaPosition - pos + 1; + } else { + // Add last directive to map with empty string as value + result.append(pair<String, String>(trimToNextSeparator(safeHeader.substring(pos, max - pos).stripWhiteSpace()), "")); + return; + } + } +} + +static void parseCacheControlDirectiveValues(const String& directives, Vector<String>& result) +{ + directives.split(',', false, result); + unsigned max = result.size(); + for (unsigned i = 0; i < max; ++i) + result[i] = result[i].stripWhiteSpace(); +} + } diff --git a/WebCore/platform/network/ResourceResponseBase.h b/WebCore/platform/network/ResourceResponseBase.h index 06b0499..abc756e 100644 --- a/WebCore/platform/network/ResourceResponseBase.h +++ b/WebCore/platform/network/ResourceResponseBase.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006, 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 @@ -29,13 +30,20 @@ #include "HTTPHeaderMap.h" #include "KURL.h" +#include <memory> + namespace WebCore { class ResourceResponse; +struct CrossThreadResourceResponseData; // Do not use this class directly, use the class ResponseResponse instead class ResourceResponseBase { - public: +public: + static std::auto_ptr<ResourceResponse> adopt(std::auto_ptr<CrossThreadResourceResponseData>); + + // Gets a copy of the data suitable for passing to another thread. + std::auto_ptr<CrossThreadResourceResponseData> copyData() const; bool isNull() const { return m_isNull; } bool isHTTP() const; @@ -62,8 +70,8 @@ class ResourceResponseBase { const String& httpStatusText() const; void setHTTPStatusText(const String&); - String httpHeaderField(const String& name) const; - void setHTTPHeaderField(const String& name, const String& value); + String httpHeaderField(const AtomicString& name) const; + void setHTTPHeaderField(const AtomicString& name, const String& value); const HTTPHeaderMap& httpHeaderFields() const; bool isMultipart() const { return mimeType() == "multipart/x-mixed-replace"; } @@ -76,15 +84,29 @@ class ResourceResponseBase { void setLastModifiedDate(time_t); time_t lastModifiedDate() const; + bool cacheControlContainsNoCache() const + { + if (!m_haveParsedCacheControl) + parseCacheControlDirectives(); + return m_cacheControlContainsMustRevalidate; + } + bool cacheControlContainsMustRevalidate() const + { + if (!m_haveParsedCacheControl) + parseCacheControlDirectives(); + return m_cacheControlContainsMustRevalidate; + } + static bool compare(const ResourceResponse& a, const ResourceResponse& b); - protected: +protected: ResourceResponseBase() : m_expectedContentLength(0) , m_httpStatusCode(0) , m_expirationDate(0) , m_lastModifiedDate(0) , m_isNull(true) + , m_haveParsedCacheControl(false) { } @@ -98,16 +120,17 @@ class ResourceResponseBase { , m_expirationDate(0) , m_lastModifiedDate(0) , m_isNull(false) + , m_haveParsedCacheControl(false) { } void lazyInit() const; // The ResourceResponse subclass may "shadow" this method to lazily initialize platform specific fields - void platformLazyInit() {} + void platformLazyInit() { } // The ResourceResponse subclass may "shadow" this method to compare platform specific fields - static bool platformCompare(const ResourceResponse& a, const ResourceResponse& b) { return true; } + static bool platformCompare(const ResourceResponse&, const ResourceResponse&) { return true; } KURL m_url; String m_mimeType; @@ -119,13 +142,35 @@ class ResourceResponseBase { HTTPHeaderMap m_httpHeaderFields; time_t m_expirationDate; time_t m_lastModifiedDate; - bool m_isNull; + bool m_isNull : 1; + +private: + void parseCacheControlDirectives() const; + mutable bool m_haveParsedCacheControl : 1; + mutable bool m_cacheControlContainsMustRevalidate : 1; + mutable bool m_cacheControlContainsNoCache : 1; }; inline bool operator==(const ResourceResponse& a, const ResourceResponse& b) { return ResourceResponseBase::compare(a, b); } inline bool operator!=(const ResourceResponse& a, const ResourceResponse& b) { return !(a == b); } +struct CrossThreadResourceResponseData { + KURL m_url; + String m_mimeType; + long long m_expectedContentLength; + String m_textEncodingName; + String m_suggestedFilename; + int m_httpStatusCode; + String m_httpStatusText; + OwnPtr<CrossThreadHTTPHeaderMapData> m_httpHeaders; + time_t m_expirationDate; + time_t m_lastModifiedDate; + bool m_haveParsedCacheControl : 1; + bool m_cacheControlContainsMustRevalidate : 1; + bool m_cacheControlContainsNoCache : 1; +}; + } // namespace WebCore #endif // ResourceResponseBase_h diff --git a/WebCore/platform/network/cf/DNSCFNet.cpp b/WebCore/platform/network/cf/DNSCFNet.cpp index e571494..bf21ab1 100644 --- a/WebCore/platform/network/cf/DNSCFNet.cpp +++ b/WebCore/platform/network/cf/DNSCFNet.cpp @@ -30,7 +30,7 @@ namespace WebCore { -void prefetchDNS(const String& hostname) +void prefetchDNS(const String&) { notImplemented(); } diff --git a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp index fa7947f..a4000a3 100644 --- a/WebCore/platform/network/cf/ResourceHandleCFNet.cpp +++ b/WebCore/platform/network/cf/ResourceHandleCFNet.cpp @@ -53,6 +53,51 @@ namespace WebCore { +static HMODULE findCFNetworkModule() +{ + if (HMODULE module = GetModuleHandleA("CFNetwork")) + return module; + return GetModuleHandleA("CFNetwork_debug"); +} + +static DWORD cfNetworkVersion() +{ + HMODULE cfNetworkModule = findCFNetworkModule(); + WCHAR filename[MAX_PATH]; + GetModuleFileName(cfNetworkModule, filename, MAX_PATH); + DWORD handle; + DWORD versionInfoSize = GetFileVersionInfoSize(filename, &handle); + Vector<BYTE> versionInfo(versionInfoSize); + GetFileVersionInfo(filename, handle, versionInfoSize, versionInfo.data()); + VS_FIXEDFILEINFO* fixedFileInfo; + UINT fixedFileInfoLength; + VerQueryValue(versionInfo.data(), TEXT("\\"), reinterpret_cast<LPVOID*>(&fixedFileInfo), &fixedFileInfoLength); + return fixedFileInfo->dwProductVersionMS; +} + +static CFIndex highestSupportedCFURLConnectionClientVersion() +{ + const DWORD firstCFNetworkVersionWithConnectionClientV2 = 0x000101a8; // 1.424 + const DWORD firstCFNetworkVersionWithConnectionClientV3 = 0x000101ad; // 1.429 + +#ifndef _CFURLConnectionClientV2Present + return 1; +#else + + DWORD version = cfNetworkVersion(); + if (version < firstCFNetworkVersionWithConnectionClientV2) + return 1; +#ifndef _CFURLConnectionClientV3Present + return 2; +#else + + if (version < firstCFNetworkVersionWithConnectionClientV3) + return 2; + return 3; +#endif // _CFURLConnectionClientV3Present +#endif // _CFURLConnectionClientV2Present +} + static HashSet<String>& allowsAnyHTTPSCertificateHosts() { static HashSet<String> hosts; @@ -109,6 +154,30 @@ void didReceiveData(CFURLConnectionRef conn, CFDataRef data, CFIndex originalLen handle->client()->didReceiveData(handle, (const char*)bytes, length, originalLength); } +#ifdef _CFURLConnectionClientV2Present +static void didSendBodyData(CFURLConnectionRef conn, CFIndex bytesWritten, CFIndex totalBytesWritten, CFIndex totalBytesExpectedToWrite, const void *clientInfo) +{ + ResourceHandle* handle = (ResourceHandle*)clientInfo; + if (!handle || !handle->client()) + return; + handle->client()->didSendData(handle, totalBytesWritten, totalBytesExpectedToWrite); +} +#endif + +#ifdef _CFURLConnectionClientV3Present +static Boolean shouldUseCredentialStorageCallback(CFURLConnectionRef conn, const void* clientInfo) +{ + ResourceHandle* handle = const_cast<ResourceHandle*>(static_cast<const ResourceHandle*>(clientInfo)); + + LOG(Network, "CFNet - shouldUseCredentialStorage(conn=%p, handle=%p) (%s)", conn, handle, handle->request().url().string().utf8().data()); + + if (!handle) + return false; + + return handle->shouldUseCredentialStorage(); +} +#endif + void didFinishLoading(CFURLConnectionRef conn, const void* clientInfo) { ResourceHandle* handle = (ResourceHandle*)clientInfo; @@ -279,11 +348,20 @@ bool ResourceHandle::start(Frame* frame) RetainPtr<CFURLRequestRef> request(AdoptCF, makeFinalRequest(d->m_request, d->m_shouldContentSniff)); - // CFURLConnection Callback API currently at version 1 - const int CFURLConnectionClientVersion = 1; - CFURLConnectionClient client = {CFURLConnectionClientVersion, this, 0, 0, 0, willSendRequest, didReceiveResponse, didReceiveData, NULL, didFinishLoading, didFail, willCacheResponse, didReceiveChallenge}; - - d->m_connection.adoptCF(CFURLConnectionCreate(0, request.get(), &client)); + static CFIndex clientVersion = highestSupportedCFURLConnectionClientVersion(); + CFURLConnectionClient* client; +#if defined(_CFURLConnectionClientV3Present) + CFURLConnectionClient_V3 client_V3 = {clientVersion, this, 0, 0, 0, willSendRequest, didReceiveResponse, didReceiveData, NULL, didFinishLoading, didFail, willCacheResponse, didReceiveChallenge, didSendBodyData, shouldUseCredentialStorageCallback, 0}; + client = reinterpret_cast<CFURLConnectionClient*>(&client_V3); +#elif defined(_CFURLConnectionClientV2Present) + CFURLConnectionClient_V2 client_V2 = {clientVersion, this, 0, 0, 0, willSendRequest, didReceiveResponse, didReceiveData, NULL, didFinishLoading, didFail, willCacheResponse, didReceiveChallenge, didSendBodyData}; + client = reinterpret_cast<CFURLConnectionClient*>(&client_V2); +#else + CFURLConnectionClient client_V1 = {1, this, 0, 0, 0, willSendRequest, didReceiveResponse, didReceiveData, NULL, didFinishLoading, didFail, willCacheResponse, didReceiveChallenge}; + client = &client_V1; +#endif + + d->m_connection.adoptCF(CFURLConnectionCreate(0, request.get(), client)); CFURLConnectionScheduleWithCurrentMessageQueue(d->m_connection.get()); CFURLConnectionScheduleDownloadWithRunLoop(d->m_connection.get(), loaderRunLoop(), kCFRunLoopDefaultMode); @@ -313,6 +391,15 @@ bool ResourceHandle::supportsBufferedData() return false; } +bool ResourceHandle::shouldUseCredentialStorage() +{ + LOG(Network, "CFNet - shouldUseCredentialStorage()"); + if (client()) + return client()->shouldUseCredentialStorage(this); + + return false; +} + void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge) { LOG(Network, "CFNet - didReceiveAuthenticationChallenge()"); diff --git a/WebCore/platform/network/cf/ResourceRequestCFNet.cpp b/WebCore/platform/network/cf/ResourceRequestCFNet.cpp index b73df13..df6bbf9 100644 --- a/WebCore/platform/network/cf/ResourceRequestCFNet.cpp +++ b/WebCore/platform/network/cf/ResourceRequestCFNet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,6 +33,41 @@ namespace WebCore { +typedef void (*CFURLRequestSetContentDispositionEncodingFallbackArrayFunction)(CFMutableURLRequestRef, CFArrayRef); +typedef CFArrayRef (*CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction)(CFURLRequestRef); + +static HMODULE findCFNetworkModule() +{ + if (HMODULE module = GetModuleHandleA("CFNetwork")) + return module; + return GetModuleHandleA("CFNetwork_debug"); +} + +static CFURLRequestSetContentDispositionEncodingFallbackArrayFunction findCFURLRequestSetContentDispositionEncodingFallbackArrayFunction() +{ + return reinterpret_cast<CFURLRequestSetContentDispositionEncodingFallbackArrayFunction>(GetProcAddress(findCFNetworkModule(), "_CFURLRequestSetContentDispositionEncodingFallbackArray")); +} + +static CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction findCFURLRequestCopyContentDispositionEncodingFallbackArrayFunction() +{ + return reinterpret_cast<CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction>(GetProcAddress(findCFNetworkModule(), "_CFURLRequestCopyContentDispositionEncodingFallbackArray")); +} + +static void setContentDispositionEncodingFallbackArray(CFMutableURLRequestRef request, CFArrayRef fallbackArray) +{ + static CFURLRequestSetContentDispositionEncodingFallbackArrayFunction function = findCFURLRequestSetContentDispositionEncodingFallbackArrayFunction(); + if (function) + function(request, fallbackArray); +} + +static CFArrayRef copyContentDispositionEncodingFallbackArray(CFURLRequestRef request) +{ + static CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction function = findCFURLRequestCopyContentDispositionEncodingFallbackArrayFunction(); + if (!function) + return 0; + return function(request); +} + CFURLRequestRef ResourceRequest::cfURLRequest() const { updatePlatformRequest(); @@ -76,6 +111,16 @@ void ResourceRequest::doUpdatePlatformRequest() WebCore::setHTTPBody(cfRequest, httpBody()); CFURLRequestSetShouldHandleHTTPCookies(cfRequest, allowHTTPCookies()); + unsigned fallbackCount = m_responseContentDispositionEncodingFallbackArray.size(); + RetainPtr<CFMutableArrayRef> encodingFallbacks(AdoptCF, CFArrayCreateMutable(kCFAllocatorDefault, fallbackCount, 0)); + for (unsigned i = 0; i != fallbackCount; ++i) { + RetainPtr<CFStringRef> encodingName(AdoptCF, m_responseContentDispositionEncodingFallbackArray[i].createCFString()); + CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding(encodingName.get()); + if (encoding != kCFStringEncodingInvalidId) + CFArrayAppendValue(encodingFallbacks.get(), reinterpret_cast<const void*>(encoding)); + } + setContentDispositionEncodingFallbackArray(cfRequest, encodingFallbacks.get()); + if (m_cfRequest) { RetainPtr<CFHTTPCookieStorageRef> cookieStorage(AdoptCF, CFURLRequestCopyHTTPCookieStorage(m_cfRequest.get())); if (cookieStorage) @@ -110,6 +155,17 @@ void ResourceRequest::doUpdateResourceRequest() CFRelease(headers); } + m_responseContentDispositionEncodingFallbackArray.clear(); + RetainPtr<CFArrayRef> encodingFallbacks(AdoptCF, copyContentDispositionEncodingFallbackArray(m_cfRequest.get())); + if (encodingFallbacks) { + CFIndex count = CFArrayGetCount(encodingFallbacks.get()); + for (CFIndex i = 0; i < count; ++i) { + CFStringEncoding encoding = reinterpret_cast<CFIndex>(CFArrayGetValueAtIndex(encodingFallbacks.get(), i)); + if (encoding != kCFStringEncodingInvalidId) + m_responseContentDispositionEncodingFallbackArray.append(CFStringGetNameOfEncoding(encoding)); + } + } + m_httpBody = httpBodyFromRequest(m_cfRequest.get()); } diff --git a/WebCore/platform/network/chromium/AuthenticationChallenge.h b/WebCore/platform/network/chromium/AuthenticationChallenge.h new file mode 100644 index 0000000..cd1b430 --- /dev/null +++ b/WebCore/platform/network/chromium/AuthenticationChallenge.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2008 Google, 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. + */ + +#ifndef AuthenticationChallenge_h +#define AuthenticationChallenge_h + +#include "AuthenticationChallengeBase.h" +#include "ResourceHandle.h" +#include <wtf/RefPtr.h> + +namespace WebCore { + + class ResourceHandle; + + class AuthenticationChallenge : public AuthenticationChallengeBase { + public: + AuthenticationChallenge() {} + AuthenticationChallenge(const ProtectionSpace&, const Credential& proposedCredential, unsigned previousFailureCount, const ResourceResponse&, const ResourceError&); + + ResourceHandle* sourceHandle() const { return m_sourceHandle.get(); } + + private: + friend class AuthenticationChallengeBase; + static bool platformCompare(const AuthenticationChallenge&, const AuthenticationChallenge&); + + RefPtr<ResourceHandle> m_sourceHandle; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/network/chromium/AuthenticationChallengeChromium.cpp b/WebCore/platform/network/chromium/AuthenticationChallengeChromium.cpp new file mode 100644 index 0000000..3c13b39 --- /dev/null +++ b/WebCore/platform/network/chromium/AuthenticationChallengeChromium.cpp @@ -0,0 +1,41 @@ +/* + * 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 "AuthenticationChallenge.h" + +namespace WebCore { + +bool AuthenticationChallenge::platformCompare(const AuthenticationChallenge&, const AuthenticationChallenge&) +{ + return true; +} + +} // namespace WebCore diff --git a/WebCore/platform/network/chromium/CookieJarChromium.cpp b/WebCore/platform/network/chromium/CookieJarChromium.cpp new file mode 100644 index 0000000..50cab3b --- /dev/null +++ b/WebCore/platform/network/chromium/CookieJarChromium.cpp @@ -0,0 +1,57 @@ +/* + * 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 "CookieJar.h" + +#include "ChromiumBridge.h" +#include "Document.h" + +namespace WebCore { + +void setCookies(Document* document, const KURL& url, const KURL& policyURL, const String& value) +{ + // We ignore the policyURL and compute it directly ourselves to ensure + // consistency with the cookies() method below. + ChromiumBridge::setCookies(url, document->policyBaseURL(), value); +} + +String cookies(const Document* document, const KURL& url) +{ + return ChromiumBridge::cookies(url, document->policyBaseURL()); +} + +bool cookiesEnabled(const Document*) +{ + // FIXME: For now just assume cookies are always on. + return true; +} + +} // namespace WebCore diff --git a/WebCore/platform/network/chromium/DNSChromium.cpp b/WebCore/platform/network/chromium/DNSChromium.cpp new file mode 100644 index 0000000..4da29e1 --- /dev/null +++ b/WebCore/platform/network/chromium/DNSChromium.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2008 Collin Jackson <collinj@webkit.org> + * + * 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 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 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 "DNS.h" + +#include "ChromiumBridge.h" + +namespace WebCore { + +void prefetchDNS(const String& hostname) +{ + ChromiumBridge::prefetchDNS(hostname); +} + +} // namespace WebCore diff --git a/WebCore/platform/network/chromium/NetworkStateNotifierChromium.cpp b/WebCore/platform/network/chromium/NetworkStateNotifierChromium.cpp new file mode 100644 index 0000000..3b28fbd --- /dev/null +++ b/WebCore/platform/network/chromium/NetworkStateNotifierChromium.cpp @@ -0,0 +1,50 @@ +/* + * 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 "NetworkStateNotifier.h" + +namespace WebCore { + +// Chromium doesn't currently support network state notifications. This causes +// an extra DLL to get loaded into the renderer which can slow things down a +// bit. We may want an alternate design. + +void NetworkStateNotifier::updateState() +{ +} + +NetworkStateNotifier::NetworkStateNotifier() + : m_isOnLine(true) + , m_networkStateChangedFunction(0) +{ +} + +} // namespace WebCore diff --git a/WebCore/platform/network/chromium/NetworkStateNotifierPrivate.h b/WebCore/platform/network/chromium/NetworkStateNotifierPrivate.h new file mode 100644 index 0000000..7628d59 --- /dev/null +++ b/WebCore/platform/network/chromium/NetworkStateNotifierPrivate.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#ifndef NetworkStateNotifierPrivate_h +#define NetworkStateNotifierPrivate_h + +namespace WebCore { + + struct NetworkStateNotifierPrivate {}; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/network/chromium/ResourceError.h b/WebCore/platform/network/chromium/ResourceError.h new file mode 100644 index 0000000..a1fbe11 --- /dev/null +++ b/WebCore/platform/network/chromium/ResourceError.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008 Google, 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. + */ + +#ifndef ResourceError_h +#define ResourceError_h + +#include "ResourceErrorBase.h" + +namespace WebCore { + + class ResourceError : public ResourceErrorBase { + public: + ResourceError() + { + } + + ResourceError(const String& domain, int errorCode, const String& failingURL, const String& localizedDescription) + : ResourceErrorBase(domain, errorCode, failingURL, localizedDescription) + { + } + + private: + friend class ResourceErrorBase; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/network/chromium/ResourceRequest.h b/WebCore/platform/network/chromium/ResourceRequest.h new file mode 100644 index 0000000..76b8b99 --- /dev/null +++ b/WebCore/platform/network/chromium/ResourceRequest.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> + * Copyright (C) 2008 Google, 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. + */ + +#ifndef ResourceRequest_h +#define ResourceRequest_h + +#include "CString.h" +#include "ResourceRequestBase.h" + +namespace WebCore { + + class Frame; + + class ResourceRequest : public ResourceRequestBase { + public: + enum TargetType { + TargetIsMainFrame, + TargetIsSubFrame, + TargetIsSubResource, + TargetIsObject, + TargetIsMedia + }; + + ResourceRequest(const String& url) + : ResourceRequestBase(KURL(url), UseProtocolCachePolicy) + , m_frame(0) + , m_originPid(0) + , m_targetType(TargetIsSubResource) + { + } + + ResourceRequest(const KURL& url, const CString& securityInfo) + : ResourceRequestBase(url, UseProtocolCachePolicy) + , m_frame(0) + , m_originPid(0) + , m_targetType(TargetIsSubResource) + , m_securityInfo(securityInfo) + { + } + + ResourceRequest(const KURL& url) + : ResourceRequestBase(url, UseProtocolCachePolicy) + , m_frame(0) + , m_originPid(0) + , m_targetType(TargetIsSubResource) + { + } + + ResourceRequest(const KURL& url, const String& referrer, ResourceRequestCachePolicy policy = UseProtocolCachePolicy) + : ResourceRequestBase(url, policy) + , m_frame(0) + , m_originPid(0) + , m_targetType(TargetIsSubResource) + { + setHTTPReferrer(referrer); + } + + ResourceRequest() + : ResourceRequestBase(KURL(), UseProtocolCachePolicy) + , m_frame(0) + , m_originPid(0) + , m_targetType(TargetIsSubResource) + { + } + + // Provides context for the resource request. + Frame* frame() const { return m_frame; } + void setFrame(Frame* frame) { m_frame = frame; } + + // What this request is for. + void setTargetType(TargetType type) { m_targetType = type; } + TargetType targetType() const { return m_targetType; } + + // The origin pid is the process id of the process from which this + // request originated. In the case of out-of-process plugins, this + // allows to link back the request to the plugin process (as it is + // processed through a render view process). + int originPid() const { return m_originPid; } + void setOriginPid(int originPid) { m_originPid = originPid; } + + // Opaque buffer that describes the security state (including SSL + // connection state) for the resource that should be reported when the + // resource has been loaded. This is used to simulate secure + // connection for request (typically when showing error page, so the + // error page has the errors of the page that actually failed). Empty + // string if not a secure connection. + CString securityInfo() const { return m_securityInfo; } + void setSecurityInfo(const CString& value) { m_securityInfo = value; } + + private: + friend class ResourceRequestBase; + + void doUpdatePlatformRequest() {} + void doUpdateResourceRequest() {} + + Frame* m_frame; + int m_originPid; + TargetType m_targetType; + CString m_securityInfo; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/network/chromium/ResourceResponse.h b/WebCore/platform/network/chromium/ResourceResponse.h new file mode 100644 index 0000000..256df74 --- /dev/null +++ b/WebCore/platform/network/chromium/ResourceResponse.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008 Google, 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. + */ + +#ifndef ResourceResponse_h +#define ResourceResponse_h + +#include "CString.h" +#include "NotImplemented.h" +#include "ResourceResponseBase.h" + +namespace WebCore { + + class ResourceResponse : public ResourceResponseBase { + public: + ResourceResponse() + : m_isContentFiltered(false) + { + } + + ResourceResponse(const KURL& url, const String& mimeType, long long expectedLength, const String& textEncodingName, const String& filename) + : ResourceResponseBase(url, mimeType, expectedLength, textEncodingName, filename), + m_isContentFiltered(false) + { + } + + const CString& getSecurityInfo() const { return m_securityInfo; } + void setSecurityInfo(const CString& securityInfo) + { + m_securityInfo = securityInfo; + } + + bool isContentFiltered() const { return m_isContentFiltered; } + void setIsContentFiltered(bool isContentFiltered) + { + m_isContentFiltered = isContentFiltered; + } + + private: + friend class ResourceResponseBase; + + // An opaque value that contains some information regarding the security of + // the connection for this request, such as SSL connection info (empty + // string if not over HTTPS). + CString m_securityInfo; + + void doUpdateResourceResponse() + { + notImplemented(); + } + + // Whether the contents for this response has been altered/blocked (usually + // for security reasons. + bool m_isContentFiltered; + }; + +} // namespace WebCore + +#endif diff --git a/WebCore/platform/network/curl/ResourceHandleCurl.cpp b/WebCore/platform/network/curl/ResourceHandleCurl.cpp index bbc31d4..ca24ec5 100644 --- a/WebCore/platform/network/curl/ResourceHandleCurl.cpp +++ b/WebCore/platform/network/curl/ResourceHandleCurl.cpp @@ -104,7 +104,6 @@ ResourceHandle::~ResourceHandle() bool ResourceHandle::start(Frame* frame) { ASSERT(frame); - ref(); ResourceHandleManager::sharedInstance()->add(this); return true; } diff --git a/WebCore/platform/network/curl/ResourceHandleManager.cpp b/WebCore/platform/network/curl/ResourceHandleManager.cpp index b022913..6a44233 100644 --- a/WebCore/platform/network/curl/ResourceHandleManager.cpp +++ b/WebCore/platform/network/curl/ResourceHandleManager.cpp @@ -43,6 +43,7 @@ #include "TextEncoding.h" #include <errno.h> +#include <stdio.h> #include <wtf/Vector.h> #if PLATFORM(GTK) @@ -263,8 +264,7 @@ void ResourceHandleManager::downloadTimerCallback(Timer<ResourceHandleManager>* timeout.tv_sec = 0; timeout.tv_usec = selectTimeoutMS * 1000; // select waits microseconds - // Temporarily disable timers since signals may interrupt select(), raising EINTR errors on some platforms - setDeferringTimers(true); + // Retry 'select' if it was interrupted by a process signal. int rc = 0; do { FD_ZERO(&fdread); @@ -277,7 +277,6 @@ void ResourceHandleManager::downloadTimerCallback(Timer<ResourceHandleManager>* if (maxfd >= 0) rc = ::select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout); } while (rc == -1 && errno == EINTR); - setDeferringTimers(false); if (-1 == rc) { #ifndef NDEBUG @@ -324,7 +323,7 @@ void ResourceHandleManager::downloadTimerCallback(Timer<ResourceHandleManager>* #ifndef NDEBUG char* url = 0; curl_easy_getinfo(d->m_handle, CURLINFO_EFFECTIVE_URL, &url); - printf("Curl ERROR for url='%s', error: '%s'\n", url, curl_easy_strerror(msg->data.result)); + fprintf(stderr, "Curl ERROR for url='%s', error: '%s'\n", url, curl_easy_strerror(msg->data.result)); #endif if (d->client()) d->client()->didFail(job, ResourceError()); @@ -349,6 +348,7 @@ void ResourceHandleManager::removeFromCurl(ResourceHandle* job) curl_multi_remove_handle(m_curlMultiHandle, d->m_handle); curl_easy_cleanup(d->m_handle); d->m_handle = 0; + job->deref(); } void ResourceHandleManager::setupPUT(ResourceHandle*, struct curl_slist**) @@ -362,12 +362,14 @@ void ResourceHandleManager::setupPUT(ResourceHandle*, struct curl_slist**) void ResourceHandleManager::setupPOST(ResourceHandle* job, struct curl_slist** headers) { ResourceHandleInternal* d = job->getInternal(); - Vector<FormDataElement> elements; - // Fix crash when httpBody is null (see bug #16906). - if (job->request().httpBody()) - elements = job->request().httpBody()->elements(); - size_t numElements = elements.size(); + curl_easy_setopt(d->m_handle, CURLOPT_POST, TRUE); + curl_easy_setopt(d->m_handle, CURLOPT_POSTFIELDSIZE, 0); + + if (!job->request().httpBody()) + return; + Vector<FormDataElement> elements = job->request().httpBody()->elements(); + size_t numElements = elements.size(); if (!numElements) return; @@ -375,7 +377,6 @@ void ResourceHandleManager::setupPOST(ResourceHandle* job, struct curl_slist** h if (numElements == 1) { job->request().httpBody()->flatten(d->m_postBytes); if (d->m_postBytes.size() != 0) { - curl_easy_setopt(d->m_handle, CURLOPT_POST, TRUE); curl_easy_setopt(d->m_handle, CURLOPT_POSTFIELDSIZE, d->m_postBytes.size()); curl_easy_setopt(d->m_handle, CURLOPT_POSTFIELDS, d->m_postBytes.data()); } @@ -422,8 +423,6 @@ void ResourceHandleManager::setupPOST(ResourceHandle* job, struct curl_slist** h size += elements[i].m_data.size(); } - curl_easy_setopt(d->m_handle, CURLOPT_POST, TRUE); - // cURL guesses that we want chunked encoding as long as we specify the header if (chunkedTransfer) *headers = curl_slist_append(*headers, "Transfer-Encoding: chunked"); @@ -442,6 +441,7 @@ void ResourceHandleManager::add(ResourceHandle* job) { // we can be called from within curl, so to avoid re-entrancy issues // schedule this job to be added the next time we enter curl download loop + job->ref(); m_resourceHandleList.append(job); if (!m_downloadTimer.isActive()) m_downloadTimer.startOneShot(pollTimeSeconds); @@ -453,6 +453,7 @@ bool ResourceHandleManager::removeScheduledJob(ResourceHandle* job) for (int i = 0; i < size; i++) { if (job == m_resourceHandleList[i]) { m_resourceHandleList.remove(i); + job->deref(); return true; } } @@ -585,7 +586,7 @@ void ResourceHandleManager::startJob(ResourceHandle* job) // timeout will occur and do curl_multi_perform if (ret && ret != CURLM_CALL_MULTI_PERFORM) { #ifndef NDEBUG - printf("Error %d starting job %s\n", ret, encodeWithURLEscapeSequences(job->request().url().string()).latin1().data()); + fprintf(stderr, "Error %d starting job %s\n", ret, encodeWithURLEscapeSequences(job->request().url().string()).latin1().data()); #endif job->cancel(); return; diff --git a/WebCore/platform/network/mac/FormDataStreamMac.mm b/WebCore/platform/network/mac/FormDataStreamMac.mm index 3ef224d..b618949 100644 --- a/WebCore/platform/network/mac/FormDataStreamMac.mm +++ b/WebCore/platform/network/mac/FormDataStreamMac.mm @@ -42,6 +42,7 @@ #import <wtf/Assertions.h> #import <wtf/HashMap.h> #import <wtf/MainThread.h> +#import <wtf/StdLibExtras.h> #import <wtf/Threading.h> namespace WebCore { @@ -49,14 +50,14 @@ namespace WebCore { typedef HashMap<CFReadStreamRef, RefPtr<FormData> > StreamFormDataMap; static StreamFormDataMap& getStreamFormDataMap() { - static StreamFormDataMap streamFormDataMap; + DEFINE_STATIC_LOCAL(StreamFormDataMap, streamFormDataMap, ()); return streamFormDataMap; } typedef HashMap<CFReadStreamRef, RefPtr<ResourceHandle> > StreamResourceHandleMap; static StreamResourceHandleMap& getStreamResourceHandleMap() { - static StreamResourceHandleMap streamResourceHandleMap; + DEFINE_STATIC_LOCAL(StreamResourceHandleMap, streamResourceHandleMap, ()); return streamResourceHandleMap; } @@ -222,7 +223,7 @@ static void formFinalize(CFReadStreamRef stream, void* context) delete form; } -static Boolean formOpen(CFReadStreamRef stream, CFStreamError* error, Boolean* openComplete, void* context) +static Boolean formOpen(CFReadStreamRef, CFStreamError* error, Boolean* openComplete, void* context) { FormStreamFields* form = static_cast<FormStreamFields*>(context); @@ -278,14 +279,14 @@ static Boolean formCanRead(CFReadStreamRef stream, void* context) return CFReadStreamHasBytesAvailable(form->currentStream); } -static void formClose(CFReadStreamRef stream, void* context) +static void formClose(CFReadStreamRef, void* context) { FormStreamFields* form = static_cast<FormStreamFields*>(context); closeCurrentStream(form); } -static void formSchedule(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void* context) +static void formSchedule(CFReadStreamRef, CFRunLoopRef runLoop, CFStringRef runLoopMode, void* context) { FormStreamFields* form = static_cast<FormStreamFields*>(context); @@ -294,7 +295,7 @@ static void formSchedule(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringR form->scheduledRunLoopPairs.add(SchedulePair::create(runLoop, runLoopMode)); } -static void formUnschedule(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void* context) +static void formUnschedule(CFReadStreamRef, CFRunLoopRef runLoop, CFStringRef runLoopMode, void* context) { FormStreamFields* form = static_cast<FormStreamFields*>(context); diff --git a/WebCore/platform/network/mac/NetworkStateNotifierMac.cpp b/WebCore/platform/network/mac/NetworkStateNotifierMac.cpp index 6e0b70d..c0918a4 100644 --- a/WebCore/platform/network/mac/NetworkStateNotifierMac.cpp +++ b/WebCore/platform/network/mac/NetworkStateNotifierMac.cpp @@ -28,6 +28,11 @@ #include <SystemConfiguration/SystemConfiguration.h> +#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 { static const double StateChangeTimerInterval = 2.0; @@ -71,7 +76,7 @@ void NetworkStateNotifier::updateState() } } -void NetworkStateNotifier::dynamicStoreCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info) +void NetworkStateNotifier::dynamicStoreCallback(SCDynamicStoreRef, CFArrayRef, void* info) { NetworkStateNotifier* notifier = static_cast<NetworkStateNotifier*>(info); @@ -95,6 +100,7 @@ void NetworkStateNotifier::networkStateChangeTimerFired(Timer<NetworkStateNotifi NetworkStateNotifier::NetworkStateNotifier() : m_isOnLine(false) + , m_networkStateChangedFunction(0) , m_networkStateChangeTimer(this, &NetworkStateNotifier::networkStateChangeTimerFired) { SCDynamicStoreContext context = { 0, this, 0, 0, 0 }; @@ -107,7 +113,7 @@ NetworkStateNotifier::NetworkStateNotifier() if (!configSource) return; - CFRunLoopAddSource(CFRunLoopGetCurrent(), configSource.get(), kCFRunLoopCommonModes); + CFRunLoopAddSource(CFRunLoopGetMain(), configSource.get(), kCFRunLoopCommonModes); RetainPtr<CFMutableArrayRef> keys(AdoptCF, CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks)); RetainPtr<CFMutableArrayRef> patterns(AdoptCF, CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks)); diff --git a/WebCore/platform/network/mac/ResourceHandleMac.mm b/WebCore/platform/network/mac/ResourceHandleMac.mm index b4c5ddf..9bc322d 100644 --- a/WebCore/platform/network/mac/ResourceHandleMac.mm +++ b/WebCore/platform/network/mac/ResourceHandleMac.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2004, 2006 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,7 +24,6 @@ */ #import "config.h" -#import "ResourceHandle.h" #import "ResourceHandleInternal.h" #import "AuthenticationChallenge.h" @@ -41,6 +40,7 @@ #import "SharedBuffer.h" #import "SubresourceLoader.h" #import "WebCoreSystemInterface.h" +#import <wtf/UnusedParam.h> #ifdef BUILDING_ON_TIGER typedef int NSInteger; @@ -64,6 +64,7 @@ using namespace WebCore; @end #ifndef BUILDING_ON_TIGER + @interface WebCoreSynchronousLoader : NSObject { NSURL *m_url; NSURLResponse *m_response; @@ -75,6 +76,7 @@ using namespace WebCore; @end static NSString *WebCoreSynchronousLoaderRunLoopMode = @"WebCoreSynchronousLoaderRunLoopMode"; + #endif namespace WebCore { @@ -116,12 +118,7 @@ ResourceHandle::~ResourceHandle() static const double MaxFoundationVersionWithoutdidSendBodyDataDelegate = 677.21; bool ResourceHandle::didSendBodyDataDelegateExists() { -// FIXME: Refine this check as the delegate becomes more widely available. -#ifdef BUILDING_ON_LEOPARD return NSFoundationVersionNumber > MaxFoundationVersionWithoutdidSendBodyDataDelegate; -#else - return false; -#endif } bool ResourceHandle::start(Frame* frame) @@ -140,6 +137,7 @@ bool ResourceHandle::start(Frame* frame) #ifndef NDEBUG isInitializingConnection = YES; #endif + id delegate; if (d->m_mightDownloadFromHandle) { @@ -239,6 +237,8 @@ void ResourceHandle::schedule(SchedulePair* pair) [d->m_connection.get() start]; d->m_startWhenScheduled = false; } +#else + UNUSED_PARAM(pair); #endif } @@ -247,6 +247,8 @@ void ResourceHandle::unschedule(SchedulePair* pair) #ifndef BUILDING_ON_TIGER if (NSRunLoop *runLoop = pair->nsRunLoop()) [d->m_connection.get() unscheduleFromRunLoop:runLoop forMode:(NSString *)pair->mode()]; +#else + UNUSED_PARAM(pair); #endif } @@ -363,6 +365,14 @@ void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, R error = nsError; } +bool ResourceHandle::shouldUseCredentialStorage() +{ + if (client()) + return client()->shouldUseCredentialStorage(this); + + return false; +} + void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge) { ASSERT(!d->m_currentMacChallenge); @@ -388,7 +398,7 @@ void ResourceHandle::didCancelAuthenticationChallenge(const AuthenticationChalle ASSERT(d->m_currentWebChallenge == challenge); if (client()) - client()->didCancelAuthenticationChallenge(this, d->m_currentWebChallenge); + client()->didCancelAuthenticationChallenge(this, challenge); } void ResourceHandle::receivedCredential(const AuthenticationChallenge& challenge, const Credential& credential) @@ -448,8 +458,10 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen m_handle = 0; } -- (NSURLRequest *)connection:(NSURLConnection *)con willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse +- (NSURLRequest *)connection:(NSURLConnection *)unusedConnection willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse { + UNUSED_PARAM(unusedConnection); + // the willSendRequest call may cancel this load, in which case self could be deallocated RetainPtr<WebCoreResourceHandleAsDelegate> protect(self); @@ -483,8 +495,21 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen return request.nsURLRequest(); } -- (void)connection:(NSURLConnection *)con didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)unusedConnection +{ + UNUSED_PARAM(unusedConnection); + + if (!m_handle) + return NO; + + CallbackGuard guard; + return m_handle->shouldUseCredentialStorage(); +} + +- (void)connection:(NSURLConnection *)unusedConnection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { + UNUSED_PARAM(unusedConnection); + #ifndef BUILDING_ON_TIGER if ([challenge previousFailureCount] == 0) { NSString *user = [m_url user]; @@ -507,24 +532,30 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen m_handle->didReceiveAuthenticationChallenge(core(challenge)); } -- (void)connection:(NSURLConnection *)con didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +- (void)connection:(NSURLConnection *)unusedConnection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { + UNUSED_PARAM(unusedConnection); + if (!m_handle) return; CallbackGuard guard; m_handle->didCancelAuthenticationChallenge(core(challenge)); } -- (void)connection:(NSURLConnection *)con didReceiveResponse:(NSURLResponse *)r +- (void)connection:(NSURLConnection *)unusedConnection didReceiveResponse:(NSURLResponse *)r { + UNUSED_PARAM(unusedConnection); + if (!m_handle || !m_handle->client()) return; CallbackGuard guard; m_handle->client()->didReceiveResponse(m_handle, r); } -- (void)connection:(NSURLConnection *)con didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived +- (void)connection:(NSURLConnection *)unusedConnection didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived { + UNUSED_PARAM(unusedConnection); + if (!m_handle || !m_handle->client()) return; // FIXME: If we get more than 2B bytes in a single chunk, this code won't do the right thing. @@ -534,8 +565,10 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen m_handle->client()->didReceiveData(m_handle, (const char*)[data bytes], [data length], static_cast<int>(lengthReceived)); } -- (void)connection:(NSURLConnection *)con willStopBufferingData:(NSData *)data +- (void)connection:(NSURLConnection *)unusedConnection willStopBufferingData:(NSData *)data { + UNUSED_PARAM(unusedConnection); + if (!m_handle || !m_handle->client()) return; // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing. @@ -545,16 +578,21 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen m_handle->client()->willStopBufferingData(m_handle, (const char*)[data bytes], static_cast<int>([data length])); } -- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite +- (void)connection:(NSURLConnection *)unusedConnection didSendBodyData:(NSInteger)unusedBytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite { + UNUSED_PARAM(unusedConnection); + UNUSED_PARAM(unusedBytesWritten); + if (!m_handle || !m_handle->client()) return; CallbackGuard guard; m_handle->client()->didSendData(m_handle, totalBytesWritten, totalBytesExpectedToWrite); } -- (void)connectionDidFinishLoading:(NSURLConnection *)con +- (void)connectionDidFinishLoading:(NSURLConnection *)unusedConnection { + UNUSED_PARAM(unusedConnection); + if (!m_handle || !m_handle->client()) return; CallbackGuard guard; @@ -565,8 +603,10 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen m_handle->client()->didFinishLoading(m_handle); } -- (void)connection:(NSURLConnection *)con didFailWithError:(NSError *)error +- (void)connection:(NSURLConnection *)unusedConnection didFailWithError:(NSError *)error { + UNUSED_PARAM(unusedConnection); + if (!m_handle || !m_handle->client()) return; CallbackGuard guard; @@ -611,12 +651,15 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen return [result autorelease]; } +#else + UNUSED_PARAM(connection); #endif #ifndef NDEBUG if (isInitializingConnection) LOG_ERROR("connection:willCacheResponse: was called inside of [NSURLConnection initWithRequest:delegate:] (4067625)"); #endif + if (!m_handle || !m_handle->client()) return nil; @@ -663,6 +706,7 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen @end #ifndef BUILDING_ON_TIGER + @implementation WebCoreSynchronousLoader - (BOOL)_isDone @@ -680,8 +724,11 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen [super dealloc]; } -- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)redirectResponse +- (NSURLRequest *)connection:(NSURLConnection *)unusedConnection willSendRequest:(NSURLRequest *)newRequest redirectResponse:(NSURLResponse *)unusedRedirectResponse { + UNUSED_PARAM(unusedConnection); + UNUSED_PARAM(unusedRedirectResponse); + NSURL *copy = [[newRequest URL] copy]; [m_url release]; m_url = copy; @@ -689,8 +736,10 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen return newRequest; } -- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +- (void)connection:(NSURLConnection *)unusedConnection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { + UNUSED_PARAM(unusedConnection); + if ([challenge previousFailureCount] == 0) { NSString *user = [m_url user]; NSString *password = [m_url password]; @@ -708,29 +757,37 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge]; } -- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response +- (void)connection:(NSURLConnection *)unusedConnection didReceiveResponse:(NSURLResponse *)response { + UNUSED_PARAM(unusedConnection); + NSURLResponse *r = [response copy]; [m_response release]; m_response = r; } -- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data +- (void)connection:(NSURLConnection *)unusedConnection didReceiveData:(NSData *)data { + UNUSED_PARAM(unusedConnection); + if (!m_data) m_data = [[NSMutableData alloc] init]; [m_data appendData:data]; } -- (void)connectionDidFinishLoading:(NSURLConnection *)connection +- (void)connectionDidFinishLoading:(NSURLConnection *)unusedConnection { + UNUSED_PARAM(unusedConnection); + m_isDone = YES; } -- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error +- (void)connection:(NSURLConnection *)unusedConnection didFailWithError:(NSError *)error { + UNUSED_PARAM(unusedConnection); + ASSERT(!m_error); m_error = [error retain]; @@ -776,4 +833,5 @@ void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challen } @end + #endif diff --git a/WebCore/platform/network/mac/ResourceRequestMac.mm b/WebCore/platform/network/mac/ResourceRequestMac.mm index 63fffe1..a9bbd40 100644 --- a/WebCore/platform/network/mac/ResourceRequestMac.mm +++ b/WebCore/platform/network/mac/ResourceRequestMac.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008 Apple, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,6 +31,18 @@ #import <Foundation/Foundation.h> +#ifdef BUILDING_ON_TIGER +typedef unsigned NSUInteger; +#endif + +@interface NSURLRequest (WebCoreContentDispositionEncoding) +- (NSArray *)contentDispositionEncodingFallbackArray; +@end + +@interface NSMutableURLRequest (WebCoreContentDispositionEncoding) +- (void)setContentDispositionEncodingFallbackArray:(NSArray *)theEncodingFallbackArray; +@end + namespace WebCore { NSURLRequest* ResourceRequest::nsURLRequest() const @@ -56,12 +68,25 @@ void ResourceRequest::doUpdateResourceRequest() NSString *name; while ((name = [e nextObject])) m_httpHeaderFields.set(name, [headers objectForKey:name]); - + + // The below check can be removed once we require a version of Foundation with -[NSURLRequest contentDispositionEncodingFallbackArray] method. + static bool supportsContentDispositionEncodingFallbackArray = [NSURLRequest instancesRespondToSelector:@selector(contentDispositionEncodingFallbackArray)]; + if (supportsContentDispositionEncodingFallbackArray) { + m_responseContentDispositionEncodingFallbackArray.clear(); + NSArray *encodingFallbacks = [m_nsRequest.get() contentDispositionEncodingFallbackArray]; + NSUInteger count = [encodingFallbacks count]; + for (NSUInteger i = 0; i < count; ++i) { + CFStringEncoding encoding = CFStringConvertNSStringEncodingToEncoding([(NSNumber *)[encodingFallbacks objectAtIndex:i] unsignedLongValue]); + if (encoding != kCFStringEncodingInvalidId) + m_responseContentDispositionEncodingFallbackArray.append(CFStringGetNameOfEncoding(encoding)); + } + } + if (NSData* bodyData = [m_nsRequest.get() HTTPBody]) m_httpBody = FormData::create([bodyData bytes], [bodyData length]); else if (NSInputStream* bodyStream = [m_nsRequest.get() HTTPBodyStream]) if (FormData* formData = httpBodyFromStream(bodyStream)) - m_httpBody = formData; + m_httpBody = formData; } void ResourceRequest::doUpdatePlatformRequest() @@ -93,7 +118,22 @@ void ResourceRequest::doUpdatePlatformRequest() HTTPHeaderMap::const_iterator end = httpHeaderFields().end(); for (HTTPHeaderMap::const_iterator it = httpHeaderFields().begin(); it != end; ++it) [nsRequest setValue:it->second forHTTPHeaderField:it->first]; - + + // The below check can be removed once we require a version of Foundation with -[NSMutableURLRequest setContentDispositionEncodingFallbackArray] method. + static bool supportsContentDispositionEncodingFallbackArray = [NSMutableURLRequest instancesRespondToSelector:@selector(setContentDispositionEncodingFallbackArray)]; + if (supportsContentDispositionEncodingFallbackArray) { + NSMutableArray *encodingFallbacks = [NSMutableArray array]; + unsigned count = m_responseContentDispositionEncodingFallbackArray.size(); + for (unsigned i = 0; i != count; ++i) { + CFStringRef encodingName = m_responseContentDispositionEncodingFallbackArray[i].createCFString(); + unsigned long nsEncoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding(encodingName)); + CFRelease(encodingName); + if (nsEncoding != kCFStringEncodingInvalidId) + [encodingFallbacks addObject:[NSNumber numberWithUnsignedLong:nsEncoding]]; + } + [nsRequest setContentDispositionEncodingFallbackArray:encodingFallbacks]; + } + RefPtr<FormData> formData = httpBody(); if (formData && !formData->isEmpty()) WebCore::setHTTPBody(nsRequest, formData); diff --git a/WebCore/platform/network/mac/ResourceResponseMac.mm b/WebCore/platform/network/mac/ResourceResponseMac.mm index f60b496..d501b31 100644 --- a/WebCore/platform/network/mac/ResourceResponseMac.mm +++ b/WebCore/platform/network/mac/ResourceResponseMac.mm @@ -28,6 +28,7 @@ #import "WebCoreURLResponse.h" #import <Foundation/Foundation.h> +#import <wtf/StdLibExtras.h> #import <limits> @interface NSURLResponse (FoundationSecretsWebCoreKnowsAbout) @@ -99,7 +100,7 @@ void ResourceResponse::platformLazyInit() // is returning incorrect MIME type for local .xhtml files) which is only required in Leopard. if (m_url.isLocalFile() && m_mimeType == "text/html") { const String& path = m_url.path(); - static const String xhtmlExt(".xhtml"); + DEFINE_STATIC_LOCAL(const String, xhtmlExt, (".xhtml")); if (path.endsWith(xhtmlExt, false)) m_mimeType = "application/xhtml+xml"; } diff --git a/WebCore/platform/network/soup/CookieJarSoup.cpp b/WebCore/platform/network/soup/CookieJarSoup.cpp index 4ae90e5..88109e8 100644 --- a/WebCore/platform/network/soup/CookieJarSoup.cpp +++ b/WebCore/platform/network/soup/CookieJarSoup.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2008 Xan Lopez <xan@gnome.org> + * Copyright (C) 2008 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,24 +18,16 @@ */ #include "config.h" -#include "CString.h" -#include "CookieJar.h" +#include "CookieJarSoup.h" +#include "CString.h" #include "KURL.h" -#include "PlatformString.h" -#include "StringHash.h" - -#include <libsoup/soup.h> namespace WebCore { SoupCookieJar* getCookieJar() { - static SoupCookieJar* jar = NULL; - - if (!jar) - jar = soup_cookie_jar_new(); - + static SoupCookieJar* jar = soup_cookie_jar_new(); return jar; } @@ -60,7 +53,7 @@ String cookies(const Document* /*document*/, const KURL& url) char* cookies = soup_cookie_jar_get_cookies(jar, uri, FALSE); soup_uri_free(uri); - String result(cookies); + String result(String::fromUTF8(cookies)); g_free(cookies); return result; diff --git a/WebCore/platform/qt/SystemTimeQt.cpp b/WebCore/platform/network/soup/CookieJarSoup.h index a9f3d98..61179ae 100644 --- a/WebCore/platform/qt/SystemTimeQt.cpp +++ b/WebCore/platform/network/soup/CookieJarSoup.h @@ -1,7 +1,6 @@ /* - * Copyright (C) 2006 Dirk Mueller <mueller@kde.org> - * - * All rights reserved. + * Copyright (C) 2008 Xan Lopez <xan@gnome.org> + * 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 @@ -25,22 +24,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" -#include "SystemTime.h" +#ifndef CookieJarSoup_h +#define CookieJarSoup_h -#include <sys/time.h> +#include "CookieJar.h" +#include <libsoup/soup.h> namespace WebCore { - -double currentTime() -{ - struct timeval tv; - struct timezone tz; - - gettimeofday(&tv, &tz); - return (double)tv.tv_sec + (double)(tv.tv_usec / 1000000.0); -} - + SoupCookieJar* getCookieJar(); } -// vim: ts=4 sw=4 et +#endif diff --git a/WebCore/platform/network/soup/ResourceHandleSoup.cpp b/WebCore/platform/network/soup/ResourceHandleSoup.cpp index d48ce27..da96873 100644 --- a/WebCore/platform/network/soup/ResourceHandleSoup.cpp +++ b/WebCore/platform/network/soup/ResourceHandleSoup.cpp @@ -2,6 +2,7 @@ * Copyright (C) 2008 Alp Toker <alp@atoker.com> * Copyright (C) 2008 Xan Lopez <xan@gnome.org> * Copyright (C) 2008 Collabora Ltd. + * Copyright (C) 2009 Holger Hans Peter Freyther * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,7 +25,7 @@ #include "ResourceHandle.h" #include "Base64.h" -#include "CookieJar.h" +#include "CookieJarSoup.h" #include "DocLoader.h" #include "Frame.h" #include "HTTPParsers.h" @@ -57,12 +58,21 @@ enum ERROR_BAD_NON_HTTP_METHOD }; +static void cleanupGioOperation(ResourceHandleInternal* handle); + ResourceHandleInternal::~ResourceHandleInternal() { if (m_msg) { g_object_unref(m_msg); m_msg = 0; } + + cleanupGioOperation(this); + + if (m_idleHandler) { + g_source_remove(m_idleHandler); + m_idleHandler = 0; + } } ResourceHandle::~ResourceHandle() @@ -163,8 +173,6 @@ static void finishedCallback(SoupSession *session, SoupMessage* msg, gpointer da return; ResourceHandleInternal* d = handle->getInternal(); - // The message has been handled. - d->m_msg = NULL; ResourceHandleClient* client = handle->client(); if (!client) @@ -200,6 +208,8 @@ static gboolean parseDataUrl(gpointer callback_data) ResourceHandle* handle = static_cast<ResourceHandle*>(callback_data); ResourceHandleClient* client = handle->client(); + handle->getInternal()->m_idleHandler = 0; + ASSERT(client); if (!client) return FALSE; @@ -264,10 +274,12 @@ static gboolean parseDataUrl(gpointer callback_data) bool ResourceHandle::startData(String urlString) { - // If parseDataUrl is called synchronously the job is not yet effectively started - // and webkit won't never know that the data has been parsed even didFinishLoading is called. - g_idle_add(parseDataUrl, this); - return true; + ResourceHandleInternal* d = this->getInternal(); + + // If parseDataUrl is called synchronously the job is not yet effectively started + // and webkit won't never know that the data has been parsed even didFinishLoading is called. + d->m_idleHandler = g_idle_add(parseDataUrl, this); + return true; } bool ResourceHandle::startHttp(String urlString) @@ -298,7 +310,7 @@ bool ResourceHandle::startHttp(String urlString) if (!customHeaders.isEmpty()) { HTTPHeaderMap::const_iterator end = customHeaders.end(); for (HTTPHeaderMap::const_iterator it = customHeaders.begin(); it != end; ++it) - soup_message_headers_append(msg->request_headers, it->first.utf8().data(), it->second.utf8().data()); + soup_message_headers_append(msg->request_headers, it->first.string().utf8().data(), it->second.utf8().data()); } FormData* httpBody = d->m_request.httpBody(); @@ -337,7 +349,7 @@ bool ResourceHandle::start(Frame* frame) if (equalIgnoringCase(protocol, "data")) return startData(urlString); - else if (equalIgnoringCase(protocol, "http") || equalIgnoringCase(protocol, "https")) + else if ((equalIgnoringCase(protocol, "http") || equalIgnoringCase(protocol, "https")) && SOUP_URI_VALID_FOR_HTTP(soup_uri_new(urlString.utf8().data()))) return startHttp(urlString); else if (equalIgnoringCase(protocol, "file") || equalIgnoringCase(protocol, "ftp") || equalIgnoringCase(protocol, "ftps")) // FIXME: should we be doing any other protocols here? @@ -358,10 +370,12 @@ void ResourceHandle::cancel() if (d->m_msg) { soup_session_cancel_message(session, d->m_msg, SOUP_STATUS_CANCELLED); // For re-entrancy troubles we call didFinishLoading when the message hasn't been handled yet. - d->client()->didFinishLoading(this); + if (client()) + client()->didFinishLoading(this); } else if (d->m_cancellable) { g_cancellable_cancel(d->m_cancellable); - d->client()->didFinishLoading(this); + if (client()) + client()->didFinishLoading(this); } } @@ -411,11 +425,10 @@ static inline ResourceError networkErrorForFile(GFile* file, GError* error) return resourceError; } -static void cleanupGioOperation(ResourceHandle* handle) +static void cleanupGioOperation(ResourceHandleInternal* d) { - 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); d->m_gfile = NULL; } @@ -424,6 +437,7 @@ static void cleanupGioOperation(ResourceHandle* handle) d->m_cancellable = NULL; } if (d->m_input_stream) { + g_object_set_data(G_OBJECT(d->m_input_stream), "webkit-resource", 0); g_object_unref(d->m_input_stream); d->m_input_stream = NULL; } @@ -433,25 +447,31 @@ static void cleanupGioOperation(ResourceHandle* handle) } } -static void closeCallback(GObject* source, GAsyncResult* res, gpointer data) +static void closeCallback(GObject* source, GAsyncResult* res, gpointer) { - ResourceHandle* handle = static_cast<ResourceHandle*>(data); + ResourceHandle* handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource")); + if (!handle) + return; + ResourceHandleInternal* d = handle->getInternal(); ResourceHandleClient* client = handle->client(); g_input_stream_close_finish(d->m_input_stream, res, NULL); - cleanupGioOperation(handle); + cleanupGioOperation(d); client->didFinishLoading(handle); } -static void readCallback(GObject* source, GAsyncResult* res, gpointer data) +static void readCallback(GObject* source, GAsyncResult* res, gpointer) { - ResourceHandle* handle = static_cast<ResourceHandle*>(data); + ResourceHandle* handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource")); + if (!handle) + return; + ResourceHandleInternal* d = handle->getInternal(); ResourceHandleClient* client = handle->client(); if (d->m_cancelled || !client) { - cleanupGioOperation(handle); + cleanupGioOperation(d); return; } @@ -460,12 +480,13 @@ static void readCallback(GObject* source, GAsyncResult* res, gpointer data) nread = g_input_stream_read_finish(d->m_input_stream, res, &error); if (error) { - client->didFail(handle, networkErrorForFile(d->m_gfile, error)); - cleanupGioOperation(handle); + ResourceError resourceError = networkErrorForFile(d->m_gfile, error); + cleanupGioOperation(d); + client->didFail(handle, resourceError); return; } else if (!nread) { g_input_stream_close_async(d->m_input_stream, G_PRIORITY_DEFAULT, - NULL, closeCallback, handle); + NULL, closeCallback, NULL); return; } @@ -474,17 +495,20 @@ static void readCallback(GObject* source, GAsyncResult* res, gpointer data) g_input_stream_read_async(d->m_input_stream, d->m_buffer, d->m_bufsize, G_PRIORITY_DEFAULT, d->m_cancellable, - readCallback, handle); + readCallback, NULL); } -static void openCallback(GObject* source, GAsyncResult* res, gpointer data) +static void openCallback(GObject* source, GAsyncResult* res, gpointer) { - ResourceHandle* handle = static_cast<ResourceHandle*>(data); + ResourceHandle* handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource")); + if (!handle) + return; + ResourceHandleInternal* d = handle->getInternal(); ResourceHandleClient* client = handle->client(); if (d->m_cancelled || !client) { - cleanupGioOperation(handle); + cleanupGioOperation(d); return; } @@ -492,8 +516,9 @@ static void openCallback(GObject* source, GAsyncResult* res, gpointer data) GError *error = NULL; in = g_file_read_finish(G_FILE(source), res, &error); if (error) { - client->didFail(handle, networkErrorForFile(d->m_gfile, error)); - cleanupGioOperation(handle); + ResourceError resourceError = networkErrorForFile(d->m_gfile, error); + cleanupGioOperation(d); + client->didFail(handle, resourceError); return; } @@ -501,19 +526,23 @@ static void openCallback(GObject* source, GAsyncResult* res, gpointer data) d->m_bufsize = 8192; d->m_buffer = static_cast<char*>(g_malloc(d->m_bufsize)); d->m_total = 0; + g_object_set_data(G_OBJECT(d->m_input_stream), "webkit-resource", handle); g_input_stream_read_async(d->m_input_stream, d->m_buffer, d->m_bufsize, G_PRIORITY_DEFAULT, d->m_cancellable, - readCallback, handle); + readCallback, NULL); } -static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer data) +static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer) { - ResourceHandle* handle = static_cast<ResourceHandle*>(data); + ResourceHandle* handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource")); + if (!handle) + return; + ResourceHandleInternal* d = handle->getInternal(); ResourceHandleClient* client = handle->client(); if (d->m_cancelled) { - cleanupGioOperation(handle); + cleanupGioOperation(d); return; } @@ -534,8 +563,9 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer data) // and set a timeout to unmount it later after it's been idle // for a while). - client->didFail(handle, networkErrorForFile(d->m_gfile, error)); - cleanupGioOperation(handle); + ResourceError resourceError = networkErrorForFile(d->m_gfile, error); + cleanupGioOperation(d); + client->didFail(handle, resourceError); return; } @@ -543,8 +573,9 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer data) // FIXME: what if the URI points to a directory? Should we // generate a listing? How? What do other backends do here? - client->didFail(handle, networkErrorForFile(d->m_gfile, error)); - cleanupGioOperation(handle); + ResourceError resourceError = networkErrorForFile(d->m_gfile, error); + cleanupGioOperation(d); + client->didFail(handle, resourceError); return; } @@ -559,7 +590,7 @@ static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer data) client->didReceiveResponse(handle, response); g_file_read_async(d->m_gfile, G_PRIORITY_DEFAULT, d->m_cancellable, - openCallback, handle); + openCallback, NULL); } bool ResourceHandle::startGio(String urlString) @@ -576,6 +607,7 @@ bool ResourceHandle::startGio(String urlString) urlString = urlString.left(fragPos); d->m_gfile = g_file_new_for_uri(urlString.utf8().data()); + g_object_set_data(G_OBJECT(d->m_gfile), "webkit-resource", this); d->m_cancellable = g_cancellable_new(); g_file_query_info_async(d->m_gfile, G_FILE_ATTRIBUTE_STANDARD_TYPE "," @@ -583,7 +615,7 @@ bool ResourceHandle::startGio(String urlString) G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, d->m_cancellable, - queryInfoCallback, this); + queryInfoCallback, NULL); return true; } diff --git a/WebCore/platform/network/win/CookieJarCFNetWin.cpp b/WebCore/platform/network/win/CookieJarCFNetWin.cpp index fd795ee..56d7265 100644 --- a/WebCore/platform/network/win/CookieJarCFNetWin.cpp +++ b/WebCore/platform/network/win/CookieJarCFNetWin.cpp @@ -27,23 +27,67 @@ #include "CookieJar.h" #include "CookieStorageWin.h" +#include "Document.h" #include "KURL.h" #include "PlatformString.h" -#include "Document.h" #include "ResourceHandle.h" -#include <windows.h> -#include <CoreFoundation/CoreFoundation.h> #include <CFNetwork/CFHTTPCookiesPriv.h> +#include <CoreFoundation/CoreFoundation.h> #include <WebKitSystemInterface/WebKitSystemInterface.h> +#include <windows.h> namespace WebCore { static const CFStringRef s_setCookieKeyCF = CFSTR("Set-Cookie"); static const CFStringRef s_cookieCF = CFSTR("Cookie"); +typedef Boolean (*IsHTTPOnlyFunction)(CFHTTPCookieRef); + +static HMODULE findCFNetworkModule() +{ + if (HMODULE module = GetModuleHandleA("CFNetwork")) + return module; + return GetModuleHandleA("CFNetwork_debug"); +} + +static IsHTTPOnlyFunction findIsHTTPOnlyFunction() +{ + return reinterpret_cast<IsHTTPOnlyFunction>(GetProcAddress(findCFNetworkModule(), "CFHTTPCookieIsHTTPOnly")); +} + +static bool isHTTPOnly(CFHTTPCookieRef cookie) +{ + // Once we require a newer version of CFNetwork with the CFHTTPCookieIsHTTPOnly function, + // we can change this to be a normal function call and eliminate findIsHTTPOnlyFunction. + static IsHTTPOnlyFunction function = findIsHTTPOnlyFunction(); + return function && function(cookie); +} + +static RetainPtr<CFArrayRef> filterCookies(CFArrayRef unfilteredCookies) +{ + CFIndex count = CFArrayGetCount(unfilteredCookies); + RetainPtr<CFMutableArrayRef> filteredCookies(AdoptCF, CFArrayCreateMutable(0, count, &kCFTypeArrayCallBacks)); + for (CFIndex i = 0; i < count; ++i) { + CFHTTPCookieRef cookie = (CFHTTPCookieRef)CFArrayGetValueAtIndex(unfilteredCookies, i); + + // <rdar://problem/5632883> CFHTTPCookieStorage would store an empty cookie, + // which would be sent as "Cookie: =". We have a workaround in setCookies() to prevent + // that, but we also need to avoid sending cookies that were previously stored, and + // there's no harm to doing this check because such a cookie is never valid. + if (!CFStringGetLength(CFHTTPCookieGetName(cookie))) + continue; + + if (isHTTPOnly(cookie)) + continue; + + CFArrayAppendValue(filteredCookies.get(), cookie); + } + return filteredCookies; +} + void setCookies(Document* /*document*/, const KURL& url, const KURL& policyURL, const String& value) { - // <rdar://problem/5632883> CFHTTPCookieStorage happily stores an empty cookie, which would be sent as "Cookie: =". + // <rdar://problem/5632883> CFHTTPCookieStorage stores an empty cookie, which would be sent as "Cookie: =". if (value.isEmpty()) return; @@ -59,13 +103,14 @@ void setCookies(Document* /*document*/, const KURL& url, const KURL& policyURL, String cookieString = value.contains('=') ? value : value + "="; RetainPtr<CFStringRef> cookieStringCF(AdoptCF, cookieString.createCFString()); - RetainPtr<CFDictionaryRef> headerFieldsCF(AdoptCF, CFDictionaryCreate(kCFAllocatorDefault, (const void**)&s_setCookieKeyCF, - (const void**)&cookieStringCF, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + RetainPtr<CFDictionaryRef> headerFieldsCF(AdoptCF, CFDictionaryCreate(kCFAllocatorDefault, + (const void**)&s_setCookieKeyCF, (const void**)&cookieStringCF, 1, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); RetainPtr<CFArrayRef> cookiesCF(AdoptCF, CFHTTPCookieCreateWithResponseHeaderFields(kCFAllocatorDefault, headerFieldsCF.get(), urlCF.get())); - CFHTTPCookieStorageSetCookies(cookieStorage, cookiesCF.get(), urlCF.get(), policyURLCF.get()); + CFHTTPCookieStorageSetCookies(cookieStorage, filterCookies(cookiesCF.get()).get(), urlCF.get(), policyURLCF.get()); } String cookies(const Document* /*document*/, const KURL& url) @@ -74,24 +119,11 @@ String cookies(const Document* /*document*/, const KURL& url) if (!cookieStorage) return String(); - String cookieString; RetainPtr<CFURLRef> urlCF(AdoptCF, url.createCFURL()); - bool secure = equalIgnoringCase(url.protocol(), "https"); - + bool secure = url.protocolIs("https"); RetainPtr<CFArrayRef> cookiesCF(AdoptCF, CFHTTPCookieStorageCopyCookiesForURL(cookieStorage, urlCF.get(), secure)); - - // <rdar://problem/5632883> CFHTTPCookieStorage happily stores an empty cookie, which would be sent as "Cookie: =". - // We have a workaround in setCookies() to prevent that, but we also need to avoid sending cookies that were previously stored. - CFIndex count = CFArrayGetCount(cookiesCF.get()); - RetainPtr<CFMutableArrayRef> cookiesForURLFilteredCopy(AdoptCF, CFArrayCreateMutable(0, count, &kCFTypeArrayCallBacks)); - for (CFIndex i = 0; i < count; ++i) { - CFHTTPCookieRef cookie = (CFHTTPCookieRef)CFArrayGetValueAtIndex(cookiesCF.get(), i); - if (CFStringGetLength(CFHTTPCookieGetName(cookie)) != 0) - CFArrayAppendValue(cookiesForURLFilteredCopy.get(), cookie); - } - RetainPtr<CFDictionaryRef> headerCF(AdoptCF, CFHTTPCookieCopyRequestHeaderFields(kCFAllocatorDefault, cookiesForURLFilteredCopy.get())); - + RetainPtr<CFDictionaryRef> headerCF(AdoptCF, CFHTTPCookieCopyRequestHeaderFields(kCFAllocatorDefault, filterCookies(cookiesCF.get()).get())); return (CFStringRef)CFDictionaryGetValue(headerCF.get(), s_cookieCF); } diff --git a/WebCore/platform/network/win/NetworkStateNotifierWin.cpp b/WebCore/platform/network/win/NetworkStateNotifierWin.cpp index f8cbace..5cc381d 100644 --- a/WebCore/platform/network/win/NetworkStateNotifierWin.cpp +++ b/WebCore/platform/network/win/NetworkStateNotifierWin.cpp @@ -99,6 +99,7 @@ void NetworkStateNotifier::registerForAddressChange() NetworkStateNotifier::NetworkStateNotifier() : m_isOnLine(false) + , m_networkStateChangedFunction(0) { updateState(); diff --git a/WebCore/platform/posix/FileSystemPOSIX.cpp b/WebCore/platform/posix/FileSystemPOSIX.cpp index 82ae087..c1bef60 100644 --- a/WebCore/platform/posix/FileSystemPOSIX.cpp +++ b/WebCore/platform/posix/FileSystemPOSIX.cpp @@ -163,31 +163,10 @@ String directoryName(const String& path) return dirname(fsRep.mutableData()); } -Vector<String> listDirectory(const String& path, const String& filter) -{ -#ifdef ANDROID_PLUGINS - CString fsRepPath = fileSystemRepresentation(path); - CString fsRepFilter = fileSystemRepresentation(filter); -#endif - Vector<String> entries; -#ifdef ANDROID_PLUGINS - DIR *dir = opendir(fsRepPath.data()); - if (dir == NULL) - return entries; - for (;;) { - struct dirent *entry = readdir(dir); - if (entry == NULL) - break; - if (!fnmatch(fsRepFilter.data(), entry->d_name, FNM_NOESCAPE)) { - String fullPath = path + "/" + entry->d_name; - entries.append(fullPath); - } - } - closedir(dir); -#else - notImplemented(); -#endif - return entries; -} +// OK to not implement listDirectory at the moment, because it's only used for plug-ins, and +// all platforms that use the shared plug-in implementation have implementations. We'd need +// to implement it if we wanted to use PluginDatabase.cpp on the Mac. Better to not implement +// at all and get a link error in case this arises, rather than having a stub here, because +// with a stub you learn about the problem at runtime instead of link time. } // namespace WebCore diff --git a/WebCore/platform/qt/ClipboardQt.cpp b/WebCore/platform/qt/ClipboardQt.cpp index b0a1402..1bde10b 100644 --- a/WebCore/platform/qt/ClipboardQt.cpp +++ b/WebCore/platform/qt/ClipboardQt.cpp @@ -242,7 +242,7 @@ void ClipboardQt::declareAndWriteDragImage(Element* element, const KURL& url, co return; QPixmap *pixmap = cachedImage->image()->nativeImageForCurrentFrame(); if (pixmap) - m_writableData->setImageData(pixmap); + m_writableData->setImageData(*pixmap); AtomicString imageURL = element->getAttribute(HTMLNames::srcAttr); if (imageURL.isEmpty()) diff --git a/WebCore/platform/qt/CookieJarQt.cpp b/WebCore/platform/qt/CookieJarQt.cpp index 43be75a..0d24c7e 100644 --- a/WebCore/platform/qt/CookieJarQt.cpp +++ b/WebCore/platform/qt/CookieJarQt.cpp @@ -71,6 +71,15 @@ void setCookies(Document* document, const KURL& url, const KURL& policyURL, cons return; QList<QNetworkCookie> cookies = QNetworkCookie::parseCookies(QString(value).toAscii()); +#if QT_VERSION >= 0x040500 + QList<QNetworkCookie>::Iterator it = cookies.begin(); + while (it != cookies.end()) { + if (it->isHttpOnly()) + it = cookies.erase(it); + else + ++it; + } +#endif jar->setCookiesFromUrl(cookies, p); #else QCookieJar::cookieJar()->setCookies(u, p, (QString)value); @@ -90,9 +99,14 @@ String cookies(const Document* document, const KURL& url) return String(); QStringList resultCookies; - foreach (QNetworkCookie networkCookie, cookies) + foreach (QNetworkCookie networkCookie, cookies) { +#if QT_VERSION >= 0x040500 + if (networkCookie.isHttpOnly()) + continue; +#endif resultCookies.append(QString::fromAscii( networkCookie.toRawForm(QNetworkCookie::NameAndValueOnly).constData())); + } return resultCookies.join(QLatin1String("; ")); #else diff --git a/WebCore/platform/qt/FileChooserQt.cpp b/WebCore/platform/qt/FileChooserQt.cpp index b468dbe..307876c 100644 --- a/WebCore/platform/qt/FileChooserQt.cpp +++ b/WebCore/platform/qt/FileChooserQt.cpp @@ -21,15 +21,33 @@ #include "config.h" #include "FileChooser.h" +#include "LocalizedStrings.h" #include "Font.h" +#include <QCoreApplication> #include <QFontMetrics> namespace WebCore { String FileChooser::basenameForWidth(const Font& f, int width) const { - QFontMetrics fm(f.font()); - return fm.elidedText(m_filenames[0], Qt::ElideLeft, width); + if (width <= 0) + return String(); + + String string; + if (m_filenames.isEmpty()) + string = fileButtonNoFileSelectedLabel(); + else if (m_filenames.size() == 1) { + String fname = m_filenames[0]; + QFontMetrics fm(f.font()); + string = fm.elidedText(fname, Qt::ElideLeft, width); + } else { + int n = m_filenames.size(); + string = QCoreApplication::translate("QWebPage", "%n file(s)", + "number of chosen file", + QCoreApplication::CodecForTr, n); + } + + return string; } } diff --git a/WebCore/platform/qt/FileSystemQt.cpp b/WebCore/platform/qt/FileSystemQt.cpp index 6b56070..6dbe464 100644 --- a/WebCore/platform/qt/FileSystemQt.cpp +++ b/WebCore/platform/qt/FileSystemQt.cpp @@ -118,7 +118,7 @@ Vector<String> listDirectory(const String& path, const String& filter) CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle) { - QFile *temp = new QTemporaryFile(QString(prefix)); + QFile *temp = new QTemporaryFile(QLatin1String(prefix)); if (temp->open(QIODevice::ReadWrite)) { handle = temp; return String(temp->fileName()).utf8(); @@ -163,7 +163,7 @@ bool unloadModule(PlatformModule module) } #endif -#if defined(Q_OS_WIN32) +#if defined(Q_OS_WIN) bool unloadModule(PlatformModule module) { return ::FreeLibrary(module); diff --git a/WebCore/platform/qt/KeyboardCodes.h b/WebCore/platform/qt/KeyboardCodes.h index 21d3c67..61bc9fe 100644 --- a/WebCore/platform/qt/KeyboardCodes.h +++ b/WebCore/platform/qt/KeyboardCodes.h @@ -472,6 +472,10 @@ const int VK_MEDIA_LAUNCH_APP1 = 0xB6; // VK_LAUNCH_APP2 (B7) Windows 2000/XP: Start Application 2 key const int VK_MEDIA_LAUNCH_APP2 = 0xB7; +#endif // !PLATFORM(WIN_OS) + +#if !PLATFORM(WIN_OS) || PLATFORM(WIN_CE) + // VK_OEM_1 (BA) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ';:' key const int VK_OEM_1 = 0xBA; @@ -508,6 +512,10 @@ const int VK_OEM_7 = 0xDE; // VK_OEM_8 (DF) Used for miscellaneous characters; it can vary by keyboard. const int VK_OEM_8 = 0xDF; +#endif // !PLATFORM(WIN_OS) || PLATFORM(WIN_CE) + +#if !PLATFORM(WIN_OS) + // VK_OEM_102 (E2) Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard const int VK_OEM_102 = 0xE2; diff --git a/WebCore/platform/qt/Localizations.cpp b/WebCore/platform/qt/Localizations.cpp index b49b880..cb805f9 100644 --- a/WebCore/platform/qt/Localizations.cpp +++ b/WebCore/platform/qt/Localizations.cpp @@ -233,6 +233,11 @@ String contextMenuItemTagWritingDirectionMenu() return QCoreApplication::translate("QWebPage", "Direction", "Writing direction context sub-menu item"); } +String contextMenuItemTagTextDirectionMenu() +{ + return QCoreApplication::translate("QWebPage", "Text Direction", "Text direction context sub-menu item"); +} + String contextMenuItemTagDefaultDirection() { return QCoreApplication::translate("QWebPage", "Default", "Default writing direction context menu item"); diff --git a/WebCore/platform/qt/LoggingQt.cpp b/WebCore/platform/qt/LoggingQt.cpp index 5f6720a..b76c46e 100644 --- a/WebCore/platform/qt/LoggingQt.cpp +++ b/WebCore/platform/qt/LoggingQt.cpp @@ -64,18 +64,18 @@ void InitializeLoggingChannelsIfNecessary() haveInitializedLoggingChannels = true; - QString loggingEnv = qgetenv("QT_WEBKIT_LOG"); + QByteArray loggingEnv = qgetenv("QT_WEBKIT_LOG"); if (loggingEnv.isEmpty()) return; #if defined(NDEBUG) qWarning("This is a release build. Setting QT_WEBKIT_LOG will have no effect."); #else - QStringList channels = loggingEnv.split(","); - QStringListIterator iter(channels); + QList<QByteArray> channels = loggingEnv.split(','); + QListIterator<QByteArray> iter(channels); while (iter.hasNext()) { - QString channelName = iter.next(); + QByteArray channelName = iter.next(); WTFLogChannel* channel = getChannelFromName(channelName); if (!channel) continue; channel->state = WTFLogChannelOn; diff --git a/WebCore/platform/qt/MIMETypeRegistryQt.cpp b/WebCore/platform/qt/MIMETypeRegistryQt.cpp index 9f4a786..2b5968a 100644 --- a/WebCore/platform/qt/MIMETypeRegistryQt.cpp +++ b/WebCore/platform/qt/MIMETypeRegistryQt.cpp @@ -2,6 +2,7 @@ * Copyright (C) 2006 Zack Rusin <zack@kde.org> * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -62,6 +63,8 @@ static const ExtensionMap extensionMap [] = { { "xpm", "image/x-xpm" }, { "xsl", "text/xsl" }, { "xhtml", "application/xhtml+xml" }, + { "wml", "text/vnd.wap.wml" }, + { "wmlc", "application/vnd.wap.wmlc" }, { 0, 0 } }; diff --git a/WebCore/platform/qt/PlatformMouseEventQt.cpp b/WebCore/platform/qt/PlatformMouseEventQt.cpp index afc7452..ba7a4ad 100644 --- a/WebCore/platform/qt/PlatformMouseEventQt.cpp +++ b/WebCore/platform/qt/PlatformMouseEventQt.cpp @@ -28,7 +28,7 @@ #include "config.h" #include "PlatformMouseEvent.h" -#include "SystemTime.h" +#include <wtf/CurrentTime.h> #include <QMouseEvent> @@ -36,7 +36,7 @@ namespace WebCore { PlatformMouseEvent::PlatformMouseEvent(QInputEvent* event, int clickCount) { - m_timestamp = WebCore::currentTime(); + m_timestamp = WTF::currentTime(); QMouseEvent *me = 0; diff --git a/WebCore/platform/qt/PlatformScreenQt.cpp b/WebCore/platform/qt/PlatformScreenQt.cpp index 5bc86d0..5dc0963 100644 --- a/WebCore/platform/qt/PlatformScreenQt.cpp +++ b/WebCore/platform/qt/PlatformScreenQt.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2007 Apple Inc. All rights reserved. * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2008 Holger Hans Peter Freyther * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -43,34 +44,34 @@ namespace WebCore { int screenDepth(Widget* w) { QDesktopWidget* d = QApplication::desktop(); - QWidget *view = w->root()->hostWindow()->platformWindow(); + QWidget *view = w ? w->root()->hostWindow()->platformWindow() : 0; int screenNumber = view ? d->screenNumber(view) : 0; return d->screen(screenNumber)->depth(); } int screenDepthPerComponent(Widget* w) { - QWidget *view = w->root()->hostWindow()->platformWindow(); + QWidget *view = w ? w->root()->hostWindow()->platformWindow() : 0; return view ? view->depth() : QApplication::desktop()->screen(0)->depth(); } bool screenIsMonochrome(Widget* w) { QDesktopWidget* d = QApplication::desktop(); - QWidget *view = w->root()->hostWindow()->platformWindow(); + QWidget *view = w ? w->root()->hostWindow()->platformWindow(): 0; int screenNumber = view ? d->screenNumber(view) : 0; return d->screen(screenNumber)->numColors() < 2; } FloatRect screenRect(Widget* w) { - QRect r = QApplication::desktop()->screenGeometry(w->root()->hostWindow()->platformWindow()); + QRect r = QApplication::desktop()->screenGeometry(w ? w->root()->hostWindow()->platformWindow(): 0); return FloatRect(r.x(), r.y(), r.width(), r.height()); } FloatRect screenAvailableRect(Widget* w) { - QRect r = QApplication::desktop()->availableGeometry(w->root()->hostWindow()->platformWindow()); + QRect r = QApplication::desktop()->availableGeometry(w ? w->root()->hostWindow()->platformWindow(): 0); return FloatRect(r.x(), r.y(), r.width(), r.height()); } diff --git a/WebCore/platform/qt/QWebPopup.cpp b/WebCore/platform/qt/QWebPopup.cpp index ae5c24e..d463ddf 100644 --- a/WebCore/platform/qt/QWebPopup.cpp +++ b/WebCore/platform/qt/QWebPopup.cpp @@ -35,7 +35,7 @@ QWebPopup::QWebPopup(PopupMenuClient* client) setFont(m_client->menuStyle().font().font()); connect(this, SIGNAL(activated(int)), - SLOT(activeChanged(int))); + SLOT(activeChanged(int)), Qt::QueuedConnection); } diff --git a/WebCore/platform/qt/RenderThemeQt.cpp b/WebCore/platform/qt/RenderThemeQt.cpp index 2a33e45..eee8c86 100644 --- a/WebCore/platform/qt/RenderThemeQt.cpp +++ b/WebCore/platform/qt/RenderThemeQt.cpp @@ -6,6 +6,7 @@ * Copyright (C) 2006 Zack Rusin <zack@kde.org> * 2006 Dirk Mueller <mueller@kde.org> * 2006 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) 2008 Holger Hans Peter Freyther * * All rights reserved. * @@ -45,7 +46,9 @@ #include <QStyleOptionFrameV2> #include "Color.h" +#include "CSSStyleSelector.h" #include "CSSStyleSheet.h" +#include "FontSelector.h" #include "Document.h" #include "Page.h" #include "Font.h" @@ -53,6 +56,7 @@ #include "GraphicsContext.h" #include "HTMLMediaElement.h" #include "HTMLNames.h" +#include "RenderBox.h" namespace WebCore { @@ -151,9 +155,12 @@ bool RenderThemeQt::supportsFocusRing(const RenderStyle* style) const int RenderThemeQt::baselinePosition(const RenderObject* o) const { + if (!o->isBox()) + return 0; + if (o->style()->appearance() == CheckboxPart || o->style()->appearance() == RadioPart) - return o->marginTop() + o->height() - 2; // Same as in old khtml + return toRenderBox(o)->marginTop() + toRenderBox(o)->height() - 2; // Same as in old khtml return RenderTheme::baselinePosition(o); } @@ -398,6 +405,7 @@ void RenderThemeQt::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* s fontFamily.setFamily(m_buttonFontFamily); fontDescription.setFamily(fontFamily); style->setFontDescription(fontDescription); + style->font().update(selector->fontSelector()); style->setLineHeight(RenderStyle::initialLineHeight()); setButtonSize(style); @@ -567,8 +575,6 @@ bool RenderThemeQt::paintMenuList(RenderObject* o, const RenderObject::PaintInfo opt.rect.moveTo(QPoint(0,0)); opt.rect.setSize(r.size()); - opt.frame = false; - p.drawComplexControl(QStyle::CC_ComboBox, opt); p.painter->translate(-topLeft); return false; @@ -715,8 +721,10 @@ ControlPart RenderThemeQt::applyTheme(QStyleOption& option, RenderObject* o) con // Readonly is supported on textfields. option.state |= QStyle::State_ReadOnly; - if (supportsFocus(o->style()->appearance()) && isFocused(o)) + if (supportsFocus(o->style()->appearance()) && isFocused(o)) { option.state |= QStyle::State_HasFocus; + option.state |= QStyle::State_KeyboardFocusChange; + } if (isHovered(o)) option.state |= QStyle::State_MouseOver; @@ -754,16 +762,18 @@ ControlPart RenderThemeQt::applyTheme(QStyleOption& option, RenderObject* o) con return result; } -void RenderTheme::adjustDefaultStyleSheet(CSSStyleSheet* style) +#if ENABLE(VIDEO) + +String RenderThemeQt::extraMediaControlsStyleSheet() { - QFile platformStyleSheet(":/webcore/resources/html4-adjustments-qt.css"); + QFile platformStyleSheet(QLatin1String(":/webcore/css/mediaControls-extras.css")); if (platformStyleSheet.open(QFile::ReadOnly)) { QByteArray sheetData = platformStyleSheet.readAll(); - style->parseString(QString::fromUtf8(sheetData.constData(), sheetData.length())); + return QString::fromUtf8(sheetData.constData(), sheetData.length()); } -} -#if ENABLE(VIDEO) + return String(); +} // Helper class to transform the painter's world matrix to the object's content area, scaled to 0,0,100,100 class WorldMatrixTransformer @@ -942,6 +952,11 @@ void RenderThemeQt::adjustSliderThumbSize(RenderObject* o) const } } +double RenderThemeQt::caretBlinkInterval() const +{ + return QApplication::cursorFlashTime() / 1000.0 / 2.0; +} + } // vim: ts=4 sw=4 et diff --git a/WebCore/platform/qt/RenderThemeQt.h b/WebCore/platform/qt/RenderThemeQt.h index 76e1855..9a6cf0b 100644 --- a/WebCore/platform/qt/RenderThemeQt.h +++ b/WebCore/platform/qt/RenderThemeQt.h @@ -70,6 +70,12 @@ public: virtual void adjustSliderThumbSize(RenderObject*) const; + virtual double caretBlinkInterval() const; + +#if ENABLE(VIDEO) + virtual String extraMediaControlsStyleSheet(); +#endif + protected: virtual bool paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r); virtual void setCheckboxSize(RenderStyle*) const; diff --git a/WebCore/platform/qt/ScrollbarQt.cpp b/WebCore/platform/qt/ScrollbarQt.cpp index 2d65282..29a9997 100644 --- a/WebCore/platform/qt/ScrollbarQt.cpp +++ b/WebCore/platform/qt/ScrollbarQt.cpp @@ -49,6 +49,9 @@ namespace WebCore { bool Scrollbar::contextMenu(const PlatformMouseEvent& event) { #ifndef QT_NO_CONTEXTMENU + if (!QApplication::style()->styleHint(QStyle::SH_ScrollBar_ContextMenu)) + return true; + bool horizontal = (m_orientation == HorizontalScrollbar); QMenu menu; diff --git a/WebCore/platform/qt/ScrollbarThemeQt.cpp b/WebCore/platform/qt/ScrollbarThemeQt.cpp index 1995719..3851dfe 100644 --- a/WebCore/platform/qt/ScrollbarThemeQt.cpp +++ b/WebCore/platform/qt/ScrollbarThemeQt.cpp @@ -94,11 +94,17 @@ static ScrollbarPart scrollbarPart(const QStyle::SubControl& sc) return NoPart; } -static QStyleOptionSlider* styleOptionSlider(Scrollbar* scrollbar) +static QStyleOptionSlider* styleOptionSlider(Scrollbar* scrollbar, QWidget* widget = 0) { static QStyleOptionSlider opt; + if (widget) + opt.initFrom(widget); + else + opt.state |= QStyle::State_Active; + + opt.state &= ~QStyle::State_HasFocus; + opt.rect = scrollbar->frameRect(); - opt.state = 0; if (scrollbar->enabled()) opt.state |= QStyle::State_Enabled; if (scrollbar->controlSize() != RegularScrollbar) @@ -139,7 +145,8 @@ bool ScrollbarThemeQt::paint(Scrollbar* scrollbar, GraphicsContext* graphicsCont return true; p.painter->save(); - QStyleOptionSlider* opt = styleOptionSlider(scrollbar); + QStyleOptionSlider* opt = styleOptionSlider(scrollbar, p.widget); + p.painter->setClipRect(opt->rect.intersected(damageRect)); #ifdef Q_WS_MAC diff --git a/WebCore/platform/qt/SharedTimerQt.cpp b/WebCore/platform/qt/SharedTimerQt.cpp index 49f55c1..e9bcaee 100644 --- a/WebCore/platform/qt/SharedTimerQt.cpp +++ b/WebCore/platform/qt/SharedTimerQt.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2006 George Staikos <staikos@kde.org> * Copyright (C) 2006 Dirk Mueller <mueller@kde.org> + * Copyright (C) 2008 Holger Hans Peter Freyther * * All rights reserved. * @@ -26,30 +27,105 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "SharedTimerQt.h" -#include <QApplication> +#include "config.h" + +#include <wtf/CurrentTime.h> + +#include <QBasicTimer> +#include <QCoreApplication> +#include <QDebug> +#include <QPointer> namespace WebCore { -SharedTimerQt* SharedTimerQt::s_self = 0; // FIXME: staticdeleter +class SharedTimerQt : public QObject { + friend void setSharedTimerFiredFunction(void (*f)()); +public: + static SharedTimerQt* inst(); + + void start(double); + void stop(); + +protected: + void timerEvent(QTimerEvent* ev); + +private: + SharedTimerQt(QObject* parent); + ~SharedTimerQt(); + QBasicTimer m_timer; + void (*m_timerFunction)(); +}; + +SharedTimerQt::SharedTimerQt(QObject* parent) + : QObject(parent) + , m_timerFunction(0) +{} + +SharedTimerQt::~SharedTimerQt() +{ + if (m_timer.isActive()) + (m_timerFunction)(); +} + +SharedTimerQt* SharedTimerQt::inst() +{ + static QPointer<SharedTimerQt> timer; + if (!timer) + timer = new SharedTimerQt(QCoreApplication::instance()); + + return timer; +} + +void SharedTimerQt::start(double fireTime) +{ + double interval = fireTime - currentTime(); + unsigned int intervalInMS; + if (interval < 0) + intervalInMS = 0; + else { + interval *= 1000; + intervalInMS = (unsigned int)interval; + } + + m_timer.start(intervalInMS, this); +} + +void SharedTimerQt::stop() +{ + m_timer.stop(); +} + +void SharedTimerQt::timerEvent(QTimerEvent* ev) +{ + if (!m_timerFunction || ev->timerId() != m_timer.timerId()) + return; + + m_timer.stop(); + (m_timerFunction)(); +} void setSharedTimerFiredFunction(void (*f)()) { + if (!QCoreApplication::instance()) + return; + SharedTimerQt::inst()->m_timerFunction = f; } void setSharedTimerFireTime(double fireTime) { - if (!qApp) + if (!QCoreApplication::instance()) return; - qreal fireTimeMs = (fireTime - currentTime()) * 1000; - SharedTimerQt::inst()->start(qMax(0, int(fireTimeMs))); + SharedTimerQt::inst()->start(fireTime); } void stopSharedTimer() { + if (!QCoreApplication::instance()) + return; + SharedTimerQt::inst()->stop(); } diff --git a/WebCore/platform/qt/TemporaryLinkStubs.cpp b/WebCore/platform/qt/TemporaryLinkStubs.cpp index f262684..ff0b27d 100644 --- a/WebCore/platform/qt/TemporaryLinkStubs.cpp +++ b/WebCore/platform/qt/TemporaryLinkStubs.cpp @@ -74,7 +74,7 @@ using namespace WebCore; -#if !defined(Q_WS_X11) && !defined(Q_WS_WIN) +#if (!defined(Q_WS_X11) && !defined(Q_WS_WIN) && !defined(Q_WS_MAC32)) || defined(Q_OS_WINCE) bool PluginPackage::fetchInfo() { notImplemented(); return false; } unsigned PluginPackage::hash() const { notImplemented(); return 0; } @@ -83,7 +83,11 @@ int PluginPackage::compareFileVersion(const PlatformModuleVersion&) const { notI void PluginView::setNPWindowRect(const IntRect&) { notImplemented(); } const char* PluginView::userAgent() { notImplemented(); return 0; } +#if ENABLE(NETSCAPE_PLUGIN_API) +const char* PluginView::userAgentStatic() { notImplemented(); return 0; } +#endif void PluginView::invalidateRect(NPRect*) { notImplemented(); } +void PluginView::invalidateRect(const IntRect&) { notImplemented(); } void PluginView::invalidateRegion(NPRegion) { notImplemented(); } void PluginView::forceRedraw() { notImplemented(); } void PluginView::setFocus() { Widget::setFocus(); } @@ -92,14 +96,23 @@ void PluginView::hide() { Widget::hide(); } void PluginView::paint(GraphicsContext*, const IntRect&) { notImplemented(); } void PluginView::setParent(ScrollView* view) { Widget::setParent(view); } void PluginView::setParentVisible(bool) { notImplemented(); } -void PluginView::updatePluginWidget() const { notImplemented(); } +void PluginView::updatePluginWidget() { notImplemented(); } void PluginView::handleKeyboardEvent(KeyboardEvent*) { notImplemented(); } void PluginView::handleMouseEvent(MouseEvent*) { notImplemented(); } NPError PluginView::handlePostReadFile(Vector<char>&, uint32, const char*) { notImplemented(); return NPERR_GENERIC_ERROR; } NPError PluginView::getValue(NPNVariable, void*) { notImplemented(); return NPERR_GENERIC_ERROR; } +#if ENABLE(NETSCAPE_PLUGIN_API) +NPError PluginView::getValueStatic(NPNVariable, void*) { return NPERR_GENERIC_ERROR; } +#endif PluginView::~PluginView() {} #endif +#if defined(Q_OS_WINCE) +Vector<String> PluginDatabase::defaultPluginDirectories() { notImplemented(); return Vector<String>(); } +void PluginDatabase::getPluginPathsInDirectories(HashSet<String>& paths) const { notImplemented(); } +bool PluginDatabase::isPreferredPluginDirectory(const String& directory) { notImplemented(); return false; } +#endif + namespace WebCore { void getSupportedKeySizes(Vector<String>&) { notImplemented(); } diff --git a/WebCore/platform/qt/WebCoreResources.qrc b/WebCore/platform/qt/WebCoreResources.qrc deleted file mode 100644 index e42cd7f..0000000 --- a/WebCore/platform/qt/WebCoreResources.qrc +++ /dev/null @@ -1,5 +0,0 @@ -<!DOCTYPE RCC><RCC version="1.0"> -<qresource prefix="/webcore/resources"> - <file>html4-adjustments-qt.css</file> -</qresource> -</RCC>
\ No newline at end of file diff --git a/WebCore/platform/qt/WheelEventQt.cpp b/WebCore/platform/qt/WheelEventQt.cpp index 135f15a..cc8acd2 100644 --- a/WebCore/platform/qt/WheelEventQt.cpp +++ b/WebCore/platform/qt/WheelEventQt.cpp @@ -35,7 +35,11 @@ PlatformWheelEvent::PlatformWheelEvent(QWheelEvent* e) #else : m_position(e->pos()) , m_globalPosition(e->globalPos()) +#ifdef QT_MAC_USE_COCOA + , m_granularity(ScrollByPixelWheelEvent) +#else , m_granularity(ScrollByLineWheelEvent) +#endif , m_isAccepted(false) , m_shiftKey(e->modifiers() & Qt::ShiftModifier) , m_ctrlKey(e->modifiers() & Qt::ControlModifier) diff --git a/WebCore/platform/qt/WidgetQt.cpp b/WebCore/platform/qt/WidgetQt.cpp index 68cf383..9f1a1e8 100644 --- a/WebCore/platform/qt/WidgetQt.cpp +++ b/WebCore/platform/qt/WidgetQt.cpp @@ -69,9 +69,9 @@ IntRect Widget::frameRect() const void Widget::setFrameRect(const IntRect& rect) { - if (platformWidget()) - platformWidget()->setGeometry(convertToContainingWindow(IntRect(0, 0, rect.width(), rect.height()))); m_frame = rect; + + frameRectsChanged(); } void Widget::setFocus() diff --git a/WebCore/platform/qt/html4-adjustments-qt.css b/WebCore/platform/qt/html4-adjustments-qt.css deleted file mode 100644 index 129c164..0000000 --- a/WebCore/platform/qt/html4-adjustments-qt.css +++ /dev/null @@ -1,96 +0,0 @@ -/* - * QtWebKit specific style sheet. - * - * Copyright (C) 2008 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. - * - */ - -audio { - height: 34px; - width: 400px; -} - -audio::-webkit-media-controls-mute-button, video::-webkit-media-controls-mute-button { - left: auto; - right: 5px; - width: 12px; - height: 12px; - padding: 6px; - margin: 5px 0px; -} - -audio::-webkit-media-controls-play-button, video::-webkit-media-controls-play-button { - left: 5px; - width: 9px; - height: 12px; - padding: 6px 12px 6px 11px; - margin: 5px 0px; -} - -audio::-webkit-media-controls-time-display, video::-webkit-media-controls-time-display { - /* Since MediaControlElements are always created with a renderer we have to hide - the controls we don't use, so they don't mess up activation and event handling */ - left: 0px; - top: 0px; - width: 0px; - height: 0px; - - display: none; -} - -audio::-webkit-media-controls-timeline, video::-webkit-media-controls-timeline { - left: 42px; - right: 34px; - height: 12px; - padding: 6px 8px; - margin: 5px 0px; -} - -audio::-webkit-media-controls-seek-back-button, video::-webkit-media-controls-seek-back-button { - /* Since MediaControlElements are always created with a renderer we have to hide - the controls we don't use, so they don't mess up activation and event handling */ - left: 0px; - top: 0px; - width: 0px; - height: 0px; - - display: none; -} - -audio::-webkit-media-controls-seek-forward-button, video::-webkit-media-controls-seek-forward-button { - /* Since MediaControlElements are always created with a renderer we have to hide - the controls we don't use, so they don't mess up activation and event handling */ - left: 0px; - top: 0px; - width: 0px; - height: 0px; - - display: none; -} - -audio::-webkit-media-controls-fullscreen-button, video::-webkit-media-controls-fullscreen-button { - /* Since MediaControlElements are always created with a renderer we have to hide - the controls we don't use, so they don't mess up activation and event handling */ - left: 0px; - top: 0px; - width: 0px; - height: 0px; - - display: none; -} - diff --git a/WebCore/platform/text/AtomicString.cpp b/WebCore/platform/text/AtomicString.cpp index dc573e1..5f9abfd 100644 --- a/WebCore/platform/text/AtomicString.cpp +++ b/WebCore/platform/text/AtomicString.cpp @@ -28,35 +28,21 @@ #include "StaticConstructors.h" #include "StringHash.h" -#include <kjs/identifier.h> +#include "ThreadGlobalData.h" #include <wtf/Threading.h> #include <wtf/HashSet.h> -#if ENABLE(WORKERS) -#include <wtf/ThreadSpecific.h> -using namespace WTF; -#endif - #if USE(JSC) +#include <runtime/Identifier.h> using JSC::Identifier; using JSC::UString; #endif namespace WebCore { -#if ENABLE(WORKERS) -static ThreadSpecific<HashSet<StringImpl*> >* staticStringTable; -#else -static HashSet<StringImpl*>* staticStringTable; -#endif - -static inline HashSet<StringImpl*>* stringTable() +static inline HashSet<StringImpl*>& stringTable() { -#if ENABLE(WORKERS) - return *staticStringTable; -#else - return staticStringTable; -#endif + return threadGlobalData().atomicStringTable(); } struct CStringTranslator { @@ -99,7 +85,7 @@ PassRefPtr<StringImpl> AtomicString::add(const char* c) return 0; if (!*c) return StringImpl::empty(); - pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable()->add<const char*, CStringTranslator>(c); + pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<const char*, CStringTranslator>(c); if (!addResult.second) return *addResult.first; return adoptRef(*addResult.first); @@ -191,10 +177,11 @@ PassRefPtr<StringImpl> AtomicString::add(const UChar* s, int length) return StringImpl::empty(); UCharBuffer buf = { s, length }; - pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable()->add<UCharBuffer, UCharBufferTranslator>(buf); - if (!addResult.second) - return *addResult.first; - return adoptRef(*addResult.first); + pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<UCharBuffer, UCharBufferTranslator>(buf); + + // If the string is newly-translated, then we need to adopt it. + // The boolean in the pair tells us if that is so. + return addResult.second ? adoptRef(*addResult.first) : *addResult.first; } PassRefPtr<StringImpl> AtomicString::add(const UChar* s) @@ -210,10 +197,11 @@ PassRefPtr<StringImpl> AtomicString::add(const UChar* s) return StringImpl::empty(); UCharBuffer buf = {s, length}; - pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable()->add<UCharBuffer, UCharBufferTranslator>(buf); - if (!addResult.second) - return *addResult.first; - return adoptRef(*addResult.first); + pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<UCharBuffer, UCharBufferTranslator>(buf); + + // If the string is newly-translated, then we need to adopt it. + // The boolean in the pair tells us if that is so. + return addResult.second ? adoptRef(*addResult.first) : *addResult.first; } PassRefPtr<StringImpl> AtomicString::add(StringImpl* r) @@ -224,7 +212,7 @@ PassRefPtr<StringImpl> AtomicString::add(StringImpl* r) if (r->length() == 0) return StringImpl::empty(); - StringImpl* result = *stringTable()->add(r).first; + StringImpl* result = *stringTable().add(r).first; if (result == r) r->m_inTable = true; return result; @@ -232,7 +220,7 @@ PassRefPtr<StringImpl> AtomicString::add(StringImpl* r) void AtomicString::remove(StringImpl* r) { - stringTable()->remove(r); + stringTable().remove(r); } #if USE(JSC) @@ -247,7 +235,7 @@ PassRefPtr<StringImpl> AtomicString::add(const JSC::Identifier& identifier) return StringImpl::empty(); HashAndCharacters buffer = { string->computedHash(), string->data(), length }; - pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable()->add<HashAndCharacters, HashAndCharactersTranslator>(buffer); + pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<HashAndCharacters, HashAndCharactersTranslator>(buffer); if (!addResult.second) return *addResult.first; return adoptRef(*addResult.first); @@ -264,12 +252,11 @@ PassRefPtr<StringImpl> AtomicString::add(const JSC::UString& ustring) return StringImpl::empty(); HashAndCharacters buffer = { string->hash(), string->data(), length }; - pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable()->add<HashAndCharacters, HashAndCharactersTranslator>(buffer); + pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable().add<HashAndCharacters, HashAndCharactersTranslator>(buffer); if (!addResult.second) return *addResult.first; return adoptRef(*addResult.first); } -#endif AtomicStringImpl* AtomicString::find(const JSC::Identifier& identifier) { @@ -282,8 +269,8 @@ AtomicStringImpl* AtomicString::find(const JSC::Identifier& identifier) return static_cast<AtomicStringImpl*>(StringImpl::empty()); HashAndCharacters buffer = { string->computedHash(), string->data(), length }; - HashSet<StringImpl*>::iterator iterator = stringTable()->find<HashAndCharacters, HashAndCharactersTranslator>(buffer); - if (iterator == stringTable()->end()) + HashSet<StringImpl*>::iterator iterator = stringTable().find<HashAndCharacters, HashAndCharactersTranslator>(buffer); + if (iterator == stringTable().end()) return 0; return static_cast<AtomicStringImpl*>(*iterator); } @@ -292,6 +279,7 @@ AtomicString::operator UString() const { return m_string; } +#endif DEFINE_GLOBAL(AtomicString, nullAtom) DEFINE_GLOBAL(AtomicString, emptyAtom, "") @@ -306,12 +294,6 @@ void AtomicString::init() // Initialization is not thread safe, so this function must be called from the main thread first. ASSERT(isMainThread()); -#if ENABLE(WORKERS) - staticStringTable = new ThreadSpecific<HashSet<StringImpl*> >; -#else - staticStringTable = new HashSet<StringImpl*>; -#endif - // Use placement new to initialize the globals. new ((void*)&nullAtom) AtomicString; new ((void*)&emptyAtom) AtomicString(""); diff --git a/WebCore/platform/text/AtomicString.h b/WebCore/platform/text/AtomicString.h index ad034d9..f4efab9 100644 --- a/WebCore/platform/text/AtomicString.h +++ b/WebCore/platform/text/AtomicString.h @@ -89,14 +89,14 @@ public: static void remove(StringImpl*); +#if PLATFORM(CF) || (PLATFORM(QT) && PLATFORM(DARWIN)) + AtomicString(CFStringRef s) : m_string(add(String(s).impl())) { } + CFStringRef createCFString() const { return m_string.createCFString(); } +#endif #ifdef __OBJC__ AtomicString(NSString* s) : m_string(add(String(s).impl())) { } operator NSString*() const { return m_string; } #endif -#if PLATFORM(SYMBIAN) - AtomicString(const TDesC& s) : m_string(add(String(s).impl())) { } - operator TPtrC() const { return m_string; } -#endif #if PLATFORM(QT) AtomicString(const QString& s) : m_string(add(String(s).impl())) { } operator QString() const { return m_string; } diff --git a/WebCore/platform/text/PlatformString.h b/WebCore/platform/text/PlatformString.h index 73a44bd..35d3079 100644 --- a/WebCore/platform/text/PlatformString.h +++ b/WebCore/platform/text/PlatformString.h @@ -30,11 +30,12 @@ #include <wtf/PassRefPtr.h> #if USE(JSC) -#include <kjs/identifier.h> +#include <runtime/Identifier.h> #else -// kjs/identifier.h includes HashMap.h. We explicitly include it in the case of -// non-JSC builds to keep things consistent. +// runtime/Identifier.h includes HashMap.h and HashSet.h. We explicitly include +// them in the case of non-JSC builds to keep things consistent. #include <wtf/HashMap.h> +#include <wtf/HashSet.h> #endif #if PLATFORM(CF) || (PLATFORM(QT) && PLATFORM(DARWIN)) @@ -98,6 +99,8 @@ public: int find(UChar c, int start = 0) const { return m_impl ? m_impl->find(c, start) : -1; } + int find(CharacterMatchFunctionPtr matchFunction, int start = 0) const + { return m_impl ? m_impl->find(matchFunction, start) : -1; } int find(const char* str, int start = 0, bool caseSensitive = true) const { return m_impl ? m_impl->find(str, start, caseSensitive) : -1; } int find(const String& str, int start = 0, bool caseSensitive = true) const @@ -138,10 +141,14 @@ public: String stripWhiteSpace() const; String simplifyWhiteSpace() const; - + + String removeCharacters(CharacterMatchFunctionPtr) const; + // Return the string with case folded for case insensitive comparison. String foldCase() const; + static String number(short); + static String number(unsigned short); static String number(int); static String number(unsigned); static String number(long); @@ -176,6 +183,12 @@ public: // 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; + bool isNull() const { return !m_impl; } bool isEmpty() const; @@ -200,12 +213,6 @@ public: operator QString() const; #endif -#if PLATFORM(SYMBIAN) - String(const TDesC&); - operator TPtrC() const { return des(); } - TPtrC des() const { if (!m_impl) return KNullDesC(); return m_impl->des(); } -#endif - #if PLATFORM(WX) String(const wxString&); operator wxString() const; @@ -296,6 +303,17 @@ inline int find(const UChar* characters, size_t length, UChar character, int sta return -1; } +inline int find(const UChar* characters, size_t length, CharacterMatchFunctionPtr matchFunction, int startPosition) +{ + if (startPosition >= static_cast<int>(length)) + return -1; + for (size_t i = startPosition; i < length; ++i) { + if (matchFunction(characters[i])) + return static_cast<int>(i); + } + return -1; +} + inline int reverseFind(const UChar* characters, size_t length, UChar character, int startPosition) { if (startPosition >= static_cast<int>(length) || !length) diff --git a/WebCore/platform/text/RegularExpression.cpp b/WebCore/platform/text/RegularExpression.cpp index 1b933ff..6329b3b 100644 --- a/WebCore/platform/text/RegularExpression.cpp +++ b/WebCore/platform/text/RegularExpression.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2008, 2009 Apple Inc. All rights reserved. * Copyright (C) 2008 Collabora Ltd. * * Redistribution and use in source and binary forms, with or without @@ -27,86 +27,58 @@ #include "config.h" #include "RegularExpression.h" -#include "PlatformString.h" #include "Logging.h" -#include <wtf/RefCounted.h> #include <pcre/pcre.h> -#include <sys/types.h> namespace WebCore { -const size_t maxSubstrings = 10; -const size_t maxOffsets = 3 * maxSubstrings; - class RegularExpression::Private : public RefCounted<Private> { public: - static PassRefPtr<Private> create() { return adoptRef(new Private); } - static PassRefPtr<Private> create(const String& pattern, bool caseSensitive) { return adoptRef(new Private(pattern, caseSensitive)); } - + static PassRefPtr<Private> create(const String& pattern, TextCaseSensitivity); ~Private(); - void compile(bool caseSensitive); + JSRegExp* regexp() const { return m_regexp; } + int lastMatchLength; - String pattern; - JSRegExp* regex; - - String lastMatchString; - int lastMatchOffsets[maxOffsets]; - int lastMatchCount; - int lastMatchPos; - int lastMatchLength; - private: - Private(); - Private(const String& pattern, bool caseSensitive); -}; - -RegularExpression::Private::Private() - : pattern("") -{ - compile(true); -} + Private(const String& pattern, TextCaseSensitivity); + static JSRegExp* compile(const String& pattern, TextCaseSensitivity); -RegularExpression::Private::Private(const String& p, bool caseSensitive) - : pattern(p) - , lastMatchPos(-1) - , lastMatchLength(-1) -{ - compile(caseSensitive); -} + JSRegExp* m_regexp; +}; -void RegularExpression::Private::compile(bool caseSensitive) +inline JSRegExp* RegularExpression::Private::compile(const String& pattern, TextCaseSensitivity caseSensitivity) { const char* errorMessage; - regex = jsRegExpCompile(pattern.characters(), pattern.length(), - caseSensitive ? JSRegExpDoNotIgnoreCase : JSRegExpIgnoreCase, JSRegExpSingleLine, + JSRegExp* regexp = jsRegExpCompile(pattern.characters(), pattern.length(), + caseSensitivity == TextCaseSensitive ? JSRegExpDoNotIgnoreCase : JSRegExpIgnoreCase, JSRegExpSingleLine, 0, &errorMessage); - if (!regex) + if (!regexp) LOG_ERROR("RegularExpression: pcre_compile failed with '%s'", errorMessage); + return regexp; } -RegularExpression::Private::~Private() +inline RegularExpression::Private::Private(const String& pattern, TextCaseSensitivity caseSensitivity) + : lastMatchLength(-1) + , m_regexp(compile(pattern, caseSensitivity)) { - jsRegExpFree(regex); } - -RegularExpression::RegularExpression() - : d(Private::create()) +inline PassRefPtr<RegularExpression::Private> RegularExpression::Private::create(const String& pattern, TextCaseSensitivity caseSensitivity) { + return adoptRef(new Private(pattern, caseSensitivity)); } -RegularExpression::RegularExpression(const String& pattern, bool caseSensitive) - : d(Private::create(pattern, caseSensitive)) +RegularExpression::Private::~Private() { + jsRegExpFree(m_regexp); } -RegularExpression::RegularExpression(const char* pattern) - : d(Private::create(pattern, true)) +RegularExpression::RegularExpression(const String& pattern, TextCaseSensitivity caseSensitivity) + : d(Private::create(pattern, caseSensitivity)) { } - RegularExpression::RegularExpression(const RegularExpression& re) : d(re.d) { @@ -118,52 +90,41 @@ RegularExpression::~RegularExpression() RegularExpression& RegularExpression::operator=(const RegularExpression& re) { - RegularExpression tmp(re); - tmp.d.swap(d); + d = re.d; return *this; } -String RegularExpression::pattern() const -{ - return d->pattern; -} - int RegularExpression::match(const String& str, int startFrom, int* matchLength) const { + if (!d->regexp()) + return -1; + if (str.isNull()) return -1; - d->lastMatchString = str; // First 2 offsets are start and end offsets; 3rd entry is used internally by pcre - d->lastMatchCount = jsRegExpExecute(d->regex, d->lastMatchString.characters(), - d->lastMatchString.length(), startFrom, d->lastMatchOffsets, maxOffsets); - if (d->lastMatchCount < 0) { - if (d->lastMatchCount != JSRegExpErrorNoMatch) - LOG_ERROR("RegularExpression: pcre_exec() failed with result %d", d->lastMatchCount); - d->lastMatchPos = -1; + static const size_t maxOffsets = 3; + int offsets[maxOffsets]; + int result = jsRegExpExecute(d->regexp(), str.characters(), str.length(), startFrom, offsets, maxOffsets); + if (result < 0) { + if (result != JSRegExpErrorNoMatch) + LOG_ERROR("RegularExpression: pcre_exec() failed with result %d", result); d->lastMatchLength = -1; - d->lastMatchString = String(); return -1; } - + // 1 means 1 match; 0 means more than one match. First match is recorded in offsets. - d->lastMatchPos = d->lastMatchOffsets[0]; - d->lastMatchLength = d->lastMatchOffsets[1] - d->lastMatchOffsets[0]; + d->lastMatchLength = offsets[1] - offsets[0]; if (matchLength) *matchLength = d->lastMatchLength; - return d->lastMatchPos; -} - -int RegularExpression::search(const String& str, int startFrom) const -{ - if (startFrom < 0) - startFrom = str.length() - startFrom; - return match(str, startFrom, 0); + return offsets[0]; } int RegularExpression::searchRev(const String& str) const { - // FIXME: Total hack for now. Search forward, return the last, greedy match + // FIXME: This could be faster if it actually searched backwards. + // Instead, it just searches forwards, multiple times until it finds the last match. + int start = 0; int pos; int lastPos = -1; @@ -180,17 +141,10 @@ int RegularExpression::searchRev(const String& str) const start = pos + 1; } } while (pos != -1); - d->lastMatchPos = lastPos; d->lastMatchLength = lastMatchLength; return lastPos; } -int RegularExpression::pos(int n) -{ - ASSERT(n == 0); - return d->lastMatchPos; -} - int RegularExpression::matchedLength() const { return d->lastMatchLength; diff --git a/WebCore/platform/text/RegularExpression.h b/WebCore/platform/text/RegularExpression.h index 5d1991e..3254067 100644 --- a/WebCore/platform/text/RegularExpression.h +++ b/WebCore/platform/text/RegularExpression.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2003, 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 @@ -26,29 +26,21 @@ #ifndef RegularExpression_h #define RegularExpression_h -#include <wtf/RefPtr.h> +#include "PlatformString.h" namespace WebCore { -class String; - class RegularExpression { public: - RegularExpression(); - RegularExpression(const String&, bool caseSensitive = false); - RegularExpression(const char*); + RegularExpression(const String&, TextCaseSensitivity); ~RegularExpression(); RegularExpression(const RegularExpression&); RegularExpression& operator=(const RegularExpression&); - String pattern() const; int match(const String&, int startFrom = 0, int* matchLength = 0) const; - - int search(const String&, int startFrom = 0) const; int searchRev(const String&) const; - int pos(int n = 0); int matchedLength() const; private: diff --git a/WebCore/platform/text/String.cpp b/WebCore/platform/text/String.cpp index 44500e1..638e45f 100644 --- a/WebCore/platform/text/String.cpp +++ b/WebCore/platform/text/String.cpp @@ -25,7 +25,7 @@ #include "FloatConversion.h" #include "StringBuffer.h" #include "TextEncoding.h" -#include <kjs/dtoa.h> +#include <wtf/dtoa.h> #include <limits> #include <stdarg.h> #include <wtf/ASCIICType.h> @@ -248,6 +248,13 @@ 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) @@ -276,6 +283,13 @@ String String::simplifyWhiteSpace() const return m_impl->simplifyWhiteSpace(); } +String String::removeCharacters(CharacterMatchFunctionPtr findMatch) const +{ + if (!m_impl) + return String(); + return m_impl->removeCharacters(findMatch); +} + String String::foldCase() const { if (!m_impl) @@ -364,6 +378,16 @@ String String::format(const char *format, ...) #endif } +String String::number(short n) +{ + return String::format("%hd", n); +} + +String String::number(unsigned short n) +{ + return String::format("%hu", n); +} + String String::number(int n) { return String::format("%d", n); @@ -791,7 +815,7 @@ double charactersToDouble(const UChar* data, size_t length, bool* ok) bytes[i] = data[i] < 0x7F ? data[i] : '?'; bytes[length] = '\0'; char* end; - double val = JSC::strtod(bytes.data(), &end); + double val = WTF::strtod(bytes.data(), &end); if (ok) *ok = (end == 0 || *end == '\0'); return val; @@ -823,7 +847,9 @@ PassRefPtr<SharedBuffer> utf8Buffer(const String& string) } // namespace WebCore #ifndef NDEBUG -// For debugging only -- leaks memory +// For use in the debugger - leaks memory +WebCore::String* string(const char*); + WebCore::String* string(const char* s) { return new WebCore::String(s); diff --git a/WebCore/platform/text/StringHash.h b/WebCore/platform/text/StringHash.h index c6e08a6..336dce3 100644 --- a/WebCore/platform/text/StringHash.h +++ b/WebCore/platform/text/StringHash.h @@ -21,8 +21,9 @@ #ifndef StringHash_h #define StringHash_h -#include "AtomicStringImpl.h" +#include "AtomicString.h" #include "PlatformString.h" +#include <wtf/HashFunctions.h> #include <wtf/HashTraits.h> #include <wtf/unicode/Unicode.h> @@ -76,9 +77,6 @@ namespace WebCore { }; class CaseFoldingHash { - private: - // Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's - static const unsigned PHI = 0x9e3779b9U; public: // Paul Hsieh's SuperFastHash // http://www.azillionmonkeys.com/qed/hash.html @@ -86,7 +84,7 @@ namespace WebCore { { unsigned l = length; const UChar* s = data; - uint32_t hash = PHI; + uint32_t hash = WTF::stringHashingStartValue; uint32_t tmp; int rem = l & 1; @@ -136,7 +134,7 @@ namespace WebCore { unsigned l = length; const char* s = str; - uint32_t hash = PHI; + uint32_t hash = WTF::stringHashingStartValue; uint32_t tmp; int rem = l & 1; @@ -199,10 +197,18 @@ namespace WebCore { { return hash(key.impl()); } + static unsigned hash(const AtomicString& key) + { + return hash(key.impl()); + } static bool equal(const String& a, const String& b) { return equal(a.impl(), b.impl()); } + static bool equal(const AtomicString& a, const AtomicString& b) + { + return (a == b) || equal(a.impl(), b.impl()); + } static const bool safeToCompareToEmptyOrDeleted = false; }; diff --git a/WebCore/platform/text/StringImpl.cpp b/WebCore/platform/text/StringImpl.cpp index 911c0dc..0556f8e 100644 --- a/WebCore/platform/text/StringImpl.cpp +++ b/WebCore/platform/text/StringImpl.cpp @@ -33,8 +33,10 @@ #include "StringHash.h" #include "TextBreakIterator.h" #include "TextEncoding.h" -#include <kjs/dtoa.h> +#include "ThreadGlobalData.h" +#include <wtf/dtoa.h> #include <wtf/Assertions.h> +#include <wtf/Threading.h> #include <wtf/unicode/Unicode.h> using namespace WTF; @@ -164,8 +166,7 @@ StringImpl::~StringImpl() StringImpl* StringImpl::empty() { - static StringImpl* e = new StringImpl; - return e; + return threadGlobalData().emptyString(); } bool StringImpl::containsOnlyWhitespace() @@ -188,6 +189,17 @@ PassRefPtr<StringImpl> StringImpl::substring(unsigned pos, unsigned len) return create(m_data + pos, len); } +PassRefPtr<StringImpl> StringImpl::substringCopy(unsigned pos, unsigned len) +{ + if (pos >= m_length) + pos = m_length; + if (len > m_length - pos) + len = m_length - pos; + if (!len) + return adoptRef(new StringImpl); + return substring(pos, len); +} + UChar32 StringImpl::characterStartingAt(unsigned i) { if (U16_IS_SINGLE(m_data[i])) @@ -334,6 +346,38 @@ PassRefPtr<StringImpl> StringImpl::stripWhiteSpace() return create(m_data + start, end + 1 - start); } +PassRefPtr<StringImpl> StringImpl::removeCharacters(CharacterMatchFunctionPtr findMatch) +{ + const UChar* from = m_data; + const UChar* fromend = from + m_length; + + // Assume the common case will not remove any characters + while (from != fromend && !findMatch(*from)) + from++; + if (from == fromend) + return this; + + StringBuffer data(m_length); + UChar* to = data.characters(); + unsigned outc = from - m_data; + + if (outc) + memcpy(to, m_data, outc * sizeof(UChar)); + + while (true) { + while (from != fromend && findMatch(*from)) + from++; + while (from != fromend && !findMatch(*from)) + to[outc++] = *from++; + if (from == fromend) + break; + } + + data.shrink(outc); + + return adopt(data); +} + PassRefPtr<StringImpl> StringImpl::simplifyWhiteSpace() { StringBuffer data(m_length); @@ -510,6 +554,11 @@ int StringImpl::find(UChar c, int start) return WebCore::find(m_data, m_length, c, start); } +int StringImpl::find(CharacterMatchFunctionPtr matchFunction, int start) +{ + return WebCore::find(m_data, m_length, matchFunction, start); +} + int StringImpl::find(StringImpl* str, int index, bool caseSensitive) { /* diff --git a/WebCore/platform/text/StringImpl.h b/WebCore/platform/text/StringImpl.h index 57f64c8..281aa37 100644 --- a/WebCore/platform/text/StringImpl.h +++ b/WebCore/platform/text/StringImpl.h @@ -47,12 +47,17 @@ struct HashAndCharactersTranslator; struct StringHash; struct UCharBufferTranslator; +enum TextCaseSensitivity { TextCaseSensitive, TextCaseInsensitive }; + +typedef bool (*CharacterMatchFunctionPtr)(UChar); + class StringImpl : public RefCounted<StringImpl> { friend class AtomicString; friend struct CStringTranslator; friend struct HashAndCharactersTranslator; friend struct UCharBufferTranslator; private: + friend class ThreadGlobalData; StringImpl(); StringImpl(const UChar*, unsigned length); StringImpl(const char*, unsigned length); @@ -94,6 +99,12 @@ public: // 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> substring(unsigned pos, unsigned len = UINT_MAX); UChar operator[](unsigned i) { ASSERT(i < m_length); return m_data[i]; } @@ -124,14 +135,17 @@ public: PassRefPtr<StringImpl> stripWhiteSpace(); PassRefPtr<StringImpl> simplifyWhiteSpace(); + PassRefPtr<StringImpl> removeCharacters(CharacterMatchFunctionPtr); + int find(const char*, int index = 0, bool caseSensitive = true); int find(UChar, int index = 0); + int find(CharacterMatchFunctionPtr, int index = 0); int find(StringImpl*, int index, bool caseSensitive = true); int reverseFind(UChar, int index); int reverseFind(StringImpl*, int index, bool caseSensitive = true); - bool startsWith(StringImpl* m_data, bool caseSensitive = true) { return find(m_data, 0, caseSensitive) == 0; } + bool startsWith(StringImpl* m_data, bool caseSensitive = true) { return reverseFind(m_data, 0, caseSensitive) == 0; } bool endsWith(StringImpl*, bool caseSensitive = true); PassRefPtr<StringImpl> replace(UChar, UChar); diff --git a/WebCore/platform/text/TextCodecICU.cpp b/WebCore/platform/text/TextCodecICU.cpp index 0a324a2..72d45ad 100644 --- a/WebCore/platform/text/TextCodecICU.cpp +++ b/WebCore/platform/text/TextCodecICU.cpp @@ -30,10 +30,12 @@ #include "CharacterNames.h" #include "CString.h" #include "PlatformString.h" +#include "ThreadGlobalData.h" #include <unicode/ucnv.h> #include <unicode/ucnv_cb.h> #include <wtf/Assertions.h> #include <wtf/StringExtras.h> +#include <wtf/Threading.h> using std::auto_ptr; using std::min; @@ -42,7 +44,16 @@ namespace WebCore { const size_t ConversionBufferSize = 16384; -static UConverter* cachedConverterICU; +ICUConverterWrapper::~ICUConverterWrapper() +{ + if (converter) + ucnv_close(converter); +} + +static UConverter*& cachedConverterICU() +{ + return threadGlobalData().cachedConverterICU().converter; +} static auto_ptr<TextCodec> newTextCodecICU(const TextEncoding& encoding, const void*) { @@ -95,12 +106,12 @@ void TextCodecICU::registerExtendedEncodingNames(EncodingNameRegistrar registrar standardName = "GBK"; // Similarly, EUC-KR encodings all map to an extended version. else if (strcmp(standardName, "KSC_5601") == 0 || strcmp(standardName, "EUC-KR") == 0 || strcmp(standardName, "cp1363") == 0) - standardName = "windows-949-2000"; + standardName = "windows-949"; // And so on. else if (strcasecmp(standardName, "iso-8859-9") == 0) // This name is returned in different case by ICU 3.2 and 3.6. standardName = "windows-1254"; else if (strcmp(standardName, "TIS-620") == 0) - standardName = "windows-874-2000"; + standardName = "windows-874"; registrar(standardName, standardName); @@ -132,19 +143,23 @@ void TextCodecICU::registerExtendedEncodingNames(EncodingNameRegistrar registrar registrar("xmacukrainian", "x-mac-cyrillic"); #endif registrar("cnbig5", "Big5"); - registrar("cngb", "EUC-CN"); + registrar("xxbig5", "Big5"); + registrar("cngb", "GBK"); + registrar("csgb231280", "GBK"); + registrar("xeuccn", "GBK"); + registrar("xgbk", "GBK"); registrar("csISO88598I", "ISO_8859-8-I"); - registrar("csgb231280", "EUC-CN"); - registrar("dos874", "cp874"); registrar("koi", "KOI8-R"); registrar("logical", "ISO-8859-8-I"); registrar("unicode11utf8", "UTF-8"); registrar("unicode20utf8", "UTF-8"); + registrar("xunicode20utf8", "UTF-8"); registrar("visual", "ISO-8859-8"); registrar("winarabic", "windows-1256"); registrar("winbaltic", "windows-1257"); registrar("wincyrillic", "windows-1251"); - registrar("iso885911", "windows874-2000"); + registrar("iso885911", "windows-874"); + registrar("dos874", "windows-874"); registrar("wingreek", "windows-1253"); registrar("winhebrew", "windows-1255"); registrar("winlatin2", "windows-1250"); @@ -153,15 +168,8 @@ void TextCodecICU::registerExtendedEncodingNames(EncodingNameRegistrar registrar registrar("xcp1250", "windows-1250"); registrar("xcp1251", "windows-1251"); registrar("xeuc", "EUC-JP"); - registrar("xeuccn", "EUC-CN"); - registrar("xgbk", "EUC-CN"); - registrar("xunicode20utf8", "UTF-8"); - registrar("xwindows949", "windows-949-2000"); - registrar("xxbig5", "Big5"); - - // This alias is present in modern versions of ICU, but it has no standard name, - // so we give one to it manually. It is not present in ICU 3.2. - registrar("windows874", "windows874-2000"); + registrar("xwindows949", "windows-949"); + registrar("xuhc", "windows-949"); // These aliases are present in modern versions of ICU, but use different codecs, and have no standard names. // They are not present in ICU 3.2. @@ -205,9 +213,10 @@ TextCodecICU::~TextCodecICU() void TextCodecICU::releaseICUConverter() const { if (m_converterICU) { - if (cachedConverterICU) - ucnv_close(cachedConverterICU); - cachedConverterICU = m_converterICU; + UConverter*& cachedConverter = cachedConverterICU(); + if (cachedConverter) + ucnv_close(cachedConverter); + cachedConverter = m_converterICU; m_converterICU = 0; } } @@ -221,12 +230,13 @@ void TextCodecICU::createICUConverter() const UErrorCode err; - if (cachedConverterICU) { + UConverter*& cachedConverter = cachedConverterICU(); + if (cachedConverter) { err = U_ZERO_ERROR; - const char* cachedName = ucnv_getName(cachedConverterICU, &err); + const char* cachedName = ucnv_getName(cachedConverter, &err); if (U_SUCCESS(err) && m_encoding == cachedName) { - m_converterICU = cachedConverterICU; - cachedConverterICU = 0; + m_converterICU = cachedConverter; + cachedConverter = 0; return; } } @@ -422,7 +432,7 @@ CString TextCodecICU::encode(const UChar* characters, size_t length, Unencodable // until then, we change the backslash into a yen sign. // Encoding will change the yen sign back into a backslash. String copy(characters, length); - copy.replace('\\', m_encoding.backslashAsCurrencySymbol()); + copy = m_encoding.displayString(copy.impl()); const UChar* source = copy.characters(); const UChar* sourceLimit = source + copy.length(); diff --git a/WebCore/platform/text/TextCodecICU.h b/WebCore/platform/text/TextCodecICU.h index 9c9a4a7b..f07758f 100644 --- a/WebCore/platform/text/TextCodecICU.h +++ b/WebCore/platform/text/TextCodecICU.h @@ -64,6 +64,16 @@ namespace WebCore { mutable bool m_needsGBKFallbacks; }; + struct ICUConverterWrapper { + ICUConverterWrapper() + : converter(0) + { + } + ~ICUConverterWrapper(); + + UConverter* converter; + }; + } // namespace WebCore #endif // TextCodecICU_h diff --git a/WebCore/platform/text/TextCodecUTF16.cpp b/WebCore/platform/text/TextCodecUTF16.cpp index 88e4e73..a4d0d28 100644 --- a/WebCore/platform/text/TextCodecUTF16.cpp +++ b/WebCore/platform/text/TextCodecUTF16.cpp @@ -65,7 +65,7 @@ void TextCodecUTF16::registerCodecs(TextCodecRegistrar registrar) registrar("UTF-16BE", newStreamingTextDecoderUTF16BE, 0); } -String TextCodecUTF16::decode(const char* bytes, size_t length, bool, bool stopOnError, bool& sawError) +String TextCodecUTF16::decode(const char* bytes, size_t length, bool, bool, bool&) { if (!length) return String(); @@ -89,18 +89,19 @@ String TextCodecUTF16::decode(const char* bytes, size_t length, bool, bool stopO numChars -= 1; } - if (m_littleEndian) + if (m_littleEndian) { for (size_t i = 0; i < numChars; ++i) { UChar c = p[0] | (p[1] << 8); p += 2; *q++ = c; } - else + } else { for (size_t i = 0; i < numChars; ++i) { UChar c = (p[0] << 8) | p[1]; p += 2; *q++ = c; } + } if (numBytes & 1) { ASSERT(!m_haveBufferedByte); diff --git a/WebCore/platform/text/TextEncoding.cpp b/WebCore/platform/text/TextEncoding.cpp index 9026049..063d96b 100644 --- a/WebCore/platform/text/TextEncoding.cpp +++ b/WebCore/platform/text/TextEncoding.cpp @@ -39,6 +39,7 @@ #endif #include <wtf/HashSet.h> #include <wtf/OwnPtr.h> +#include <wtf/StdLibExtras.h> namespace WebCore { @@ -49,13 +50,21 @@ static void addEncodingName(HashSet<const char*>& set, const char* name) set.add(atomicName); } +static const TextEncoding& UTF7Encoding() +{ + static TextEncoding globalUTF7Encoding("UTF-7"); + return globalUTF7Encoding; +} + TextEncoding::TextEncoding(const char* name) : m_name(atomicCanonicalTextEncodingName(name)) + , m_backslashAsCurrencySymbol(backslashAsCurrencySymbol()) { } TextEncoding::TextEncoding(const String& name) : m_name(atomicCanonicalTextEncodingName(name.characters(), name.length())) + , m_backslashAsCurrencySymbol(backslashAsCurrencySymbol()) { } @@ -122,7 +131,7 @@ bool TextEncoding::isJapanese() const if (noExtendedTextEncodingNameUsed()) return false; - static HashSet<const char*> set; + DEFINE_STATIC_LOCAL(HashSet<const char*>, set, ()); if (set.isEmpty()) { addEncodingName(set, "x-mac-japanese"); addEncodingName(set, "cp932"); @@ -154,9 +163,29 @@ UChar TextEncoding::backslashAsCurrencySymbol() const return (m_name == a || m_name == b) ? 0x00A5 : '\\'; } -const TextEncoding& TextEncoding::closest8BitEquivalent() const +bool TextEncoding::isNonByteBasedEncoding() const +{ + return *this == UTF16LittleEndianEncoding() + || *this == UTF16BigEndianEncoding() + || *this == UTF32BigEndianEncoding() + || *this == UTF32LittleEndianEncoding(); +} + +const TextEncoding& TextEncoding::closestByteBasedEquivalent() const { - if (*this == UTF16BigEndianEncoding() || *this == UTF16LittleEndianEncoding()) + if (isNonByteBasedEncoding()) + return UTF8Encoding(); + return *this; +} + +// HTML5 specifies that UTF-8 be used in form submission when a form is +// is a part of a document in UTF-16 probably because UTF-16 is not a +// byte-based encoding and can contain 0x00. By extension, the same +// should be done for UTF-32. In case of UTF-7, it is a byte-based encoding, +// but it's fraught with problems and we'd rather steer clear of it. +const TextEncoding& TextEncoding::encodingForFormSubmission() const +{ + if (isNonByteBasedEncoding() || *this == UTF7Encoding()) return UTF8Encoding(); return *this; } @@ -197,7 +226,6 @@ const TextEncoding& UTF32LittleEndianEncoding() return globalUTF32LittleEndianEncoding; } - const TextEncoding& UTF8Encoding() { static TextEncoding globalUTF8Encoding("UTF-8"); diff --git a/WebCore/platform/text/TextEncoding.h b/WebCore/platform/text/TextEncoding.h index 0a0ab8c..b2bb816 100644 --- a/WebCore/platform/text/TextEncoding.h +++ b/WebCore/platform/text/TextEncoding.h @@ -44,8 +44,23 @@ namespace WebCore { const char* name() const { return m_name; } bool usesVisualOrdering() const; bool isJapanese() const; - UChar backslashAsCurrencySymbol() const; - const TextEncoding& closest8BitEquivalent() const; + + PassRefPtr<StringImpl> displayString(PassRefPtr<StringImpl> str) const { + if (m_backslashAsCurrencySymbol == '\\' || !str) + return str; + return str->replace('\\', m_backslashAsCurrencySymbol); + } + void displayBuffer(UChar* characters, unsigned len) const { + if (m_backslashAsCurrencySymbol == '\\') + return; + for (unsigned i = 0; i < len; ++i) { + if (characters[i] == '\\') + characters[i] = m_backslashAsCurrencySymbol; + } + } + + const TextEncoding& closestByteBasedEquivalent() const; + const TextEncoding& encodingForFormSubmission() const; String decode(const char* str, size_t length) const { @@ -56,7 +71,11 @@ namespace WebCore { CString encode(const UChar*, size_t length, UnencodableHandling) const; private: + UChar backslashAsCurrencySymbol() const; + const char* m_name; + UChar m_backslashAsCurrencySymbol; + bool isNonByteBasedEncoding() const; }; inline bool operator==(const TextEncoding& a, const TextEncoding& b) { return a.name() == b.name(); } diff --git a/WebCore/platform/text/TextEncodingRegistry.cpp b/WebCore/platform/text/TextEncodingRegistry.cpp index 3f1f078..2d89fac 100644 --- a/WebCore/platform/text/TextEncodingRegistry.cpp +++ b/WebCore/platform/text/TextEncodingRegistry.cpp @@ -32,8 +32,11 @@ #include "TextCodecUTF16.h" #include <wtf/ASCIICType.h> #include <wtf/Assertions.h> +#include <wtf/HashFunctions.h> #include <wtf/HashMap.h> +#include <wtf/StdLibExtras.h> #include <wtf/StringExtras.h> +#include <wtf/Threading.h> #if USE(ICU_UNICODE) #include "TextCodecICU.h" @@ -57,10 +60,6 @@ const size_t maxEncodingNameLength = 63; // it will properly skip those characters too. struct TextEncodingNameHash { - // Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's - // or anything like that. - static const unsigned PHI = 0x9e3779b9U; - static bool equal(const char* s1, const char* s2) { char c1; @@ -83,7 +82,7 @@ struct TextEncodingNameHash { // http://burtleburtle.net/bob/hash/doobs.html static unsigned hash(const char* s) { - unsigned h = PHI; + unsigned h = WTF::stringHashingStartValue; for (;;) { char c; do { @@ -113,6 +112,15 @@ struct TextCodecFactory { typedef HashMap<const char*, const char*, TextEncodingNameHash> TextEncodingNameMap; typedef HashMap<const char*, TextCodecFactory> TextCodecMap; +static Mutex& encodingRegistryMutex() +{ + // We don't have to use AtomicallyInitializedStatic here because + // this function is called on the main thread for any page before + // it is used in worker threads. + DEFINE_STATIC_LOCAL(Mutex, mutex, ()); + return mutex; +} + static TextEncodingNameMap* textEncodingNameMap; static TextCodecMap* textCodecMap; static bool didExtendTextCodecMaps; @@ -154,13 +162,17 @@ static void addToTextEncodingNameMap(const char* alias, const char* name) static void addToTextCodecMap(const char* name, NewTextCodecFunction function, const void* additionalData) { - TextEncoding encoding(name); - ASSERT(encoding.isValid()); - textCodecMap->add(encoding.name(), TextCodecFactory(function, additionalData)); + const char* atomicName = textEncodingNameMap->get(name); + ASSERT(atomicName); + textCodecMap->add(atomicName, TextCodecFactory(function, additionalData)); } static void buildBaseTextCodecMaps() { + ASSERT(isMainThread()); + ASSERT(!textCodecMap); + ASSERT(!textEncodingNameMap); + textCodecMap = new TextCodecMap; textEncodingNameMap = new TextEncodingNameMap; @@ -199,6 +211,8 @@ static void extendTextCodecMaps() std::auto_ptr<TextCodec> newTextCodec(const TextEncoding& encoding) { + MutexLocker lock(encodingRegistryMutex()); + ASSERT(textCodecMap); TextCodecFactory factory = textCodecMap->get(encoding.name()); ASSERT(factory.function); @@ -211,6 +225,9 @@ const char* atomicCanonicalTextEncodingName(const char* name) return 0; if (!textEncodingNameMap) buildBaseTextCodecMaps(); + + MutexLocker lock(encodingRegistryMutex()); + if (const char* atomicName = textEncodingNameMap->get(name)) return atomicName; if (didExtendTextCodecMaps) @@ -238,6 +255,7 @@ const char* atomicCanonicalTextEncodingName(const UChar* characters, size_t leng bool noExtendedTextEncodingNameUsed() { + // If the calling thread did not use extended encoding names, it is fine for it to use a stale false value. return !didExtendTextCodecMaps; } diff --git a/WebCore/platform/text/TextStream.cpp b/WebCore/platform/text/TextStream.cpp index 5b7a0c7..eb4bae7 100644 --- a/WebCore/platform/text/TextStream.cpp +++ b/WebCore/platform/text/TextStream.cpp @@ -33,6 +33,11 @@ namespace WebCore { static const size_t printBufferSize = 100; // large enough for any integer or floating point value in string format, including trailing null character +TextStream& TextStream::operator<<(bool b) +{ + return *this << (b ? "1" : "0"); +} + TextStream& TextStream::operator<<(int i) { char buffer[printBufferSize]; diff --git a/WebCore/platform/text/TextStream.h b/WebCore/platform/text/TextStream.h index 6fb3f4b..71034f3 100644 --- a/WebCore/platform/text/TextStream.h +++ b/WebCore/platform/text/TextStream.h @@ -35,6 +35,7 @@ class String; class TextStream { public: + TextStream& operator<<(bool); TextStream& operator<<(int); TextStream& operator<<(unsigned); TextStream& operator<<(long); diff --git a/WebCore/platform/gtk/SystemTimeGtk.cpp b/WebCore/platform/text/chromium/TextBreakIteratorInternalICUChromium.cpp index 9d26d41..09096d7 100644 --- a/WebCore/platform/gtk/SystemTimeGtk.cpp +++ b/WebCore/platform/text/chromium/TextBreakIteratorInternalICUChromium.cpp @@ -1,5 +1,6 @@ /* - * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Google Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -13,20 +14,19 @@ * * 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. + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * */ #include "config.h" -#include <glib.h> +#include "TextBreakIteratorInternalICU.h" namespace WebCore { -double currentTime() +const char* currentTextBreakLocaleID() { - GTimeVal now; - g_get_current_time(&now); - return static_cast<double>(now.tv_sec) + static_cast<double>(now.tv_usec / 1000000.0); + return "en_us"; } -} +} // namespace WebCore diff --git a/WebCore/platform/text/mac/ShapeArabic.c b/WebCore/platform/text/mac/ShapeArabic.c index 6dbc008..1e0d91b 100644 --- a/WebCore/platform/text/mac/ShapeArabic.c +++ b/WebCore/platform/text/mac/ShapeArabic.c @@ -347,8 +347,7 @@ isTashkeelChar(UChar ch) { */ static int32_t shapeUnicode(UChar *dest, int32_t sourceLength, - int32_t destSize,uint32_t options, - UErrorCode *pErrorCode, + int32_t destSize, int tashkeelFlag) { int32_t i, iend; @@ -528,11 +527,11 @@ int32_t shapeArabic(const UChar *source, int32_t sourceLength, UChar *dest, int3 switch(options&U_SHAPE_LETTERS_MASK) { case U_SHAPE_LETTERS_SHAPE : /* Call the shaping function with tashkeel flag == 1 */ - destLength = shapeUnicode(dest,sourceLength,destCapacity,options,pErrorCode,1); + destLength = shapeUnicode(dest,sourceLength,destCapacity,1); break; case U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED : /* Call the shaping function with tashkeel flag == 0 */ - destLength = shapeUnicode(dest,sourceLength,destCapacity,options,pErrorCode,0); + destLength = shapeUnicode(dest,sourceLength,destCapacity,0); break; case U_SHAPE_LETTERS_UNSHAPE : ASSERT_NOT_REACHED(); diff --git a/WebCore/platform/text/mac/StringImplMac.mm b/WebCore/platform/text/mac/StringImplMac.mm index 2180b94..3e0731c 100644 --- a/WebCore/platform/text/mac/StringImplMac.mm +++ b/WebCore/platform/text/mac/StringImplMac.mm @@ -21,6 +21,8 @@ #include "config.h" #include "StringImpl.h" +#include <Foundation/Foundation.h> + namespace WebCore { StringImpl::operator NSString *() diff --git a/WebCore/platform/text/mac/TextCodecMac.cpp b/WebCore/platform/text/mac/TextCodecMac.cpp index ac1f0fb..3baf21f 100644 --- a/WebCore/platform/text/mac/TextCodecMac.cpp +++ b/WebCore/platform/text/mac/TextCodecMac.cpp @@ -31,7 +31,9 @@ #include "CharacterNames.h" #include "CharsetData.h" #include "PlatformString.h" +#include "ThreadGlobalData.h" #include <wtf/Assertions.h> +#include <wtf/Threading.h> using std::auto_ptr; using std::min; @@ -43,8 +45,10 @@ namespace WebCore { const size_t ConversionBufferSize = 16384; -static TECObjectRef cachedConverterTEC; -static TECTextEncodingID cachedConverterEncoding = invalidEncoding; +static TECConverterWrapper& cachedConverterTEC() +{ + return threadGlobalData().cachedConverterTEC(); +} void TextCodecMac::registerEncodingNames(EncodingNameRegistrar registrar) { @@ -91,22 +95,26 @@ TextCodecMac::~TextCodecMac() void TextCodecMac::releaseTECConverter() const { if (m_converterTEC) { - if (cachedConverterTEC != 0) - TECDisposeConverter(cachedConverterTEC); - cachedConverterTEC = m_converterTEC; - cachedConverterEncoding = m_encoding; + TECConverterWrapper& cachedConverter = cachedConverterTEC(); + if (cachedConverter.converter) + TECDisposeConverter(cachedConverter.converter); + cachedConverter.converter = m_converterTEC; + cachedConverter.encoding = m_encoding; m_converterTEC = 0; } } OSStatus TextCodecMac::createTECConverter() const { - bool cachedEncodingEqual = cachedConverterEncoding == m_encoding; - cachedConverterEncoding = invalidEncoding; + TECConverterWrapper& cachedConverter = cachedConverterTEC(); + + bool cachedEncodingEqual = cachedConverter.encoding == m_encoding; + cachedConverter.encoding = invalidEncoding; + + if (cachedEncodingEqual && cachedConverter.converter) { + m_converterTEC = cachedConverter.converter; + cachedConverter.converter = 0; - if (cachedEncodingEqual && cachedConverterTEC) { - m_converterTEC = cachedConverterTEC; - cachedConverterTEC = 0; TECClearConverterContextInfo(m_converterTEC); } else { OSStatus status = TECCreateConverter(&m_converterTEC, m_encoding, @@ -116,7 +124,7 @@ OSStatus TextCodecMac::createTECConverter() const TECSetBasicOptions(m_converterTEC, kUnicodeForceASCIIRangeMask); } - + return noErr; } diff --git a/WebCore/platform/text/mac/TextCodecMac.h b/WebCore/platform/text/mac/TextCodecMac.h index aee4a97..3e7a237 100644 --- a/WebCore/platform/text/mac/TextCodecMac.h +++ b/WebCore/platform/text/mac/TextCodecMac.h @@ -60,6 +60,14 @@ namespace WebCore { mutable TECObjectRef m_converterTEC; }; + struct TECConverterWrapper { + TECConverterWrapper() : converter(0), encoding(invalidEncoding) { } + ~TECConverterWrapper() { if (converter) TECDisposeConverter(converter); } + + TECObjectRef converter; + TECTextEncodingID encoding; + }; + } // namespace WebCore #endif // TextCodecMac_h diff --git a/WebCore/platform/win/COMPtr.h b/WebCore/platform/win/COMPtr.h index 784495a..692706f 100644 --- a/WebCore/platform/win/COMPtr.h +++ b/WebCore/platform/win/COMPtr.h @@ -26,7 +26,9 @@ #ifndef COMPtr_h #define COMPtr_h +#ifndef NOMINMAX #define NOMINMAX +#endif #include <guiddef.h> #include <unknwn.h> diff --git a/WebCore/platform/win/ClipboardWin.cpp b/WebCore/platform/win/ClipboardWin.cpp index 129d881..7a88c3a 100644 --- a/WebCore/platform/win/ClipboardWin.cpp +++ b/WebCore/platform/win/ClipboardWin.cpp @@ -333,10 +333,15 @@ static HGLOBAL createGlobalImageFileDescriptor(const String& url, const String& fgd->fgd[0].dwFlags = FD_FILESIZE; fgd->fgd[0].nFileSizeLow = image->image()->data()->size(); - String extension("."); - extension += WebCore::MIMETypeRegistry::getPreferredExtensionForMIMEType(image->response().mimeType()); const String& preferredTitle = title.isEmpty() ? image->response().suggestedFilename() : title; - fsPath = filesystemPathFromUrlOrTitle(url, preferredTitle, extension.length() ? (TCHAR*)extension.charactersWithNullTermination() : 0, false); + String extension = image->image()->filenameExtension(); + if (extension.isEmpty()) { + // Do not continue processing in the rare and unusual case where a decoded image is not able + // to provide a filename extension. Something tricky (like a bait-n-switch) is going on + return 0; + } + extension.insert(".", 0); + fsPath = filesystemPathFromUrlOrTitle(url, preferredTitle, (TCHAR*)extension.charactersWithNullTermination(), false); if (fsPath.length() <= 0) { GlobalUnlock(memObj); diff --git a/WebCore/platform/win/ContextMenuItemWin.cpp b/WebCore/platform/win/ContextMenuItemWin.cpp index bd10c91..648d593 100644 --- a/WebCore/platform/win/ContextMenuItemWin.cpp +++ b/WebCore/platform/win/ContextMenuItemWin.cpp @@ -102,8 +102,7 @@ LPMENUITEMINFO ContextMenuItem::releasePlatformDescription() ContextMenuItemType ContextMenuItem::type() const { ContextMenuItemType type = ActionType; - - if ((m_platformDescription->fType & MFT_STRING) && m_platformDescription->hSubMenu) + if (((m_platformDescription->fType & ~MFT_OWNERDRAW) == MFT_STRING) && m_platformDescription->hSubMenu) type = SubmenuType; else if (m_platformDescription->fType & MFT_SEPARATOR) type = SeparatorType; @@ -187,7 +186,7 @@ void ContextMenuItem::setEnabled(bool enabled) bool ContextMenuItem::enabled() const { - return m_platformDescription->fState & MFS_ENABLED; + return !(m_platformDescription->fState & MFS_DISABLED); } } diff --git a/WebCore/platform/win/DragImageCGWin.cpp b/WebCore/platform/win/DragImageCGWin.cpp index 7788572..77b358b 100644 --- a/WebCore/platform/win/DragImageCGWin.cpp +++ b/WebCore/platform/win/DragImageCGWin.cpp @@ -37,6 +37,11 @@ namespace WebCore { +void deallocContext(CGContextRef target) +{ + CGContextRelease(target); +} + HBITMAP allocImage(HDC dc, IntSize size, CGContextRef *targetRef) { HBITMAP hbmp; diff --git a/WebCore/platform/win/DragImageCairoWin.cpp b/WebCore/platform/win/DragImageCairoWin.cpp index 5fff64f..1b8fb06 100644 --- a/WebCore/platform/win/DragImageCairoWin.cpp +++ b/WebCore/platform/win/DragImageCairoWin.cpp @@ -29,25 +29,170 @@ #include "CachedImage.h" #include "GraphicsContext.h" #include "Image.h" -#include "NotImplemented.h" #include "RetainPtr.h" +#include <cairo-win32.h> +#include "GraphicsContextPlatformPrivateCairo.h" + #include <windows.h> +extern "C" { +typedef struct _cairo* CairoContextRef; +} + namespace WebCore { +void deallocContext(CairoContextRef target) +{ + cairo_destroy(target); +} + +HBITMAP allocImage(HDC dc, IntSize size, CairoContextRef* targetRef) +{ + BITMAPINFO bmpInfo = {0}; + bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmpInfo.bmiHeader.biWidth = size.width(); + bmpInfo.bmiHeader.biHeight = size.height(); // Must be positive! + bmpInfo.bmiHeader.biPlanes = 1; + bmpInfo.bmiHeader.biBitCount = 32; + bmpInfo.bmiHeader.biCompression = BI_RGB; + bmpInfo.bmiHeader.biClrUsed = 0; // unused + bmpInfo.bmiHeader.biClrImportant = 0; + + LPVOID bits; + HBITMAP hbmp = CreateDIBSection(dc, &bmpInfo, DIB_RGB_COLORS, &bits, 0, 0); + + // At this point, we have a Cairo surface that points to a Windows DIB. The DIB interprets + // with the opposite meaning of positive Y axis, so everything we draw into this cairo + // context is going to be upside down. + if (!targetRef) + return hbmp; + + cairo_surface_t* bitmapContext = cairo_image_surface_create_for_data((unsigned char*)bits, + CAIRO_FORMAT_ARGB32, + bmpInfo.bmiHeader.biWidth, + bmpInfo.bmiHeader.biHeight, + bmpInfo.bmiHeader.biWidth * 4); + + if (!bitmapContext) { + DeleteObject(hbmp); + return 0; + } + + *targetRef = cairo_create (bitmapContext); + cairo_surface_destroy (bitmapContext); + + // At this point, we have a Cairo surface that points to a Windows DIB. The DIB interprets + // with the opposite meaning of positive Y axis, so everything we draw into this cairo + // context is going to be upside down. + // + // So, we must invert the CTM for the context so that drawing commands will be flipped + // before they get written to the internal buffer. + cairo_matrix_t matrix; + cairo_matrix_init(&matrix, 1.0, 0.0, 0.0, -1.0, 0.0, size.height()); + cairo_set_matrix(*targetRef, &matrix); + + return hbmp; +} + +static cairo_surface_t* createCairoContextFromBitmap(HBITMAP bitmap) +{ + BITMAP info; + GetObject(bitmap, sizeof(info), &info); + ASSERT(info.bmBitsPixel == 32); + + // At this point, we have a Cairo surface that points to a Windows BITMAP. The BITMAP + // has the opposite meaning of positive Y axis, so everything we draw into this cairo + // context is going to be upside down. + return cairo_image_surface_create_for_data((unsigned char*)info.bmBits, + CAIRO_FORMAT_ARGB32, + info.bmWidth, + info.bmHeight, + info.bmWidthBytes); +} + DragImageRef scaleDragImage(DragImageRef image, FloatSize scale) { - notImplemented(); + // FIXME: due to the way drag images are done on windows we need + // to preprocess the alpha channel <rdar://problem/5015946> + if (!image) + return 0; + + IntSize srcSize = dragImageSize(image); + IntSize dstSize(static_cast<int>(srcSize.width() * scale.width()), static_cast<int>(srcSize.height() * scale.height())); + + HBITMAP hbmp = 0; + HDC dc = GetDC(0); + HDC dstDC = CreateCompatibleDC(dc); + + if (!dstDC) + goto exit; + + CairoContextRef targetContext; + hbmp = allocImage(dstDC, dstSize, &targetContext); + if (!hbmp) + goto exit; + + cairo_surface_t* srcImage = createCairoContextFromBitmap(image); + + // Scale the target surface to the new image size, and flip it + // so that when we set the srcImage as the surface it will draw + // right-side-up. + cairo_translate(targetContext, 0, dstSize.height()); + cairo_scale(targetContext, scale.width(), -scale.height()); + cairo_set_source_surface (targetContext, srcImage, 0.0, 0.0); - return image; + // Now we can paint and get the correct result + cairo_paint(targetContext); + + cairo_surface_destroy (srcImage); + cairo_destroy(targetContext); + ::DeleteObject(image); + image = 0; + +exit: + if (!hbmp) + hbmp = image; + if (dstDC) + DeleteDC(dstDC); + ReleaseDC(0, dc); + return hbmp; } DragImageRef createDragImageFromImage(Image* img) { - notImplemented(); + HBITMAP hbmp = 0; + HDC dc = GetDC(0); + HDC workingDC = CreateCompatibleDC(dc); + if (!workingDC) + goto exit; + + CairoContextRef drawContext = 0; + hbmp = allocImage(workingDC, img->size(), &drawContext); + if (!hbmp) + goto exit; + + if (!drawContext) { + ::DeleteObject(hbmp); + hbmp = 0; + } + + cairo_set_source_rgb (drawContext, 1.0, 0.0, 1.0); + cairo_fill_preserve (drawContext); + + cairo_surface_t* srcImage = img->nativeImageForCurrentFrame(); + + // Draw the image. + cairo_set_source_surface(drawContext, srcImage, 0.0, 0.0); + cairo_paint(drawContext); + + cairo_destroy (drawContext); - return 0; +exit: + if (workingDC) + DeleteDC(workingDC); + ReleaseDC(0, dc); + return hbmp; } } diff --git a/WebCore/platform/win/LoggingWin.cpp b/WebCore/platform/win/LoggingWin.cpp new file mode 100644 index 0000000..bb0e4f4 --- /dev/null +++ b/WebCore/platform/win/LoggingWin.cpp @@ -0,0 +1,100 @@ +/* + * 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 "Logging.h" + +#include "PlatformString.h" +#include <wtf/OwnArrayPtr.h> + +namespace WebCore { + +static inline void initializeWithUserDefault(WTFLogChannel& channel) +{ + DWORD length = GetEnvironmentVariableA(channel.defaultName, 0, 0); + if (!length) + return; + + OwnArrayPtr<char> buffer(new char[length]); + + if (!GetEnvironmentVariableA(channel.defaultName, buffer.get(), length)) + return; + + String variableValue(buffer.get()); + + static const String& hexadecimalPrefix = *new String("0x"); + if (variableValue.length() < 3 || !variableValue.startsWith(hexadecimalPrefix, false)) { + LOG_ERROR("Unable to parse hex value for %s (%s), logging is off", channel.defaultName, buffer.get()); + return; + } + + String unprefixedValue = variableValue.substring(2); + + // Now parse the unprefixed string as a hexadecimal number. + bool parsedSuccessfully = false; + unsigned logLevel = unprefixedValue.toUIntStrict(&parsedSuccessfully, 16); + + if (!parsedSuccessfully) { + LOG_ERROR("Unable to parse hex value for %s (%s), logging is off", channel.defaultName, buffer.get()); + return; + } + + if ((logLevel & channel.mask) == channel.mask) + channel.state = WTFLogChannelOn; + else + channel.state = WTFLogChannelOff; +} + +void InitializeLoggingChannelsIfNecessary() +{ + static bool haveInitializedLoggingChannels = false; + if (haveInitializedLoggingChannels) + return; + haveInitializedLoggingChannels = true; + + initializeWithUserDefault(LogNotYetImplemented); + initializeWithUserDefault(LogFrames); + initializeWithUserDefault(LogLoading); + initializeWithUserDefault(LogPopupBlocking); + initializeWithUserDefault(LogEvents); + initializeWithUserDefault(LogEditing); + initializeWithUserDefault(LogTextConversion); + initializeWithUserDefault(LogIconDatabase); + initializeWithUserDefault(LogSQLDatabase); + initializeWithUserDefault(LogSpellingAndGrammar); + initializeWithUserDefault(LogBackForward); + initializeWithUserDefault(LogHistory); + initializeWithUserDefault(LogPageCache); + initializeWithUserDefault(LogPlatformLeaks); + initializeWithUserDefault(LogNetwork); + initializeWithUserDefault(LogFTP); + initializeWithUserDefault(LogThreading); + initializeWithUserDefault(LogStorageAPI); + initializeWithUserDefault(LogMedia); + initializeWithUserDefault(LogPlugin); + initializeWithUserDefault(LogArchives); +} + +} // namespace WebCore diff --git a/WebCore/platform/win/MIMETypeRegistryWin.cpp b/WebCore/platform/win/MIMETypeRegistryWin.cpp index 06c6f36..6885402 100644 --- a/WebCore/platform/win/MIMETypeRegistryWin.cpp +++ b/WebCore/platform/win/MIMETypeRegistryWin.cpp @@ -32,16 +32,6 @@ namespace WebCore { -String getMIMETypeForUTI(const String & uti) -{ - String mimeType; - // FIXME: This is an ugly hack: public.type -> image/type mimetype - if (int dotLocation = uti.reverseFind('.')) { - mimeType = String("image/")+uti.substring(dotLocation + 1); - } - return mimeType; -} - static String mimeTypeForExtension(const String& extension) { String ext = "." + extension; @@ -59,14 +49,6 @@ static String mimeTypeForExtension(const String& extension) String MIMETypeRegistry::getPreferredExtensionForMIMEType(const String& type) { - String mimeType; - - int semiColonPos = type.find(';'); - if (semiColonPos < 0) - mimeType = type; - else - mimeType = type.substring(0, semiColonPos); - String path = "MIME\\Database\\Content Type\\" + type; WCHAR extStr[MAX_PATH]; DWORD extStrLen = sizeof(extStr); @@ -109,6 +91,8 @@ String MIMETypeRegistry::getMIMETypeForExtension(const String &ext) mimetypeMap.add("ico", "image/ico"); mimetypeMap.add("cur", "image/ico"); mimetypeMap.add("bmp", "image/bmp"); + mimetypeMap.add("wml", "text/vnd.wap.wml"); + mimetypeMap.add("wmlc", "application/vnd.wap.wmlc"); } String result = mimetypeMap.get(ext); if (result.isEmpty()) { diff --git a/WebCore/platform/win/PopupMenuWin.cpp b/WebCore/platform/win/PopupMenuWin.cpp index 64b8a59..59ea563 100644 --- a/WebCore/platform/win/PopupMenuWin.cpp +++ b/WebCore/platform/win/PopupMenuWin.cpp @@ -50,8 +50,6 @@ static const int defaultAnimationDuration = 200; // Maximum height of a popup window static const int maxPopupHeight = 320; -static const int popupWindowAlphaPercent = 95; - const int optionSpacingMiddle = 1; const int popupWindowBorderWidth = 1; @@ -99,7 +97,7 @@ void PopupMenu::show(const IntRect& r, FrameView* v, int index) if (!m_popup) { registerPopup(); - DWORD exStyle = WS_EX_LAYERED | WS_EX_LTRREADING; + 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 @@ -112,7 +110,6 @@ void PopupMenu::show(const IntRect& r, FrameView* v, int index) return; ::SetWindowLongPtr(m_popup, 0, (LONG_PTR)this); - ::SetLayeredWindowAttributes(m_popup, 0, (255 * popupWindowAlphaPercent) / 100, LWA_ALPHA); } if (!m_scrollbar) @@ -526,13 +523,12 @@ void PopupMenu::paint(const IntRect& damageRect, HDC hdc) itemFont = Font(d, itemFont.letterSpacing(), itemFont.wordSpacing()); itemFont.update(m_popupClient->fontSelector()); } - context.setFont(itemFont); // Draw the item text if (itemStyle.isVisible()) { int textX = max(0, client()->clientPaddingLeft() - client()->clientInsetLeft()); int textY = itemRect.y() + itemFont.ascent() + (itemRect.height() - itemFont.height()) / 2; - context.drawBidiText(textRun, IntPoint(textX, textY)); + context.drawBidiText(itemFont, textRun, IntPoint(textX, textY)); } } diff --git a/WebCore/platform/win/SharedTimerWin.cpp b/WebCore/platform/win/SharedTimerWin.cpp index b611659..da27a53 100644 --- a/WebCore/platform/win/SharedTimerWin.cpp +++ b/WebCore/platform/win/SharedTimerWin.cpp @@ -27,9 +27,9 @@ #include "SharedTimer.h" #include "Page.h" -#include "SystemTime.h" #include "Widget.h" #include <wtf/Assertions.h> +#include <wtf/CurrentTime.h> // Note: wx headers set defines that affect the configuration of windows.h // so we must include the wx header first to get unicode versions of functions, @@ -41,6 +41,10 @@ #include <windows.h> #include <mmsystem.h> +#if PLATFORM(WIN) +#include "PluginView.h" +#endif + // These aren't in winuser.h with the MSVS 2003 Platform SDK, // so use default values in that case. #ifndef USER_TIMER_MINIMUM @@ -55,10 +59,6 @@ #define QS_RAWINPUT 0x0400 #endif -#if PLATFORM(WIN) -#include "PluginView.h" -#endif - namespace WebCore { static UINT timerID; @@ -68,7 +68,6 @@ static HWND timerWindowHandle = 0; static UINT timerFiredMessage = 0; static HANDLE timerQueue; static HANDLE timer; -static Mutex timerMutex; static bool highResTimerActive; static bool processingCustomTimerMessage = false; static LONG pendingTimers; @@ -139,17 +138,8 @@ void setSharedTimerFiredFunction(void (*f)()) sharedTimerFiredFunction = f; } -static void clearTimer() -{ - MutexLocker locker(timerMutex); - if (timerQueue && timer) - DeleteTimerQueueTimer(timerQueue, timer, 0); - timer = 0; -} - static void NTAPI queueTimerProc(PVOID, BOOLEAN) { - clearTimer(); if (InterlockedIncrement(&pendingTimers) == 1) PostMessage(timerWindowHandle, timerFiredMessage, 0, 0); } @@ -196,11 +186,9 @@ void setSharedTimerFireTime(double fireTime) // Otherwise, delay the PostMessage via a CreateTimerQueueTimer if (!timerQueue) timerQueue = CreateTimerQueue(); - MutexLocker locker(timerMutex); if (timer) - timerSet = ChangeTimerQueueTimer(timerQueue, timer, intervalInMS, 0); - else - timerSet = CreateTimerQueueTimer(&timer, timerQueue, queueTimerProc, 0, intervalInMS, 0, WT_EXECUTEINTIMERTHREAD | WT_EXECUTEONLYONCE); + DeleteTimerQueueTimer(timerQueue, timer, 0); + timerSet = CreateTimerQueueTimer(&timer, timerQueue, queueTimerProc, 0, intervalInMS, 0, WT_EXECUTEINTIMERTHREAD | WT_EXECUTEONLYONCE); } } @@ -209,13 +197,19 @@ void setSharedTimerFireTime(double fireTime) KillTimer(timerWindowHandle, timerID); timerID = 0; } - } else + } else { timerID = SetTimer(timerWindowHandle, sharedTimerID, intervalInMS, 0); + timer = 0; + } } void stopSharedTimer() { - clearTimer(); + if (timerQueue && timer) { + DeleteTimerQueueTimer(timerQueue, timer, 0); + timer = 0; + } + if (timerID) { KillTimer(timerWindowHandle, timerID); timerID = 0; diff --git a/WebCore/platform/win/SystemTimeWin.cpp b/WebCore/platform/win/SystemTimeWin.cpp index 473e8de..88ea145 100644 --- a/WebCore/platform/win/SystemTimeWin.cpp +++ b/WebCore/platform/win/SystemTimeWin.cpp @@ -26,30 +26,23 @@ #include "config.h" #include "SystemTime.h" -#include <DateMath.h> #include <windows.h> -#if COMPILER(MINGW) +#if COMPILER(MINGW) || (PLATFORM(QT) && COMPILER(MSVC)) #include <float.h> #define FLOAT_MAX FLT_MAX #endif namespace WebCore { -double currentTime() -{ - // Call through to our high-resolution JSC time code, since calls like GetSystemTimeAsFileTime and ftime are only accurate within 15ms. - // This resolution can be improved with timeBeginPeriod/timeEndPeriod on Vista, but these calls don't - // improve the resolution of date/time getters (GetSystemTimeAsFileTime, ftime, etc.) on XP. - return JSC::getCurrentUTCTimeWithMicroseconds() * 0.001; -} - float userIdleTime() { +#if !PLATFORM(WIN_CE) LASTINPUTINFO lastInputInfo = {0}; lastInputInfo.cbSize = sizeof(LASTINPUTINFO); if (::GetLastInputInfo(&lastInputInfo)) return (GetTickCount() - lastInputInfo.dwTime) * 0.001; // ::GetTickCount returns ms of uptime valid for up to 49.7 days. +#endif return FLT_MAX; // return an arbitrarily high userIdleTime so that releasing pages from the page cache isn't postponed. } diff --git a/WebCore/platform/win/TemporaryLinkStubs.cpp b/WebCore/platform/win/TemporaryLinkStubs.cpp index 80c8df0..71eed00 100644 --- a/WebCore/platform/win/TemporaryLinkStubs.cpp +++ b/WebCore/platform/win/TemporaryLinkStubs.cpp @@ -33,5 +33,7 @@ namespace WebCore { // <keygen> String signedPublicKeyAndChallengeString(unsigned, const String&, const KURL&) { notImplemented(); return String(); } void getSupportedKeySizes(Vector<String>&) { notImplemented(); } - +#if PLATFORM(CAIRO) +void populateFontDatabase() { /* Not needed for GDI fonts */ } +#endif } // namespace WebCore diff --git a/WebCore/platform/win/WebCoreTextRenderer.cpp b/WebCore/platform/win/WebCoreTextRenderer.cpp index 75ce003..affeb9d 100644 --- a/WebCore/platform/win/WebCoreTextRenderer.cpp +++ b/WebCore/platform/win/WebCoreTextRenderer.cpp @@ -52,10 +52,8 @@ static void doDrawTextAtPoint(GraphicsContext& context, const String& text, cons context.setFillColor(color); if (isOneLeftToRightRun(run)) font.drawText(&context, run, point); - else { - context.setFont(font); - context.drawBidiText(run, point); - } + else + context.drawBidiText(font, run, point); if (underlinedIndex >= 0) { ASSERT(underlinedIndex < static_cast<int>(text.length())); diff --git a/WebCore/platform/wx/ContextMenuItemWx.cpp b/WebCore/platform/wx/ContextMenuItemWx.cpp new file mode 100644 index 0000000..51ebe13 --- /dev/null +++ b/WebCore/platform/wx/ContextMenuItemWx.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2008 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "ContextMenuItem.h" +#include "ContextMenu.h" +#include "PlatformMenuDescription.h" + +using namespace WebCore; + +ContextMenuItem::ContextMenuItem(ContextMenu* subMenu) +{ + m_platformDescription.type = SubmenuType; + m_platformDescription.action = ContextMenuItemTagNoAction; + if (subMenu) + setSubMenu(subMenu); + else + m_platformDescription.subMenu = 0; +} + +ContextMenuItem::ContextMenuItem(ContextMenuItemType type, ContextMenuAction action, + const String& title, ContextMenu* subMenu) +{ + m_platformDescription.type = type; + m_platformDescription.action = action; + m_platformDescription.title = title; + if (subMenu) + setSubMenu(subMenu); + else + m_platformDescription.subMenu = 0; +} + +ContextMenuItem::~ContextMenuItem() +{ +} + +PlatformMenuItemDescription ContextMenuItem::releasePlatformDescription() +{ + return m_platformDescription; +} + +ContextMenuItemType ContextMenuItem::type() const +{ + return m_platformDescription.type; +} + +void ContextMenuItem::setType(ContextMenuItemType type) +{ + m_platformDescription.type = type; +} + +ContextMenuAction ContextMenuItem::action() const +{ + return m_platformDescription.action; +} + +void ContextMenuItem::setAction(ContextMenuAction action) +{ + m_platformDescription.action = action; +} + +String ContextMenuItem::title() const +{ + return m_platformDescription.title; +} + +void ContextMenuItem::setTitle(const String& title) +{ + m_platformDescription.title = title; +} + +void ContextMenuItem::setSubMenu(ContextMenu* subMenu) +{ + m_platformDescription.subMenu = subMenu->releasePlatformDescription(); +} + +void ContextMenuItem::setChecked(bool shouldCheck) +{ + m_platformDescription.checked = shouldCheck; +} + +void ContextMenuItem::setEnabled(bool shouldEnable) +{ + m_platformDescription.enabled = shouldEnable; +} diff --git a/WebCore/platform/wx/ContextMenuWx.cpp b/WebCore/platform/wx/ContextMenuWx.cpp new file mode 100644 index 0000000..6f1bc9c --- /dev/null +++ b/WebCore/platform/wx/ContextMenuWx.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2008 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "ContextMenu.h" +#include "ContextMenuItem.h" +#include "PlatformMenuDescription.h" +#include "wx/menu.h" + +using namespace WebCore; + +typedef WTF::HashMap<int, ContextMenuAction> ItemActionMap; +static ItemActionMap s_itemActions; + +ContextMenuItem* ContextMenu::itemWithId(int id) +{ + return new ContextMenuItem(ActionType, s_itemActions.get(id), ""); +} + +ContextMenu::ContextMenu(const HitTestResult& result) : m_hitTestResult(result) +{ + m_platformDescription = new wxMenu(0); +} + +ContextMenu::~ContextMenu() +{ + if (m_platformDescription) + delete m_platformDescription; +} + +void ContextMenu::appendItem(ContextMenuItem& item) +{ + if (!m_platformDescription) + return; + + checkOrEnableIfNeeded(item); + + PlatformMenuItemDescription itemDescription = item.releasePlatformDescription(); + wxItemKind menuKindWx = ( itemDescription.type == CheckableActionType ) ? wxITEM_CHECK : wxITEM_NORMAL; + wxString titleWx(itemDescription.title); + int idWx = wxID_ANY; + wxMenuItem * itemWx; + + ItemActionMap::const_iterator end = s_itemActions.end(); + for (ItemActionMap::const_iterator it = s_itemActions.begin(); it != end; ++it) { + if (it->second == itemDescription.action) + idWx = it->first; + } + + if (itemDescription.subMenu) { + itemWx = new wxMenuItem(m_platformDescription, idWx, titleWx, wxEmptyString, wxITEM_NORMAL, itemDescription.subMenu); + } else if (itemDescription.type != SeparatorType) { + itemWx = new wxMenuItem(m_platformDescription, idWx, titleWx, wxT(""), menuKindWx); + } else { + itemWx = new wxMenuItem(m_platformDescription); + } + + s_itemActions.add(itemWx->GetId(), item.action()); + + m_platformDescription->Append(itemWx); + m_platformDescription->Enable(itemWx->GetId(), itemDescription.enabled); + + if (menuKindWx == wxITEM_CHECK) + m_platformDescription->Check(itemWx->GetId(), itemDescription.checked); +} + +void ContextMenu::setPlatformDescription(PlatformMenuDescription menu) +{ + if (!menu) + return; + + if (m_platformDescription) + delete m_platformDescription; + + m_platformDescription = menu; +} + +PlatformMenuDescription ContextMenu::platformDescription() const +{ + return m_platformDescription; +} + +PlatformMenuDescription ContextMenu::releasePlatformDescription() +{ + PlatformMenuDescription description = m_platformDescription; + m_platformDescription = 0; + + return description; +} diff --git a/WebCore/platform/wx/LocalizedStringsWx.cpp b/WebCore/platform/wx/LocalizedStringsWx.cpp index a315181..5bede52 100644 --- a/WebCore/platform/wx/LocalizedStringsWx.cpp +++ b/WebCore/platform/wx/LocalizedStringsWx.cpp @@ -68,177 +68,182 @@ String fileButtonNoFileSelectedLabel() String contextMenuItemTagOpenLinkInNewWindow() { - return String(); + return String("Open Link in New Window"); } String contextMenuItemTagDownloadLinkToDisk() { - return String(); + return String("Download Link to Disk"); } String contextMenuItemTagCopyLinkToClipboard() { - return String(); + return String("Copy Link to Clipboard"); } String contextMenuItemTagOpenImageInNewWindow() { - return String(); + return String("Open Image in New Window"); } String contextMenuItemTagDownloadImageToDisk() { - return String(); + return String("Download Image to Disk"); } String contextMenuItemTagCopyImageToClipboard() { - return String(); + return String("Copy Image to Clipboard"); } String contextMenuItemTagOpenFrameInNewWindow() { - return String(); + return String("Open Frame in New Window"); } String contextMenuItemTagCopy() { - return String(); + return String("Copy"); } String contextMenuItemTagGoBack() { - return String(); + return String("Go Back"); } String contextMenuItemTagGoForward() { - return String(); + return String("Go Forward"); } String contextMenuItemTagStop() { - return String(); + return String("Stop"); } String contextMenuItemTagReload() { - return String(); + return String("Reload"); } String contextMenuItemTagCut() { - return String(); + return String("Cut"); } String contextMenuItemTagPaste() { - return String(); + return String("Paste"); } String contextMenuItemTagNoGuessesFound() { - return String(); + return String("No Guesses Found"); } String contextMenuItemTagIgnoreSpelling() { - return String(); + return String("Ignore Spelling"); } String contextMenuItemTagLearnSpelling() { - return String(); + return String("Learn Spelling"); } String contextMenuItemTagSearchWeb() { - return String(); + return String("Search Web"); } String contextMenuItemTagLookUpInDictionary() { - return String(); + return String("Look Up in Dictionary"); } String contextMenuItemTagOpenLink() { - return String(); + return String("Open Link"); } String contextMenuItemTagIgnoreGrammar() { - return String(); + return String("Ignore Grammar"); } String contextMenuItemTagSpellingMenu() { - return String(); + return String("Spelling"); } String contextMenuItemTagShowSpellingPanel(bool show) { - return String(); + return String("Show Spelling Panel"); } String contextMenuItemTagCheckSpelling() { - return String(); + return String("Check Spelling"); } String contextMenuItemTagCheckSpellingWhileTyping() { - return String(); + return String("Check Spelling While Typing"); } String contextMenuItemTagCheckGrammarWithSpelling() { - return String(); + return String("Check Grammar with Spelling"); } String contextMenuItemTagFontMenu() { - return String(); + return String("Font"); } String contextMenuItemTagBold() { - return String(); + return String("Bold"); } String contextMenuItemTagItalic() { - return String(); + return String("Italic"); } String contextMenuItemTagUnderline() { - return String(); + return String("Underline"); } String contextMenuItemTagOutline() { - return String(); + return String("Outline"); } String contextMenuItemTagWritingDirectionMenu() { - return String(); + return String("Writing Direction"); +} + +String contextMenuItemTagTextDirectionMenu() +{ + return String("Text Direction"); } String contextMenuItemTagDefaultDirection() { - return String(); + return String("Default Direction"); } String contextMenuItemTagLeftToRight() { - return String(); + return String("Left to Right"); } String contextMenuItemTagRightToLeft() { - return String(); + return String("Right to Left"); } String searchMenuNoRecentSearchesText() diff --git a/WebCore/platform/wx/MimeTypeRegistryWx.cpp b/WebCore/platform/wx/MimeTypeRegistryWx.cpp index c025d02..601cd9f 100644 --- a/WebCore/platform/wx/MimeTypeRegistryWx.cpp +++ b/WebCore/platform/wx/MimeTypeRegistryWx.cpp @@ -38,6 +38,7 @@ static const ExtensionMap extensionMap [] = { { "bmp", "image/bmp" }, { "css", "text/css" }, { "gif", "image/gif" }, + { "htm", "text/html" }, { "html", "text/html" }, { "ico", "image/x-icon" }, { "jpeg", "image/jpeg" }, diff --git a/WebCore/platform/wx/MouseEventWx.cpp b/WebCore/platform/wx/MouseEventWx.cpp index c9468a9..a02d7ba 100644 --- a/WebCore/platform/wx/MouseEventWx.cpp +++ b/WebCore/platform/wx/MouseEventWx.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "Assertions.h" #include "PlatformMouseEvent.h" -#include "SystemTime.h" +#include <wtf/CurrentTime.h> #include <wx/defs.h> #include <wx/event.h> @@ -69,7 +69,7 @@ PlatformMouseEvent::PlatformMouseEvent(const wxMouseEvent& event, const wxPoint& else m_clickCount = event.ButtonDClick() ? 2 : 1; - m_timestamp = WebCore::currentTime(); + m_timestamp = WTF::currentTime(); } } diff --git a/WebCore/platform/wx/PasteboardWx.cpp b/WebCore/platform/wx/PasteboardWx.cpp index 3b71e9a..67697de 100644 --- a/WebCore/platform/wx/PasteboardWx.cpp +++ b/WebCore/platform/wx/PasteboardWx.cpp @@ -31,6 +31,7 @@ #include "Frame.h" #include "KURL.h" #include "markup.h" +#include "NotImplemented.h" #include "PlatformString.h" #include <wx/defs.h> @@ -53,27 +54,39 @@ void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, { if (wxTheClipboard->Open()) { - String text = frame->selectedText(); - text.replace('\\', frame->backslashAsCurrencySymbol()); - - wxTheClipboard->SetData( new wxTextDataObject(text) ); + wxTheClipboard->SetData( new wxTextDataObject(frame->selectedText()) ); wxTheClipboard->Close(); } } bool Pasteboard::canSmartReplace() { + notImplemented(); return false; } String Pasteboard::plainText(Frame* frame) { + notImplemented(); return String(); } PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefPtr<Range> context, bool allowPlainText, bool& chosePlainText) { + RefPtr<DocumentFragment> fragment = 0; + if (wxTheClipboard->Open()) { + if (allowPlainText && wxTheClipboard->IsSupported( wxDF_TEXT )) { + wxTextDataObject data; + wxTheClipboard->GetData( data ); + chosePlainText = true; + fragment = createFragmentFromText(context.get(), data.GetText()); + } + wxTheClipboard->Close(); + } + if (fragment) + return fragment.release(); + return 0; } @@ -93,6 +106,7 @@ void Pasteboard::clear() void Pasteboard::writeImage(Node*, const KURL&, const String& title) { + notImplemented(); } } diff --git a/WebCore/platform/wx/RenderThemeWx.cpp b/WebCore/platform/wx/RenderThemeWx.cpp index 05ebeb9..9b6dea5 100644 --- a/WebCore/platform/wx/RenderThemeWx.cpp +++ b/WebCore/platform/wx/RenderThemeWx.cpp @@ -34,6 +34,7 @@ #include "WebKit/wx/WebView.h" +#include <wx/dcgraph.h> #include <wx/defs.h> #include <wx/renderer.h> #include <wx/dcclient.h> @@ -130,7 +131,12 @@ bool RenderThemeWx::isControlStyled(const RenderStyle* style, const BorderData& if (style->appearance() == TextFieldPart || style->appearance() == TextAreaPart) return style->border() != border; - return RenderTheme::isControlStyled(style, border, background, backgroundColor); + // Normally CSS can be used to set properties of form controls (such as adding a background bitmap). + // However, for this to work RenderThemeWx needs to adjust uncustomized elements (e.g. buttons) to reflect the + // changes made by CSS. Since we don't do that right now, the native parts of form elements appear in odd places. + // Until we have time to implement that support, we return false here, so that we ignore customizations + // and always use the native theme drawing to draw form controls. + return false; } void RenderThemeWx::adjustRepaintRect(const RenderObject* o, IntRect& r) @@ -250,8 +256,12 @@ bool RenderThemeWx::paintButton(RenderObject* o, const RenderObject::PaintInfo& wxRendererNative::Get().DrawPushButton(window, *dc, r, flags); else if(part == RadioPart) { if (isChecked(o)) - flags |= wxCONTROL_CHECKED; + flags |= wxCONTROL_CHECKED; +#if wxCHECK_VERSION(2,9,0) + wxRendererNative::Get().DrawRadioButton(window, *dc, r, flags); +#else wxRenderer_DrawRadioButton(window, *dc, r, flags); +#endif } else if(part == CheckboxPart) { if (isChecked(o)) @@ -270,7 +280,12 @@ bool RenderThemeWx::paintTextField(RenderObject* o, const RenderObject::PaintInf { wxWindow* window = o->view()->frameView()->platformWidget(); wxDC* dc = static_cast<wxDC*>(i.context->platformContext()); +#if wxCHECK_VERSION(2,9,0) + wxRendererNative::Get().DrawTextCtrl(window, *dc, r, 0); +#else wxRenderer_DrawTextCtrl(window, *dc, r, 0); +#endif + return false; } @@ -298,7 +313,11 @@ bool RenderThemeWx::paintMenuList(RenderObject* o, const RenderObject::PaintInfo if (isPressed(o)) flags |= wxCONTROL_PRESSED; +#if wxCHECK_VERSION(2,9,0) + wxRendererNative::Get().DrawChoice(window, *dc, r, flags); +#else wxRenderer_DrawChoice(window, *dc, r, flags); +#endif return false; } diff --git a/WebCore/platform/wx/ScrollViewWx.cpp b/WebCore/platform/wx/ScrollViewWx.cpp index 3822cba..254ac9f 100644 --- a/WebCore/platform/wx/ScrollViewWx.cpp +++ b/WebCore/platform/wx/ScrollViewWx.cpp @@ -306,6 +306,16 @@ void ScrollView::platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode vertical = m_data->vScrollbarMode; } +void ScrollView::platformSetCanBlitOnScroll(bool canBlitOnScroll) +{ + m_canBlitOnScroll = canBlitOnScroll; +} + +bool ScrollView::platformCanBlitOnScroll() const +{ + return m_canBlitOnScroll; +} + // used for subframes support void ScrollView::platformAddChild(Widget* widget) { diff --git a/WebCore/platform/wx/SharedTimerWx.cpp b/WebCore/platform/wx/SharedTimerWx.cpp index 19747ce..d95457b 100644 --- a/WebCore/platform/wx/SharedTimerWx.cpp +++ b/WebCore/platform/wx/SharedTimerWx.cpp @@ -27,10 +27,10 @@ #include "SharedTimer.h" #include "NotImplemented.h" -#include "SystemTime.h" #include "Widget.h" #include <wtf/Assertions.h> +#include <wtf/CurrentTime.h> #include <stdio.h> #include "wx/defs.h" diff --git a/WebCore/platform/wx/wxcode/gtk/non-kerned-drawing.cpp b/WebCore/platform/wx/wxcode/gtk/non-kerned-drawing.cpp index b86a9bc..ed8fb09 100644 --- a/WebCore/platform/wx/wxcode/gtk/non-kerned-drawing.cpp +++ b/WebCore/platform/wx/wxcode/gtk/non-kerned-drawing.cpp @@ -28,6 +28,7 @@ #include "GraphicsContext.h" #include "SimpleFontData.h" +#include <wx/dcgraph.h> #include <wx/defs.h> #include <wx/dcclient.h> #include <wx/gdicmn.h> |