diff options
author | dglazkov@google.com <dglazkov@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-10-06 19:48:07 +0000 |
---|---|---|
committer | dglazkov@google.com <dglazkov@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-10-06 19:48:07 +0000 |
commit | 9b814d9a263d92030e9be424c223f6f3cfa7b67a (patch) | |
tree | 50e4877d65acaffafa9e99f59e6a0c85980c407e | |
parent | 757449ab8a47562b490588e0e05e826fc8aceeeb (diff) | |
download | chromium_src-9b814d9a263d92030e9be424c223f6f3cfa7b67a.zip chromium_src-9b814d9a263d92030e9be424c223f6f3cfa7b67a.tar.gz chromium_src-9b814d9a263d92030e9be424c223f6f3cfa7b67a.tar.bz2 |
Cleaning up the unfork
Removing files from pending
Review URL: http://codereview.chromium.org/6500
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2892 0039d316-1c4b-4281-b951-d872f2087c98
29 files changed, 29 insertions, 28602 deletions
@@ -12,7 +12,7 @@ deps = { "http://googletest.googlecode.com/svn/trunk@63", "src/third_party/WebKit": - "/trunk/deps/third_party/WebKit@2871", + "/trunk/deps/third_party/WebKit@2888", "src/third_party/cygwin": "/trunk/deps/third_party/cygwin@1788", diff --git a/webkit/build/WebCore/WebCore.vcproj b/webkit/build/WebCore/WebCore.vcproj index e8e5dd6..0ad44a9 100644 --- a/webkit/build/WebCore/WebCore.vcproj +++ b/webkit/build/WebCore/WebCore.vcproj @@ -242,7 +242,7 @@ > </File> <File - RelativePath="..\..\pending\Console.h" + RelativePath="..\..\..\third_party\WebKit\WebCore\page\Console.h" > </File> <File @@ -266,11 +266,11 @@ > </File> <File - RelativePath="..\..\pending\DOMWindow.cpp" + RelativePath="..\..\..\third_party\WebKit\WebCore\page\DOMWindow.cpp" > </File> <File - RelativePath="..\..\pending\DOMWindow.h" + RelativePath="..\..\..\third_party\WebKit\WebCore\page\DOMWindow.h" > </File> <File @@ -282,7 +282,7 @@ > </File> <File - RelativePath="..\..\pending\DragController.cpp" + RelativePath="..\..\..\third_party\WebKit\WebCore\page\DragController.cpp" > </File> <File @@ -290,7 +290,7 @@ > </File> <File - RelativePath="..\..\pending\EventHandler.cpp" + RelativePath="..\..\..\third_party\WebKit\WebCore\page\EventHandler.cpp" > </File> <File @@ -310,7 +310,7 @@ > </File> <File - RelativePath="..\..\pending\Frame.cpp" + RelativePath="..\..\..\third_party\WebKit\WebCore\page\Frame.cpp" > </File> <File @@ -433,7 +433,7 @@ > </File> <File - RelativePath="..\..\pending\CompositeAnimation.h" + RelativePath="..\..\..\third_party\WebKit\WebCore\page\animation\CompositeAnimation.h" > </File> <File @@ -466,7 +466,7 @@ > </File> <File - RelativePath="..\..\pending\CachedCSSStyleSheet.cpp" + RelativePath="..\..\..\third_party\WebKit\WebCore\loader\CachedCSSStyleSheet.cpp" > </File> <File @@ -494,7 +494,7 @@ > </File> <File - RelativePath="..\..\pending\CachedResource.h" + RelativePath="..\..\..\third_party\WebKit\WebCore\loader\CachedResource.h" > </File> <File @@ -510,7 +510,7 @@ > </File> <File - RelativePath="..\..\pending\CachedScript.cpp" + RelativePath="..\..\..\third_party\WebKit\WebCore\loader\CachedScript.cpp" > </File> <File @@ -554,7 +554,7 @@ > </File> <File - RelativePath="..\..\pending\EmptyClients.h" + RelativePath="..\..\..\third_party\WebKit\WebCore\loader\EmptyClients.h" > </File> <File @@ -566,15 +566,15 @@ > </File> <File - RelativePath="..\..\pending\FrameLoader.cpp" + RelativePath="..\..\..\third_party\WebKit\WebCore\loader\FrameLoader.cpp" > </File> <File - RelativePath="..\..\pending\FrameLoader.h" + RelativePath="..\..\..\third_party\WebKit\WebCore\loader\FrameLoader.h" > </File> <File - RelativePath="..\..\pending\FrameLoaderClient.h" + RelativePath="..\..\..\third_party\WebKit\WebCore\loader\FrameLoaderClient.h" > </File> <File @@ -830,7 +830,7 @@ > </File> <File - RelativePath="..\..\pending\FileSystem.h" + RelativePath="...\..\..\third_party\WebKit\WebCore\platform\FileSystem.h" > </File> <File @@ -838,7 +838,7 @@ > </File> <File - RelativePath="..\..\pending\Font.cpp" + RelativePath="..\..\..\third_party\WebKit\WebCore\platform\graphics\Font.cpp" > </File> <File @@ -846,11 +846,11 @@ > </File> <File - RelativePath="..\..\pending\FontCache.cpp" + RelativePath="..\..\..\third_party\WebKit\WebCore\platform\graphics\FontCache.cpp" > </File> <File - RelativePath="..\..\pending\FontCache.h" + RelativePath="..\..\..\third_party\WebKit\WebCore\platform\graphics\FontCache.h" > </File> <File @@ -858,7 +858,7 @@ > </File> <File - RelativePath="..\..\pending\FontDescription.h" + RelativePath="..\..\..\third_party\WebKit\WebCore\platform\graphics\FontDescription.h" > </File> <File @@ -1357,7 +1357,7 @@ Name="win" > <File - RelativePath="..\..\pending\FileSystemWin.cpp" + RelativePath="..\..\..\third_party\WebKit\WebCore\platform\win\FileSystemWin.cpp" > </File> </Filter> @@ -1365,11 +1365,11 @@ Name="text" > <File - RelativePath="..\..\pending\AtomicString.cpp" + RelativePath="..\..\..\third_party\WebKit\WebCore\platform\text\AtomicString.cpp" > </File> <File - RelativePath="..\..\pending\AtomicString.h" + RelativePath="..\..\..\third_party\WebKit\WebCore\platform\text\AtomicString.h" > </File> <File @@ -1846,7 +1846,7 @@ > </File> <File - RelativePath="..\..\pending\CSSStyleSelector.cpp" + RelativePath="..\..\..\third_party\WebKit\WebCore\css\CSSStyleSelector.cpp" > </File> <File @@ -3158,11 +3158,11 @@ > </File> <File - RelativePath="..\..\pending\Document.cpp" + RelativePath="..\..\..\third_party\WebKit\WebCore\dom\Document.cpp" > </File> <File - RelativePath="..\..\pending\Document.h" + RelativePath="..\..\..\third_party\WebKit\WebCore\dom\Document.h" > </File> <File @@ -3678,7 +3678,7 @@ > </File> <File - RelativePath="..\..\pending\DeleteButtonController.cpp" + RelativePath="..\..\..\third_party\WebKit\WebCore\editing\DeleteButtonController.cpp" > </File> <File @@ -4042,11 +4042,11 @@ > </File> <File - RelativePath="..\..\pending\CanvasRenderingContext2D.cpp" + RelativePath="..\..\..\third_party\WebKit\WebCore\html\CanvasRenderingContext2D.cpp" > </File> <File - RelativePath="..\..\pending\CanvasRenderingContext2D.h" + RelativePath="..\..\..\third_party\WebKit\WebCore\html\CanvasRenderingContext2D.h" > </File> <File diff --git a/webkit/pending/AtomicString.cpp b/webkit/pending/AtomicString.cpp deleted file mode 100644 index ccadfce..0000000 --- a/webkit/pending/AtomicString.cpp +++ /dev/null @@ -1,300 +0,0 @@ -/* - * 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" - -#ifdef SKIP_STATIC_CONSTRUCTORS_ON_GCC -#define ATOMICSTRING_HIDE_GLOBALS 1 -#endif - -#include "AtomicString.h" - -#include "StaticConstructors.h" -#include "StringHash.h" -#include <kjs/identifier.h> -#include <wtf/HashSet.h> - -#if USE(JSC) -using KJS::Identifier; -using KJS::UString; -#endif - -namespace WebCore { - -static HashSet<StringImpl*>* stringTable; - -struct CStringTranslator { - static unsigned hash(const char* c) - { - return StringImpl::computeHash(c); - } - - static bool equal(StringImpl* r, const char* s) - { - int length = r->length(); - const UChar* d = r->characters(); - for (int i = 0; i != length; ++i) { - unsigned char c = s[i]; - if (d[i] != c) - return false; - } - return s[length] == 0; - } - - static void translate(StringImpl*& location, const char* const& c, unsigned hash) - { - location = new StringImpl(c, strlen(c), hash); - } -}; - -bool operator==(const AtomicString& a, const char* b) -{ - StringImpl* impl = a.impl(); - if ((!impl || !impl->characters()) && !b) - return true; - if ((!impl || !impl->characters()) || !b) - return false; - return CStringTranslator::equal(impl, b); -} - -PassRefPtr<StringImpl> AtomicString::add(const char* c) -{ - if (!c) - return 0; - if (!*c) - return StringImpl::empty(); - pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable->add<const char*, CStringTranslator>(c); - if (!addResult.second) - return *addResult.first; - return adoptRef(*addResult.first); -} - -struct UCharBuffer { - const UChar* s; - unsigned length; -}; - -static inline bool equal(StringImpl* string, const UChar* characters, unsigned length) -{ - if (string->length() != length) - return false; - -#if PLATFORM(ARM) - const UChar* stringCharacters = string->characters(); - for (unsigned i = 0; i != length; ++i) { - if (*stringCharacters++ != *characters++) - return false; - } - return true; -#else - /* Do it 4-bytes-at-a-time on architectures where it's safe */ - - const uint32_t* stringCharacters = reinterpret_cast<const uint32_t*>(string->characters()); - const uint32_t* bufferCharacters = reinterpret_cast<const uint32_t*>(characters); - - unsigned halfLength = length >> 1; - for (unsigned i = 0; i != halfLength; ++i) { - if (*stringCharacters++ != *bufferCharacters++) - return false; - } - - if (length & 1 && *reinterpret_cast<const uint16_t*>(stringCharacters) != *reinterpret_cast<const uint16_t*>(bufferCharacters)) - return false; - - return true; -#endif -} - -struct UCharBufferTranslator { - static unsigned hash(const UCharBuffer& buf) - { - return StringImpl::computeHash(buf.s, buf.length); - } - - static bool equal(StringImpl* const& str, const UCharBuffer& buf) - { - return WebCore::equal(str, buf.s, buf.length); - } - - static void translate(StringImpl*& location, const UCharBuffer& buf, unsigned hash) - { - location = new StringImpl(buf.s, buf.length, hash); - } -}; - -struct HashAndCharacters { - unsigned hash; - const UChar* characters; - unsigned length; -}; - -struct HashAndCharactersTranslator { - static unsigned hash(const HashAndCharacters& buffer) - { - ASSERT(buffer.hash == StringImpl::computeHash(buffer.characters, buffer.length)); - return buffer.hash; - } - - static bool equal(StringImpl* const& string, const HashAndCharacters& buffer) - { - return WebCore::equal(string, buffer.characters, buffer.length); - } - - static void translate(StringImpl*& location, const HashAndCharacters& buffer, unsigned hash) - { - location = new StringImpl(buffer.characters, buffer.length, hash); - } -}; - -PassRefPtr<StringImpl> AtomicString::add(const UChar* s, int length) -{ - if (!s) - return 0; - - if (length == 0) - 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); -} - -PassRefPtr<StringImpl> AtomicString::add(const UChar* s) -{ - if (!s) - return 0; - - int length = 0; - while (s[length] != UChar(0)) - length++; - - if (length == 0) - 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); -} - -PassRefPtr<StringImpl> AtomicString::add(StringImpl* r) -{ - if (!r || r->m_inTable) - return r; - - if (r->length() == 0) - return StringImpl::empty(); - - StringImpl* result = *stringTable->add(r).first; - if (result == r) - r->m_inTable = true; - return result; -} - -void AtomicString::remove(StringImpl* r) -{ - stringTable->remove(r); -} - -#if USE(JSC) -PassRefPtr<StringImpl> AtomicString::add(const KJS::Identifier& identifier) -{ - if (identifier.isNull()) - return 0; - - UString::Rep* string = identifier.ustring().rep(); - unsigned length = string->size(); - if (!length) - return StringImpl::empty(); - - HashAndCharacters buffer = { string->computedHash(), string->data(), length }; - pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable->add<HashAndCharacters, HashAndCharactersTranslator>(buffer); - if (!addResult.second) - return *addResult.first; - return adoptRef(*addResult.first); -} - -PassRefPtr<StringImpl> AtomicString::add(const KJS::UString& ustring) -{ - if (ustring.isNull()) - return 0; - - UString::Rep* string = ustring.rep(); - unsigned length = string->size(); - if (!length) - return StringImpl::empty(); - - HashAndCharacters buffer = { string->hash(), string->data(), length }; - pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable->add<HashAndCharacters, HashAndCharactersTranslator>(buffer); - if (!addResult.second) - return *addResult.first; - return adoptRef(*addResult.first); -} - -AtomicStringImpl* AtomicString::find(const KJS::Identifier& identifier) -{ - if (identifier.isNull()) - return 0; - - UString::Rep* string = identifier.ustring().rep(); - unsigned length = string->size(); - if (!length) - 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()) - return 0; - return static_cast<AtomicStringImpl*>(*iterator); -} - -AtomicString::operator UString() const -{ - return m_string; -} -#endif - -DEFINE_GLOBAL(AtomicString, nullAtom) -DEFINE_GLOBAL(AtomicString, emptyAtom, "") -DEFINE_GLOBAL(AtomicString, textAtom, "#text") -DEFINE_GLOBAL(AtomicString, commentAtom, "#comment") -DEFINE_GLOBAL(AtomicString, starAtom, "*") - -void AtomicString::init() -{ - static bool initialized; - if (!initialized) { - stringTable = new HashSet<StringImpl*>; - - // Use placement new to initialize the globals. - new ((void*)&nullAtom) AtomicString; - new ((void*)&emptyAtom) AtomicString(""); - new ((void*)&textAtom) AtomicString("#text"); - new ((void*)&commentAtom) AtomicString("#comment"); - new ((void*)&starAtom) AtomicString("*"); - - initialized = true; - } -} - -} diff --git a/webkit/pending/AtomicString.h b/webkit/pending/AtomicString.h deleted file mode 100644 index 50be34a..0000000 --- a/webkit/pending/AtomicString.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2004, 2005, 2006, 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. - * - */ - -#ifndef AtomicString_h -#define AtomicString_h - -#include "AtomicStringImpl.h" -#include "PlatformString.h" - -namespace WebCore { - -class AtomicString { -public: - static void init(); - - AtomicString() { } - AtomicString(const char* s) : m_string(add(s)) { } - AtomicString(const UChar* s, int length) : m_string(add(s, length)) { } - AtomicString(const UChar* s) : m_string(add(s)) { } -#if USE(JSC) - AtomicString(const KJS::UString& s) : m_string(add(s)) { } - AtomicString(const KJS::Identifier& s) : m_string(add(s)) { } -#endif - AtomicString(StringImpl* imp) : m_string(add(imp)) { } - AtomicString(AtomicStringImpl* imp) : m_string(imp) { } - AtomicString(const String& s) : m_string(add(s.impl())) { } - -#if USE(JSC) - static AtomicStringImpl* find(const KJS::Identifier&); -#endif - - operator const String&() const { return m_string; } - const String& string() const { return m_string; }; - -#if USE(JSC) - operator KJS::UString() const; -#endif - - AtomicStringImpl* impl() const { return static_cast<AtomicStringImpl *>(m_string.impl()); } - - const UChar* characters() const { return m_string.characters(); } - unsigned length() const { return m_string.length(); } - - UChar operator[](unsigned int i) const { return m_string[i]; } - - bool contains(UChar c) const { return m_string.contains(c); } - bool contains(const AtomicString& s, bool caseSensitive = true) const - { return m_string.contains(s.string(), caseSensitive); } - - int find(UChar c, int start = 0) const { return m_string.find(c, start); } - int find(const AtomicString& s, int start = 0, bool caseSentitive = true) const - { return m_string.find(s.string(), start, caseSentitive); } - - bool startsWith(const AtomicString& s, bool caseSensitive = true) const - { return m_string.startsWith(s.string(), caseSensitive); } - bool endsWith(const AtomicString& s, bool caseSensitive = true) const - { return m_string.endsWith(s.string(), caseSensitive); } - - int toInt(bool* ok = 0) const { return m_string.toInt(ok); } - double toDouble(bool* ok = 0) const { return m_string.toDouble(ok); } - float toFloat(bool* ok = 0) const { return m_string.toFloat(ok); } - bool percentage(int& p) const { return m_string.percentage(p); } - Length* toLengthArray(int& len) const { return m_string.toLengthArray(len); } - Length* toCoordsArray(int& len) const { return m_string.toCoordsArray(len); } - - bool isNull() const { return m_string.isNull(); } - bool isEmpty() const { return m_string.isEmpty(); } - - static void remove(StringImpl*); - -#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; } -#endif - -private: - String m_string; - - static PassRefPtr<StringImpl> add(const char*); - static PassRefPtr<StringImpl> add(const UChar*, int length); - static PassRefPtr<StringImpl> add(const UChar*); - static PassRefPtr<StringImpl> add(StringImpl*); -#if USE(JSC) - static PassRefPtr<StringImpl> add(const KJS::UString&); - static PassRefPtr<StringImpl> add(const KJS::Identifier&); -#endif -}; - -inline bool operator==(const AtomicString& a, const AtomicString& b) { return a.impl() == b.impl(); } -bool operator==(const AtomicString& a, const char* b); -inline bool operator==(const AtomicString& a, const String& b) { return equal(a.impl(), b.impl()); } -inline bool operator==(const char* a, const AtomicString& b) { return b == a; } -inline bool operator==(const String& a, const AtomicString& b) { return equal(a.impl(), b.impl()); } - -inline bool operator!=(const AtomicString& a, const AtomicString& b) { return a.impl() != b.impl(); } -inline bool operator!=(const AtomicString& a, const char *b) { return !(a == b); } -inline bool operator!=(const AtomicString& a, const String& b) { return !equal(a.impl(), b.impl()); } -inline bool operator!=(const char* a, const AtomicString& b) { return !(b == a); } -inline bool operator!=(const String& a, const AtomicString& b) { return !equal(a.impl(), b.impl()); } - -inline bool equalIgnoringCase(const AtomicString& a, const AtomicString& b) { return equalIgnoringCase(a.impl(), b.impl()); } -inline bool equalIgnoringCase(const AtomicString& a, const char* b) { return equalIgnoringCase(a.impl(), b); } -inline bool equalIgnoringCase(const AtomicString& a, const String& b) { return equalIgnoringCase(a.impl(), b.impl()); } -inline bool equalIgnoringCase(const char* a, const AtomicString& b) { return equalIgnoringCase(a, b.impl()); } -inline bool equalIgnoringCase(const String& a, const AtomicString& b) { return equalIgnoringCase(a.impl(), b.impl()); } - -// Define external global variables for the commonly used atomic strings. -#ifndef ATOMICSTRING_HIDE_GLOBALS - extern const AtomicString nullAtom; - extern const AtomicString emptyAtom; - extern const AtomicString textAtom; - extern const AtomicString commentAtom; - extern const AtomicString starAtom; -#endif - -} // namespace WebCore - -#endif // AtomicString_h diff --git a/webkit/pending/CSSStyleSelector.cpp b/webkit/pending/CSSStyleSelector.cpp deleted file mode 100644 index 766696f..0000000 --- a/webkit/pending/CSSStyleSelector.cpp +++ /dev/null @@ -1,5707 +0,0 @@ -/* - * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) - * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com) - * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> - * Copyright (C) 2007, 2008 Eric Seidel <eric@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. - */ - -#include "config.h" -#include "CSSStyleSelector.h" - -#include "CSSBorderImageValue.h" -#include "CSSCursorImageValue.h" -#include "CSSFontFace.h" -#include "CSSFontFaceRule.h" -#include "CSSFontFaceSource.h" -#include "CSSImportRule.h" -#include "CSSMediaRule.h" -#include "CSSParser.h" -#include "CSSPrimitiveValueMappings.h" -#include "CSSProperty.h" -#include "CSSPropertyNames.h" -#include "CSSReflectValue.h" -#include "CSSRuleList.h" -#include "CSSSelector.h" -#include "CSSStyleRule.h" -#include "CSSStyleSheet.h" -#include "CSSTimingFunctionValue.h" -#include "CSSValueList.h" -#include "CSSVariableDependentValue.h" -#include "CSSVariablesDeclaration.h" -#include "CSSVariablesRule.h" -#include "CachedImage.h" -#include "Counter.h" -#include "FontCache.h" -#include "FontFamilyValue.h" -#include "FontValue.h" -#include "Frame.h" -#include "FrameView.h" -#include "HTMLDocument.h" -#include "HTMLElement.h" -#include "HTMLInputElement.h" -#include "HTMLTextAreaElement.h" -#include "HTMLNames.h" -#include "MediaList.h" -#include "MediaQueryEvaluator.h" -#include "Page.h" -#include "PageGroup.h" -#include "Pair.h" -#include "Rect.h" -#include "RenderTheme.h" -#include "SelectionController.h" -#include "Settings.h" -#include "ShadowValue.h" -#include "StyleCachedImage.h" -#include "StyleGeneratedImage.h" -#include "StyleSheetList.h" -#include "Text.h" -#include "UserAgentStyleSheets.h" -#include "WebKitCSSKeyframeRule.h" -#include "WebKitCSSKeyframesRule.h" -#include "WebKitCSSTransformValue.h" -#include "XMLNames.h" -#include "loader.h" -#include <wtf/Vector.h> - -#if ENABLE(DASHBOARD_SUPPORT) -#include "DashboardRegion.h" -#endif - -#if ENABLE(SVG) -#include "XLinkNames.h" -#include "SVGNames.h" -#endif - -using namespace std; - -namespace WebCore { - -using namespace HTMLNames; - -// #define STYLE_SHARING_STATS 1 - -#define HANDLE_INHERIT(prop, Prop) \ -if (isInherit) { \ - m_style->set##Prop(m_parentStyle->prop()); \ - return; \ -} - -#define HANDLE_INHERIT_AND_INITIAL(prop, Prop) \ -HANDLE_INHERIT(prop, Prop) \ -if (isInitial) { \ - m_style->set##Prop(RenderStyle::initial##Prop()); \ - return; \ -} - -#define HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(prop, Prop, Value) \ -HANDLE_INHERIT(prop, Prop) \ -if (isInitial) { \ - m_style->set##Prop(RenderStyle::initial##Value());\ - return;\ -} - -#define HANDLE_FILL_LAYER_INHERIT_AND_INITIAL(layerType, LayerType, prop, Prop) \ -if (isInherit) { \ - FillLayer* currChild = m_style->access##LayerType##Layers(); \ - FillLayer* prevChild = 0; \ - const FillLayer* currParent = m_parentStyle->layerType##Layers(); \ - while (currParent && currParent->is##Prop##Set()) { \ - if (!currChild) { \ - /* Need to make a new layer.*/ \ - currChild = new FillLayer(LayerType##FillLayer); \ - prevChild->setNext(currChild); \ - } \ - currChild->set##Prop(currParent->prop()); \ - prevChild = currChild; \ - currChild = prevChild->next(); \ - currParent = currParent->next(); \ - } \ - \ - while (currChild) { \ - /* Reset any remaining layers to not have the property set. */ \ - currChild->clear##Prop(); \ - currChild = currChild->next(); \ - } \ -} else if (isInitial) { \ - FillLayer* currChild = m_style->access##LayerType##Layers(); \ - currChild->set##Prop(FillLayer::initialFill##Prop(LayerType##FillLayer)); \ - for (currChild = currChild->next(); currChild; currChild = currChild->next()) \ - currChild->clear##Prop(); \ -} - -#define HANDLE_FILL_LAYER_VALUE(layerType, LayerType, prop, Prop, value) { \ -HANDLE_FILL_LAYER_INHERIT_AND_INITIAL(layerType, LayerType, prop, Prop) \ -if (isInherit || isInitial) \ - return; \ -FillLayer* currChild = m_style->access##LayerType##Layers(); \ -FillLayer* prevChild = 0; \ -if (value->isValueList()) { \ - /* Walk each value and put it into a layer, creating new layers as needed. */ \ - CSSValueList* valueList = static_cast<CSSValueList*>(value); \ - for (unsigned int i = 0; i < valueList->length(); i++) { \ - if (!currChild) { \ - /* Need to make a new layer to hold this value */ \ - currChild = new FillLayer(LayerType##FillLayer); \ - prevChild->setNext(currChild); \ - } \ - mapFill##Prop(currChild, valueList->itemWithoutBoundsCheck(i)); \ - prevChild = currChild; \ - currChild = currChild->next(); \ - } \ -} else { \ - mapFill##Prop(currChild, value); \ - currChild = currChild->next(); \ -} \ -while (currChild) { \ - /* Reset all remaining layers to not have the property set. */ \ - currChild->clear##Prop(); \ - currChild = currChild->next(); \ -} } - -#define HANDLE_BACKGROUND_INHERIT_AND_INITIAL(prop, Prop) \ -HANDLE_FILL_LAYER_INHERIT_AND_INITIAL(background, Background, prop, Prop) - -#define HANDLE_BACKGROUND_VALUE(prop, Prop, value) \ -HANDLE_FILL_LAYER_VALUE(background, Background, prop, Prop, value) - -#define HANDLE_MASK_INHERIT_AND_INITIAL(prop, Prop) \ -HANDLE_FILL_LAYER_INHERIT_AND_INITIAL(mask, Mask, prop, Prop) - -#define HANDLE_MASK_VALUE(prop, Prop, value) \ -HANDLE_FILL_LAYER_VALUE(mask, Mask, prop, Prop, value) - -#define HANDLE_ANIMATION_INHERIT_AND_INITIAL(prop, Prop) \ -if (isInherit) { \ - AnimationList* list = m_style->accessAnimations(); \ - const AnimationList* parentList = m_parentStyle->animations(); \ - size_t i = 0, parentSize = parentList ? parentList->size() : 0; \ - for ( ; i < parentSize && (*parentList)[i]->is##Prop##Set(); ++i) { \ - if (list->size() <= i) \ - list->append(Animation::create()); \ - (*list)[i]->set##Prop((*parentList)[i]->prop()); \ - } \ - \ - /* Reset any remaining animations to not have the property set. */ \ - for ( ; i < list->size(); ++i) \ - (*list)[i]->clear##Prop(); \ -} else if (isInitial) { \ - AnimationList* list = m_style->accessAnimations(); \ - if (list->isEmpty()) \ - list->append(Animation::create()); \ - (*list)[0]->set##Prop(RenderStyle::initialAnimation##Prop()); \ - for (size_t i = 1; i < list->size(); ++i) \ - (*list)[0]->clear##Prop(); \ -} - -#define HANDLE_ANIMATION_VALUE(prop, Prop, value) { \ -HANDLE_ANIMATION_INHERIT_AND_INITIAL(prop, Prop) \ -if (isInherit || isInitial) \ - return; \ -AnimationList* list = m_style->accessAnimations(); \ -size_t childIndex = 0; \ -if (value->isValueList()) { \ - /* Walk each value and put it into an animation, creating new animations as needed. */ \ - CSSValueList* valueList = static_cast<CSSValueList*>(value); \ - for (unsigned int i = 0; i < valueList->length(); i++) { \ - if (childIndex <= list->size()) \ - list->append(Animation::create()); \ - mapAnimation##Prop((*list)[childIndex].get(), valueList->itemWithoutBoundsCheck(i)); \ - ++childIndex; \ - } \ -} else { \ - if (list->isEmpty()) \ - list->append(Animation::create()); \ - mapAnimation##Prop((*list)[childIndex].get(), value); \ - childIndex = 1; \ -} \ -for ( ; childIndex < list->size(); ++childIndex) { \ - /* Reset all remaining animations to not have the property set. */ \ - (*list)[childIndex]->clear##Prop(); \ -} \ -} - -#define HANDLE_TRANSITION_INHERIT_AND_INITIAL(prop, Prop) \ -if (isInherit) { \ - AnimationList* list = m_style->accessTransitions(); \ - const AnimationList* parentList = m_parentStyle->transitions(); \ - size_t i = 0, parentSize = parentList ? parentList->size() : 0; \ - for ( ; i < parentSize && (*parentList)[i]->is##Prop##Set(); ++i) { \ - if (list->size() <= i) \ - list->append(Animation::create()); \ - (*list)[i]->set##Prop((*parentList)[i]->prop()); \ - } \ - \ - /* Reset any remaining transitions to not have the property set. */ \ - for ( ; i < list->size(); ++i) \ - (*list)[i]->clear##Prop(); \ -} else if (isInitial) { \ - AnimationList* list = m_style->accessTransitions(); \ - if (list->isEmpty()) \ - list->append(Animation::create()); \ - (*list)[0]->set##Prop(RenderStyle::initialAnimation##Prop()); \ - for (size_t i = 1; i < list->size(); ++i) \ - (*list)[0]->clear##Prop(); \ -} - -#define HANDLE_TRANSITION_VALUE(prop, Prop, value) { \ -HANDLE_TRANSITION_INHERIT_AND_INITIAL(prop, Prop) \ -if (isInherit || isInitial) \ - return; \ -AnimationList* list = m_style->accessTransitions(); \ -size_t childIndex = 0; \ -if (value->isValueList()) { \ - /* Walk each value and put it into a transition, creating new animations as needed. */ \ - CSSValueList* valueList = static_cast<CSSValueList*>(value); \ - for (unsigned int i = 0; i < valueList->length(); i++) { \ - if (childIndex <= list->size()) \ - list->append(Animation::create()); \ - mapAnimation##Prop((*list)[childIndex].get(), valueList->itemWithoutBoundsCheck(i)); \ - ++childIndex; \ - } \ -} else { \ - if (list->isEmpty()) \ - list->append(Animation::create()); \ - mapAnimation##Prop((*list)[childIndex].get(), value); \ - childIndex = 1; \ -} \ -for ( ; childIndex < list->size(); ++childIndex) { \ - /* Reset all remaining transitions to not have the property set. */ \ - (*list)[childIndex]->clear##Prop(); \ -} \ -} - -#define HANDLE_INHERIT_COND(propID, prop, Prop) \ -if (id == propID) { \ - m_style->set##Prop(m_parentStyle->prop()); \ - return; \ -} - -#define HANDLE_INHERIT_COND_WITH_BACKUP(propID, prop, propAlt, Prop) \ -if (id == propID) { \ - if (m_parentStyle->prop().isValid()) \ - m_style->set##Prop(m_parentStyle->prop()); \ - else \ - m_style->set##Prop(m_parentStyle->propAlt()); \ - return; \ -} - -#define HANDLE_INITIAL_COND(propID, Prop) \ -if (id == propID) { \ - m_style->set##Prop(RenderStyle::initial##Prop()); \ - return; \ -} - -#define HANDLE_INITIAL_COND_WITH_VALUE(propID, Prop, Value) \ -if (id == propID) { \ - m_style->set##Prop(RenderStyle::initial##Value()); \ - return; \ -} - -class CSSRuleSet { -public: - CSSRuleSet(); - ~CSSRuleSet(); - - typedef HashMap<AtomicStringImpl*, CSSRuleDataList*> AtomRuleMap; - - void addRulesFromSheet(CSSStyleSheet*, const MediaQueryEvaluator&, CSSStyleSelector* = 0); - - void addRule(CSSStyleRule* rule, CSSSelector* sel); - void addToRuleSet(AtomicStringImpl* key, AtomRuleMap& map, - CSSStyleRule* rule, CSSSelector* sel); - - CSSRuleDataList* getIDRules(AtomicStringImpl* key) { return m_idRules.get(key); } - CSSRuleDataList* getClassRules(AtomicStringImpl* key) { return m_classRules.get(key); } - CSSRuleDataList* getTagRules(AtomicStringImpl* key) { return m_tagRules.get(key); } - CSSRuleDataList* getUniversalRules() { return m_universalRules; } - -public: - AtomRuleMap m_idRules; - AtomRuleMap m_classRules; - AtomRuleMap m_tagRules; - CSSRuleDataList* m_universalRules; - unsigned m_ruleCount; -}; - -static CSSRuleSet* defaultStyle; -static CSSRuleSet* defaultQuirksStyle; -static CSSRuleSet* defaultPrintStyle; -static CSSRuleSet* defaultViewSourceStyle; - -RenderStyle* CSSStyleSelector::s_styleNotYetAvailable; - -static PseudoState pseudoState; - -static void loadDefaultStyle(); - -static const MediaQueryEvaluator& screenEval() -{ - static const MediaQueryEvaluator staticScreenEval("screen"); - return staticScreenEval; -} - -static const MediaQueryEvaluator& printEval() -{ - static const MediaQueryEvaluator staticPrintEval("print"); - return staticPrintEval; -} - -CSSStyleSelector::CSSStyleSelector(Document* doc, const String& userStyleSheet, StyleSheetList* styleSheets, CSSStyleSheet* mappedElementSheet, bool strictParsing, bool matchAuthorAndUserStyles) - : m_backgroundData(BackgroundFillLayer) - , m_checker(doc, strictParsing, false) - , m_fontSelector(CSSFontSelector::create(doc)) -{ - init(); - - m_matchAuthorAndUserStyles = matchAuthorAndUserStyles; - - if (!defaultStyle) - loadDefaultStyle(); - - m_userStyle = 0; - - // construct document root element default style. this is needed - // to evaluate media queries that contain relative constraints, like "screen and (max-width: 10em)" - // This is here instead of constructor, because when constructor is run, - // document doesn't have documentElement - // NOTE: this assumes that element that gets passed to styleForElement -call - // is always from the document that owns the style selector - FrameView* view = doc->view(); - if (view) - m_medium = new MediaQueryEvaluator(view->mediaType()); - else - m_medium = new MediaQueryEvaluator("all"); - - Element* root = doc->documentElement(); - - if (root) - m_rootDefaultStyle = styleForElement(root, 0, false, true); // dont ref, because the RenderStyle is allocated from global heap - - if (m_rootDefaultStyle && view) { - delete m_medium; - m_medium = new MediaQueryEvaluator(view->mediaType(), view->frame(), m_rootDefaultStyle); - } - - // FIXME: This sucks! The user sheet is reparsed every time! - if (!userStyleSheet.isEmpty()) { - m_userSheet = CSSStyleSheet::create(doc); - m_userSheet->parseString(userStyleSheet, strictParsing); - - m_userStyle = new CSSRuleSet(); - m_userStyle->addRulesFromSheet(m_userSheet.get(), *m_medium, this); - } - - // add stylesheets from document - m_authorStyle = new CSSRuleSet(); - - // Add rules from elments like SVG's <font-face> - if (mappedElementSheet) - m_authorStyle->addRulesFromSheet(mappedElementSheet, *m_medium, this); - - unsigned length = styleSheets->length(); - for (unsigned i = 0; i < length; i++) { - StyleSheet* sheet = styleSheets->item(i); - if (sheet->isCSSStyleSheet() && !sheet->disabled()) - m_authorStyle->addRulesFromSheet(static_cast<CSSStyleSheet*>(sheet), *m_medium, this); - } -} - -// this is a simplified style setting function for keyframe styles -void CSSStyleSelector::addKeyframeStyle(Document* doc, const WebKitCSSKeyframesRule* rule) -{ - AtomicString s(rule->name()); - RefPtr<KeyframeList> list; - if (m_keyframeRuleMap.contains(s.impl())) - list = m_keyframeRuleMap.get(s.impl()).get(); - else { - list = KeyframeList::create(s); - m_keyframeRuleMap.add(s.impl(), list); - } - list->clear(); - - for (unsigned i = 0; i < rule->length(); ++i) { - const WebKitCSSKeyframeRule* kf = rule->item(i); - m_style = new (doc->renderArena()) RenderStyle(); - m_style->ref(); - CSSMutableStyleDeclaration* decl = kf->style(); - DeprecatedValueListConstIterator<CSSProperty> end; - for (DeprecatedValueListConstIterator<CSSProperty> it = decl->valuesIterator(); it != end; ++it) { - const CSSProperty& current = *it; - applyProperty(current.id(), current.value()); - list->addProperty(current.id()); - } - list->insert(kf->key(), *m_style); - m_style->deref(doc->renderArena()); - m_style = 0; - } -} - -void CSSStyleSelector::init() -{ - m_element = 0; - m_matchedDecls.clear(); - m_ruleList = 0; - m_rootDefaultStyle = 0; - m_medium = 0; -} - -CSSStyleSelector::~CSSStyleSelector() -{ - m_fontSelector->clearDocument(); - delete m_medium; - ::delete m_rootDefaultStyle; - delete m_authorStyle; - delete m_userStyle; - deleteAllValues(m_viewportDependentMediaQueryResults); - m_keyframeRuleMap.clear(); -} - -static CSSStyleSheet* parseUASheet(const char* characters, unsigned size) -{ - CSSStyleSheet* sheet = CSSStyleSheet::create().releaseRef(); // leak the sheet on purpose - sheet->parseString(String(characters, size)); - return sheet; -} - -static void loadDefaultStyle() -{ - ASSERT(!defaultStyle); - - defaultStyle = new CSSRuleSet; - defaultPrintStyle = new CSSRuleSet; - defaultQuirksStyle = new CSSRuleSet; - defaultViewSourceStyle = new CSSRuleSet; - - // Strict-mode rules. - CSSStyleSheet* defaultSheet = parseUASheet(html4UserAgentStyleSheet, sizeof(html4UserAgentStyleSheet)); - RenderTheme::adjustDefaultStyleSheet(defaultSheet); - defaultStyle->addRulesFromSheet(defaultSheet, screenEval()); - defaultPrintStyle->addRulesFromSheet(defaultSheet, printEval()); - - // Quirks-mode rules. - defaultQuirksStyle->addRulesFromSheet(parseUASheet(quirksUserAgentStyleSheet, sizeof(quirksUserAgentStyleSheet)), screenEval()); - - // View source rules. - defaultViewSourceStyle->addRulesFromSheet(parseUASheet(sourceUserAgentStyleSheet, sizeof(sourceUserAgentStyleSheet)), screenEval()); -} - -void CSSStyleSelector::addMatchedDeclaration(CSSMutableStyleDeclaration* decl) -{ - if (!decl->hasVariableDependentValue()) { - m_matchedDecls.append(decl); - return; - } - - // See if we have already resolved the variables in this declaration. - CSSMutableStyleDeclaration* resolvedDecl = m_resolvedVariablesDeclarations.get(decl).get(); - if (resolvedDecl) { - m_matchedDecls.append(resolvedDecl); - return; - } - - // If this declaration has any variables in it, then we need to make a cloned - // declaration with as many variables resolved as possible for this style selector's media. - RefPtr<CSSMutableStyleDeclaration> newDecl = CSSMutableStyleDeclaration::create(decl->parentRule()); - m_matchedDecls.append(newDecl.get()); - m_resolvedVariablesDeclarations.set(decl, newDecl); - - HashSet<String> usedBlockVariables; - resolveVariablesForDeclaration(decl, newDecl.get(), usedBlockVariables); -} - -void CSSStyleSelector::resolveVariablesForDeclaration(CSSMutableStyleDeclaration* decl, CSSMutableStyleDeclaration* newDecl, HashSet<String>& usedBlockVariables) -{ - // Now iterate over the properties in the original declaration. As we resolve variables we'll end up - // mutating the new declaration (possibly expanding shorthands). The new declaration has no m_node - // though, so it can't mistakenly call setChanged on anything. - DeprecatedValueListConstIterator<CSSProperty> end; - for (DeprecatedValueListConstIterator<CSSProperty> it = decl->valuesIterator(); it != end; ++it) { - const CSSProperty& current = *it; - if (!current.value()->isVariableDependentValue()) { - // We can just add the parsed property directly. - newDecl->addParsedProperty(current); - continue; - } - CSSValueList* valueList = static_cast<CSSVariableDependentValue*>(current.value())->valueList(); - if (!valueList) - continue; - CSSParserValueList resolvedValueList; - unsigned s = valueList->length(); - bool fullyResolved = true; - for (unsigned i = 0; i < s; ++i) { - CSSValue* val = valueList->item(i); - CSSPrimitiveValue* primitiveValue = val->isPrimitiveValue() ? static_cast<CSSPrimitiveValue*>(val) : 0; - if (primitiveValue && primitiveValue->isVariable()) { - CSSVariablesRule* rule = m_variablesMap.get(primitiveValue->getStringValue()); - if (!rule || !rule->variables()) { - fullyResolved = false; - break; - } - - if (current.id() == CSSPropertyWebkitVariableDeclarationBlock && s == 1) { - fullyResolved = false; - if (!usedBlockVariables.contains(primitiveValue->getStringValue())) { - CSSMutableStyleDeclaration* declBlock = rule->variables()->getParsedVariableDeclarationBlock(primitiveValue->getStringValue()); - if (declBlock) { - usedBlockVariables.add(primitiveValue->getStringValue()); - resolveVariablesForDeclaration(declBlock, newDecl, usedBlockVariables); - } - } - } - - CSSValueList* resolvedVariable = rule->variables()->getParsedVariable(primitiveValue->getStringValue()); - if (!resolvedVariable) { - fullyResolved = false; - break; - } - unsigned valueSize = resolvedVariable->length(); - for (unsigned j = 0; j < valueSize; ++j) - resolvedValueList.addValue(resolvedVariable->item(j)->parserValue()); - } else - resolvedValueList.addValue(val->parserValue()); - } - - if (!fullyResolved) - continue; - - // We now have a fully resolved new value list. We want the parser to use this value list - // and parse our new declaration. - CSSParser(m_checker.m_strictParsing).parsePropertyWithResolvedVariables(current.id(), current.isImportant(), newDecl, &resolvedValueList); - } -} - -void CSSStyleSelector::matchRules(CSSRuleSet* rules, int& firstRuleIndex, int& lastRuleIndex) -{ - m_matchedRules.clear(); - - if (!rules || !m_element) - return; - - // We need to collect the rules for id, class, tag, and everything else into a buffer and - // then sort the buffer. - if (m_element->hasID()) - matchRulesForList(rules->getIDRules(m_element->getIDAttribute().impl()), firstRuleIndex, lastRuleIndex); - if (m_element->hasClass()) { - ASSERT(m_styledElement); - const ClassNames& classNames = m_styledElement->classNames(); - size_t size = classNames.size(); - for (size_t i = 0; i < size; ++i) - matchRulesForList(rules->getClassRules(classNames[i].impl()), firstRuleIndex, lastRuleIndex); - } - matchRulesForList(rules->getTagRules(m_element->localName().impl()), firstRuleIndex, lastRuleIndex); - matchRulesForList(rules->getUniversalRules(), firstRuleIndex, lastRuleIndex); - - // If we didn't match any rules, we're done. - if (m_matchedRules.isEmpty()) - return; - - // Sort the set of matched rules. - sortMatchedRules(0, m_matchedRules.size()); - - // Now transfer the set of matched rules over to our list of decls. - if (!m_checker.m_collectRulesOnly) { - for (unsigned i = 0; i < m_matchedRules.size(); i++) - addMatchedDeclaration(m_matchedRules[i]->rule()->declaration()); - } else { - for (unsigned i = 0; i < m_matchedRules.size(); i++) { - if (!m_ruleList) - m_ruleList = CSSRuleList::create(); - m_ruleList->append(m_matchedRules[i]->rule()); - } - } -} - -void CSSStyleSelector::matchRulesForList(CSSRuleDataList* rules, int& firstRuleIndex, int& lastRuleIndex) -{ - if (!rules) - return; - - for (CSSRuleData* d = rules->first(); d; d = d->next()) { - CSSStyleRule* rule = d->rule(); - const AtomicString& localName = m_element->localName(); - const AtomicString& selectorLocalName = d->selector()->m_tag.localName(); - if ((localName == selectorLocalName || selectorLocalName == starAtom) && checkSelector(d->selector())) { - // If the rule has no properties to apply, then ignore it. - CSSMutableStyleDeclaration* decl = rule->declaration(); - if (!decl || !decl->length()) - continue; - - // If we're matching normal rules, set a pseudo bit if - // we really just matched a pseudo-element. - if (m_dynamicPseudo != RenderStyle::NOPSEUDO && m_checker.m_pseudoStyle == RenderStyle::NOPSEUDO) { - if (m_checker.m_collectRulesOnly) - return; - if (m_dynamicPseudo < RenderStyle::FIRST_INTERNAL_PSEUDOID) - m_style->setHasPseudoStyle(m_dynamicPseudo); - } else { - // Update our first/last rule indices in the matched rules array. - lastRuleIndex = m_matchedDecls.size() + m_matchedRules.size(); - if (firstRuleIndex == -1) - firstRuleIndex = lastRuleIndex; - - // Add this rule to our list of matched rules. - addMatchedRule(d); - } - } - } -} - -bool operator >(CSSRuleData& r1, CSSRuleData& r2) -{ - int spec1 = r1.selector()->specificity(); - int spec2 = r2.selector()->specificity(); - return (spec1 == spec2) ? r1.position() > r2.position() : spec1 > spec2; -} -bool operator <=(CSSRuleData& r1, CSSRuleData& r2) -{ - return !(r1 > r2); -} - -void CSSStyleSelector::sortMatchedRules(unsigned start, unsigned end) -{ - if (start >= end || (end - start == 1)) - return; // Sanity check. - - if (end - start <= 6) { - // Apply a bubble sort for smaller lists. - for (unsigned i = end - 1; i > start; i--) { - bool sorted = true; - for (unsigned j = start; j < i; j++) { - CSSRuleData* elt = m_matchedRules[j]; - CSSRuleData* elt2 = m_matchedRules[j + 1]; - if (*elt > *elt2) { - sorted = false; - m_matchedRules[j] = elt2; - m_matchedRules[j + 1] = elt; - } - } - if (sorted) - return; - } - return; - } - - // Peform a merge sort for larger lists. - unsigned mid = (start + end) / 2; - sortMatchedRules(start, mid); - sortMatchedRules(mid, end); - - CSSRuleData* elt = m_matchedRules[mid - 1]; - CSSRuleData* elt2 = m_matchedRules[mid]; - - // Handle the fast common case (of equal specificity). The list may already - // be completely sorted. - if (*elt <= *elt2) - return; - - // We have to merge sort. Ensure our merge buffer is big enough to hold - // all the items. - Vector<CSSRuleData*> rulesMergeBuffer; - rulesMergeBuffer.reserveCapacity(end - start); - - unsigned i1 = start; - unsigned i2 = mid; - - elt = m_matchedRules[i1]; - elt2 = m_matchedRules[i2]; - - while (i1 < mid || i2 < end) { - if (i1 < mid && (i2 == end || *elt <= *elt2)) { - rulesMergeBuffer.append(elt); - if (++i1 < mid) - elt = m_matchedRules[i1]; - } else { - rulesMergeBuffer.append(elt2); - if (++i2 < end) - elt2 = m_matchedRules[i2]; - } - } - - for (unsigned i = start; i < end; i++) - m_matchedRules[i] = rulesMergeBuffer[i - start]; -} - -void CSSStyleSelector::initElementAndPseudoState(Element* e) -{ - m_element = e; - if (m_element && m_element->isStyledElement()) - m_styledElement = static_cast<StyledElement*>(m_element); - else - m_styledElement = 0; - pseudoState = PseudoUnknown; -} - -void CSSStyleSelector::initForStyleResolve(Element* e, RenderStyle* parentStyle, RenderStyle::PseudoId pseudoID) -{ - m_checker.m_pseudoStyle = pseudoID; - - m_parentNode = e ? e->parentNode() : 0; - -#if ENABLE(SVG) - if (!m_parentNode && e && e->isSVGElement() && e->isShadowNode()) - m_parentNode = e->shadowParentNode(); -#endif - - if (parentStyle) - m_parentStyle = parentStyle; - else - m_parentStyle = m_parentNode ? m_parentNode->renderStyle() : 0; - - m_style = 0; - - m_matchedDecls.clear(); - - m_ruleList = 0; - - m_fontDirty = false; -} - -static inline const AtomicString* linkAttribute(Node* node) -{ - if (!node->isLink()) - return 0; - - ASSERT(node->isElementNode()); - Element* element = static_cast<Element*>(node); - if (element->isHTMLElement()) - return &element->getAttribute(hrefAttr); -#if ENABLE(SVG) - if (element->isSVGElement()) - return &element->getAttribute(XLinkNames::hrefAttr); -#endif - return 0; -} - -CSSStyleSelector::SelectorChecker::SelectorChecker(Document* document, bool strictParsing, bool collectRulesOnly) - : m_document(document) - , m_strictParsing(strictParsing) - , m_collectRulesOnly(collectRulesOnly) - , m_pseudoStyle(RenderStyle::NOPSEUDO) - , m_documentIsHTML(document->isHTMLDocument()) -{ -} - -PseudoState CSSStyleSelector::SelectorChecker::checkPseudoState(Element* element, bool checkVisited) const -{ - const AtomicString* attr = linkAttribute(element); - if (!attr || attr->isNull()) - return PseudoNone; - - if (!checkVisited) - return PseudoAnyLink; - - unsigned hash = m_document->visitedLinkHash(*attr); - if (!hash) - return PseudoLink; - - Frame* frame = m_document->frame(); - if (!frame) - return PseudoLink; - - Page* page = frame->page(); - if (!page) - return PseudoLink; - - m_linksCheckedForVisitedState.add(hash); - return page->group().isLinkVisited(hash) ? PseudoVisited : PseudoLink; -} - -bool CSSStyleSelector::SelectorChecker::checkSelector(CSSSelector* sel, Element* element) const -{ - pseudoState = PseudoUnknown; - RenderStyle::PseudoId dynamicPseudo = RenderStyle::NOPSEUDO; - - return checkSelector(sel, element, 0, dynamicPseudo, true, false) == SelectorMatches; -} - -// a helper function for parsing nth-arguments -static bool parseNth(const String& nth, int &a, int &b) -{ - if (nth.isEmpty()) - return false; - a = 0; - b = 0; - if (nth == "odd") { - a = 2; - b = 1; - } else if (nth == "even") { - a = 2; - b = 0; - } else { - int n = nth.find('n'); - if (n != -1) { - if (nth[0] == '-') { - if (n == 1) - a = -1; // -n == -1n - else - a = nth.substring(0, n).toInt(); - } else if (!n) - a = 1; // n == 1n - else - a = nth.substring(0, n).toInt(); - - int p = nth.find('+', n); - if (p != -1) - b = nth.substring(p + 1, nth.length() - p - 1).toInt(); - else { - p = nth.find('-', n); - b = -nth.substring(p + 1, nth.length() - p - 1).toInt(); - } - } else - b = nth.toInt(); - } - return true; -} - -// a helper function for checking nth-arguments -static bool matchNth(int count, int a, int b) -{ - if (!a) - return count == b; - else if (a > 0) { - if (count < b) - return false; - return (count - b) % a == 0; - } else { - if (count > b) - return false; - return (b - count) % (-a) == 0; - } -} - - -#ifdef STYLE_SHARING_STATS -static int fraction = 0; -static int total = 0; -#endif - -static const unsigned cStyleSearchThreshold = 10; - -Node* CSSStyleSelector::locateCousinList(Element* parent, unsigned depth) -{ - if (parent && parent->isStyledElement()) { - StyledElement* p = static_cast<StyledElement*>(parent); - if (!p->inlineStyleDecl() && !p->hasID()) { - Node* r = p->previousSibling(); - unsigned subcount = 0; - RenderStyle* st = p->renderStyle(); - while (r) { - if (r->renderStyle() == st) - return r->lastChild(); - if (subcount++ == cStyleSearchThreshold) - return 0; - r = r->previousSibling(); - } - if (!r && depth < cStyleSearchThreshold) - r = locateCousinList(static_cast<Element*>(parent->parentNode()), depth + 1); - while (r) { - if (r->renderStyle() == st) - return r->lastChild(); - if (subcount++ == cStyleSearchThreshold) - return 0; - r = r->previousSibling(); - } - } - } - return 0; -} - -bool CSSStyleSelector::canShareStyleWithElement(Node* n) -{ - if (n->isStyledElement()) { - StyledElement* s = static_cast<StyledElement*>(n); - RenderStyle* style = s->renderStyle(); - if (style && !style->unique() && - (s->tagQName() == m_element->tagQName()) && !s->hasID() && - (s->hasClass() == m_element->hasClass()) && !s->inlineStyleDecl() && - (s->hasMappedAttributes() == m_styledElement->hasMappedAttributes()) && - (s->isLink() == m_element->isLink()) && - !style->affectedByAttributeSelectors() && - (s->hovered() == m_element->hovered()) && - (s->active() == m_element->active()) && - (s->focused() == m_element->focused()) && - (s != s->document()->getCSSTarget() && m_element != m_element->document()->getCSSTarget()) && - (s->getAttribute(typeAttr) == m_element->getAttribute(typeAttr)) && - (s->getAttribute(XMLNames::langAttr) == m_element->getAttribute(XMLNames::langAttr)) && - (s->getAttribute(langAttr) == m_element->getAttribute(langAttr)) && - (s->getAttribute(readonlyAttr) == m_element->getAttribute(readonlyAttr)) && - (s->getAttribute(cellpaddingAttr) == m_element->getAttribute(cellpaddingAttr))) { - bool isControl = s->isControl(); - if (isControl != m_element->isControl()) - return false; - if (isControl && (s->isEnabled() != m_element->isEnabled()) || - (s->isIndeterminate() != m_element->isIndeterminate()) || - (s->isChecked() != m_element->isChecked())) - return false; - - if (style->transitions() || style->animations()) - return false; - - bool classesMatch = true; - if (s->hasClass()) { - const AtomicString& class1 = m_element->getAttribute(classAttr); - const AtomicString& class2 = s->getAttribute(classAttr); - classesMatch = (class1 == class2); - } - - if (classesMatch) { - bool mappedAttrsMatch = true; - if (s->hasMappedAttributes()) - mappedAttrsMatch = s->mappedAttributes()->mapsEquivalent(m_styledElement->mappedAttributes()); - if (mappedAttrsMatch) { - bool linksMatch = true; - - if (s->isLink()) { - // We need to check to see if the visited state matches. - if (pseudoState == PseudoUnknown) { - const Color& linkColor = m_element->document()->linkColor(); - const Color& visitedColor = m_element->document()->visitedLinkColor(); - pseudoState = m_checker.checkPseudoState(m_element, style->pseudoState() != PseudoAnyLink || linkColor != visitedColor); - } - linksMatch = (pseudoState == style->pseudoState()); - } - - if (linksMatch) - return true; - } - } - } - } - return false; -} - -RenderStyle* CSSStyleSelector::locateSharedStyle() -{ - if (m_styledElement && !m_styledElement->inlineStyleDecl() && !m_styledElement->hasID() && !m_styledElement->document()->usesSiblingRules()) { - // Check previous siblings. - unsigned count = 0; - Node* n; - for (n = m_element->previousSibling(); n && !n->isElementNode(); n = n->previousSibling()) { } - while (n) { - if (canShareStyleWithElement(n)) - return n->renderStyle(); - if (count++ == cStyleSearchThreshold) - return 0; - for (n = n->previousSibling(); n && !n->isElementNode(); n = n->previousSibling()) { } - } - if (!n) - n = locateCousinList(static_cast<Element*>(m_element->parentNode())); - while (n) { - if (canShareStyleWithElement(n)) - return n->renderStyle(); - if (count++ == cStyleSearchThreshold) - return 0; - for (n = n->previousSibling(); n && !n->isElementNode(); n = n->previousSibling()) { } - } - } - return 0; -} - -void CSSStyleSelector::matchUARules(int& firstUARule, int& lastUARule) -{ - // First we match rules from the user agent sheet. - CSSRuleSet* userAgentStyleSheet = m_medium->mediaTypeMatchSpecific("print") - ? defaultPrintStyle : defaultStyle; - matchRules(userAgentStyleSheet, firstUARule, lastUARule); - - // In quirks mode, we match rules from the quirks user agent sheet. - if (!m_checker.m_strictParsing) - matchRules(defaultQuirksStyle, firstUARule, lastUARule); - - // If we're in view source mode, then we match rules from the view source style sheet. - if (m_checker.m_document->frame() && m_checker.m_document->frame()->inViewSourceMode()) - matchRules(defaultViewSourceStyle, firstUARule, lastUARule); -} - -// If resolveForRootDefault is true, style based on user agent style sheet only. This is used in media queries, where -// relative units are interpreted according to document root element style, styled only with UA stylesheet - -RenderStyle* CSSStyleSelector::styleForElement(Element* e, RenderStyle* defaultParent, bool allowSharing, bool resolveForRootDefault) -{ - // Once an element has a renderer, we don't try to destroy it, since otherwise the renderer - // will vanish if a style recalc happens during loading. - if (allowSharing && !e->document()->haveStylesheetsLoaded() && !e->renderer()) { - if (!s_styleNotYetAvailable) { - s_styleNotYetAvailable = ::new RenderStyle; - s_styleNotYetAvailable->ref(); - s_styleNotYetAvailable->setDisplay(NONE); - s_styleNotYetAvailable->font().update(m_fontSelector); - } - s_styleNotYetAvailable->ref(); - e->document()->setHasNodesWithPlaceholderStyle(); - return s_styleNotYetAvailable; - } - - initElementAndPseudoState(e); - if (allowSharing) { - m_style = locateSharedStyle(); -#ifdef STYLE_SHARING_STATS - fraction += m_style != 0; - total++; - printf("Sharing %d out of %d\n", fraction, total); -#endif - if (m_style) { - m_style->ref(); - return m_style; - } - } - initForStyleResolve(e, defaultParent); - - if (resolveForRootDefault) { - m_style = ::new RenderStyle(); - // don't ref, because we want to delete this, but we cannot unref it - } else { - m_style = new (e->document()->renderArena()) RenderStyle(); - m_style->ref(); - } - if (m_parentStyle) - m_style->inheritFrom(m_parentStyle); - else - m_parentStyle = m_style; - -#if ENABLE(SVG) - static bool loadedSVGUserAgentSheet; - if (e->isSVGElement() && !loadedSVGUserAgentSheet) { - // SVG rules. - loadedSVGUserAgentSheet = true; - CSSStyleSheet* svgSheet = parseUASheet(svgUserAgentStyleSheet, sizeof(svgUserAgentStyleSheet)); - defaultStyle->addRulesFromSheet(svgSheet, screenEval()); - defaultPrintStyle->addRulesFromSheet(svgSheet, printEval()); - } -#endif - - int firstUARule = -1, lastUARule = -1; - int firstUserRule = -1, lastUserRule = -1; - int firstAuthorRule = -1, lastAuthorRule = -1; - matchUARules(firstUARule, lastUARule); - - if (!resolveForRootDefault) { - // 4. Now we check user sheet rules. - if (m_matchAuthorAndUserStyles) - matchRules(m_userStyle, firstUserRule, lastUserRule); - - // 5. Now check author rules, beginning first with presentational attributes - // mapped from HTML. - if (m_styledElement) { - // Ask if the HTML element has mapped attributes. - if (m_styledElement->hasMappedAttributes()) { - // Walk our attribute list and add in each decl. - const NamedMappedAttrMap* map = m_styledElement->mappedAttributes(); - for (unsigned i = 0; i < map->length(); i++) { - MappedAttribute* attr = map->attributeItem(i); - if (attr->decl()) { - lastAuthorRule = m_matchedDecls.size(); - if (firstAuthorRule == -1) - firstAuthorRule = lastAuthorRule; - addMatchedDeclaration(attr->decl()); - } - } - } - - // Now we check additional mapped declarations. - // Tables and table cells share an additional mapped rule that must be applied - // after all attributes, since their mapped style depends on the values of multiple attributes. - if (m_styledElement->canHaveAdditionalAttributeStyleDecls()) { - m_additionalAttributeStyleDecls.clear(); - m_styledElement->additionalAttributeStyleDecls(m_additionalAttributeStyleDecls); - if (!m_additionalAttributeStyleDecls.isEmpty()) { - unsigned additionalDeclsSize = m_additionalAttributeStyleDecls.size(); - if (firstAuthorRule == -1) - firstAuthorRule = m_matchedDecls.size(); - lastAuthorRule = m_matchedDecls.size() + additionalDeclsSize - 1; - for (unsigned i = 0; i < additionalDeclsSize; i++) - addMatchedDeclaration(m_additionalAttributeStyleDecls[i]); - } - } - } - - // 6. Check the rules in author sheets next. - if (m_matchAuthorAndUserStyles) - matchRules(m_authorStyle, firstAuthorRule, lastAuthorRule); - - // 7. Now check our inline style attribute. - if (m_matchAuthorAndUserStyles && m_styledElement) { - CSSMutableStyleDeclaration* inlineDecl = m_styledElement->inlineStyleDecl(); - if (inlineDecl) { - lastAuthorRule = m_matchedDecls.size(); - if (firstAuthorRule == -1) - firstAuthorRule = lastAuthorRule; - addMatchedDeclaration(inlineDecl); - } - } - } - - // Now we have all of the matched rules in the appropriate order. Walk the rules and apply - // high-priority properties first, i.e., those properties that other properties depend on. - // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important - // and (4) normal important. - m_lineHeightValue = 0; - applyDeclarations(true, false, 0, m_matchedDecls.size() - 1); - if (!resolveForRootDefault) { - applyDeclarations(true, true, firstAuthorRule, lastAuthorRule); - applyDeclarations(true, true, firstUserRule, lastUserRule); - } - applyDeclarations(true, true, firstUARule, lastUARule); - - // If our font got dirtied, go ahead and update it now. - if (m_fontDirty) - updateFont(); - - // Line-height is set when we are sure we decided on the font-size - if (m_lineHeightValue) - applyProperty(CSSPropertyLineHeight, m_lineHeightValue); - - // Now do the normal priority UA properties. - applyDeclarations(false, false, firstUARule, lastUARule); - - // Cache our border and background so that we can examine them later. - cacheBorderAndBackground(); - - // Now do the author and user normal priority properties and all the !important properties. - if (!resolveForRootDefault) { - applyDeclarations(false, false, lastUARule + 1, m_matchedDecls.size() - 1); - applyDeclarations(false, true, firstAuthorRule, lastAuthorRule); - applyDeclarations(false, true, firstUserRule, lastUserRule); - } - applyDeclarations(false, true, firstUARule, lastUARule); - - // If our font got dirtied by one of the non-essential font props, - // go ahead and update it a second time. - if (m_fontDirty) - updateFont(); - - // Clean up our style object's display and text decorations (among other fixups). - adjustRenderStyle(m_style, e); - - // If we are a link, cache the determined pseudo-state. - if (e->isLink()) - m_style->setPseudoState(pseudoState); - - // If we have first-letter pseudo style, do not share this style - if (m_style->hasPseudoStyle(RenderStyle::FIRST_LETTER)) - m_style->setUnique(); - - // Now return the style. - return m_style; -} - -RenderStyle* CSSStyleSelector::pseudoStyleForElement(RenderStyle::PseudoId pseudo, Element* e, RenderStyle* parentStyle) -{ - if (!e) - return 0; - - initElementAndPseudoState(e); - initForStyleResolve(e, parentStyle, pseudo); - m_style = parentStyle; - - // Since we don't use pseudo-elements in any of our quirk/print user agent rules, don't waste time walking - // those rules. - - // Check UA, user and author rules. - int firstUARule = -1, lastUARule = -1, firstUserRule = -1, lastUserRule = -1, firstAuthorRule = -1, lastAuthorRule = -1; - matchUARules(firstUARule, lastUARule); - - if (m_matchAuthorAndUserStyles) { - matchRules(m_userStyle, firstUserRule, lastUserRule); - matchRules(m_authorStyle, firstAuthorRule, lastAuthorRule); - } - - if (m_matchedDecls.isEmpty()) - return 0; - - m_style = new (e->document()->renderArena()) RenderStyle(); - m_style->ref(); - if (parentStyle) - m_style->inheritFrom(parentStyle); - - m_style->noninherited_flags._styleType = pseudo; - - m_lineHeightValue = 0; - // High-priority properties. - applyDeclarations(true, false, 0, m_matchedDecls.size() - 1); - applyDeclarations(true, true, firstAuthorRule, lastAuthorRule); - applyDeclarations(true, true, firstUserRule, lastUserRule); - applyDeclarations(true, true, firstUARule, lastUARule); - - // If our font got dirtied, go ahead and update it now. - if (m_fontDirty) - updateFont(); - - // Line-height is set when we are sure we decided on the font-size - if (m_lineHeightValue) - applyProperty(CSSPropertyLineHeight, m_lineHeightValue); - - // Now do the normal priority properties. - applyDeclarations(false, false, firstUARule, lastUARule); - - // Cache our border and background so that we can examine them later. - cacheBorderAndBackground(); - - applyDeclarations(false, false, lastUARule + 1, m_matchedDecls.size() - 1); - applyDeclarations(false, true, firstAuthorRule, lastAuthorRule); - applyDeclarations(false, true, firstUserRule, lastUserRule); - applyDeclarations(false, true, firstUARule, lastUARule); - - // If our font got dirtied by one of the non-essential font props, - // go ahead and update it a second time. - if (m_fontDirty) - updateFont(); - // Clean up our style object's display and text decorations (among other fixups). - adjustRenderStyle(m_style, 0); - - // Now return the style. - return m_style; -} - -static void addIntrinsicMargins(RenderStyle* style) -{ - // Intrinsic margin value. - const int intrinsicMargin = 2 * style->effectiveZoom(); - - // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed. - // FIXME: Using "quirk" to decide the margin wasn't set is kind of lame. - if (style->width().isIntrinsicOrAuto()) { - if (style->marginLeft().quirk()) - style->setMarginLeft(Length(intrinsicMargin, Fixed)); - if (style->marginRight().quirk()) - style->setMarginRight(Length(intrinsicMargin, Fixed)); - } - - if (style->height().isAuto()) { - if (style->marginTop().quirk()) - style->setMarginTop(Length(intrinsicMargin, Fixed)); - if (style->marginBottom().quirk()) - style->setMarginBottom(Length(intrinsicMargin, Fixed)); - } -} - -void CSSStyleSelector::adjustRenderStyle(RenderStyle* style, Element *e) -{ - // Cache our original display. - style->setOriginalDisplay(style->display()); - - if (style->display() != NONE) { - // If we have a <td> that specifies a float property, in quirks mode we just drop the float - // property. - // Sites also commonly use display:inline/block on <td>s and <table>s. In quirks mode we force - // these tags to retain their display types. - if (!m_checker.m_strictParsing && e) { - if (e->hasTagName(tdTag)) { - style->setDisplay(TABLE_CELL); - style->setFloating(FNONE); - } - else if (e->hasTagName(tableTag)) - style->setDisplay(style->isDisplayInlineType() ? INLINE_TABLE : TABLE); - } - - // Tables never support the -webkit-* values for text-align and will reset back to the default. - if (e && e->hasTagName(tableTag) && (style->textAlign() == WEBKIT_LEFT || style->textAlign() == WEBKIT_CENTER || style->textAlign() == WEBKIT_RIGHT)) - style->setTextAlign(TAAUTO); - - // Frames and framesets never honor position:relative or position:absolute. This is necessary to - // fix a crash where a site tries to position these objects. They also never honor display. - if (e && (e->hasTagName(frameTag) || e->hasTagName(framesetTag))) { - style->setPosition(StaticPosition); - style->setDisplay(BLOCK); - } - - // Table headers with a text-align of auto will change the text-align to center. - if (e && e->hasTagName(thTag) && style->textAlign() == TAAUTO) - style->setTextAlign(CENTER); - - // Mutate the display to BLOCK or TABLE for certain cases, e.g., if someone attempts to - // position or float an inline, compact, or run-in. Cache the original display, since it - // may be needed for positioned elements that have to compute their static normal flow - // positions. We also force inline-level roots to be block-level. - if (style->display() != BLOCK && style->display() != TABLE && style->display() != BOX && - (style->position() == AbsolutePosition || style->position() == FixedPosition || style->floating() != FNONE || - (e && e->document()->documentElement() == e))) { - if (style->display() == INLINE_TABLE) - style->setDisplay(TABLE); - else if (style->display() == INLINE_BOX) - style->setDisplay(BOX); - else if (style->display() == LIST_ITEM) { - // It is a WinIE bug that floated list items lose their bullets, so we'll emulate the quirk, - // but only in quirks mode. - if (!m_checker.m_strictParsing && style->floating() != FNONE) - style->setDisplay(BLOCK); - } - else - style->setDisplay(BLOCK); - } - - // After performing the display mutation, check table rows. We do not honor position:relative on - // table rows or cells. This has been established in CSS2.1 (and caused a crash in containingBlock() - // on some sites). - if ((style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW_GROUP || - style->display() == TABLE_FOOTER_GROUP || style->display() == TABLE_ROW || style->display() == TABLE_CELL) && - style->position() == RelativePosition) - style->setPosition(StaticPosition); - } - - // Make sure our z-index value is only applied if the object is positioned. - if (style->position() == StaticPosition) - style->setHasAutoZIndex(); - - // Auto z-index becomes 0 for the root element and transparent objects. This prevents - // cases where objects that should be blended as a single unit end up with a non-transparent - // object wedged in between them. Auto z-index also becomes 0 for objects that specify transforms/masks/reflections. - if (style->hasAutoZIndex() && ((e && e->document()->documentElement() == e) || style->opacity() < 1.0f || - style->hasTransform() || style->hasMask() || style->boxReflect())) - style->setZIndex(0); - - // Button, legend, input, select and textarea all consider width values of 'auto' to be 'intrinsic'. - // This will be important when we use block flows for all form controls. - if (e && (e->hasTagName(legendTag) || e->hasTagName(buttonTag) || e->hasTagName(inputTag) || - e->hasTagName(selectTag) || e->hasTagName(textareaTag))) { - if (style->width().isAuto()) - style->setWidth(Length(Intrinsic)); - } - - // Textarea considers overflow visible as auto. - if (e && e->hasTagName(textareaTag)) { - style->setOverflowX(style->overflowX() == OVISIBLE ? OAUTO : style->overflowX()); - style->setOverflowY(style->overflowY() == OVISIBLE ? OAUTO : style->overflowY()); - } - - // Finally update our text decorations in effect, but don't allow text-decoration to percolate through - // tables, inline blocks, inline tables, or run-ins. - if (style->display() == TABLE || style->display() == INLINE_TABLE || style->display() == RUN_IN - || style->display() == INLINE_BLOCK || style->display() == INLINE_BOX) - style->setTextDecorationsInEffect(style->textDecoration()); - else - style->addToTextDecorationsInEffect(style->textDecoration()); - - // If either overflow value is not visible, change to auto. - if (style->overflowX() == OMARQUEE && style->overflowY() != OMARQUEE) - style->setOverflowY(OMARQUEE); - else if (style->overflowY() == OMARQUEE && style->overflowX() != OMARQUEE) - style->setOverflowX(OMARQUEE); - else if (style->overflowX() == OVISIBLE && style->overflowY() != OVISIBLE) - style->setOverflowX(OAUTO); - else if (style->overflowY() == OVISIBLE && style->overflowX() != OVISIBLE) - style->setOverflowY(OAUTO); - - // Table rows, sections and the table itself will support overflow:hidden and will ignore scroll/auto. - // FIXME: Eventually table sections will support auto and scroll. - if (style->display() == TABLE || style->display() == INLINE_TABLE || - style->display() == TABLE_ROW_GROUP || style->display() == TABLE_ROW) { - if (style->overflowX() != OVISIBLE && style->overflowX() != OHIDDEN) - style->setOverflowX(OVISIBLE); - if (style->overflowY() != OVISIBLE && style->overflowY() != OHIDDEN) - style->setOverflowY(OVISIBLE); - } - - // Cull out any useless layers and also repeat patterns into additional layers. - style->adjustBackgroundLayers(); - style->adjustMaskLayers(); - - // Do the same for animations and transitions. - style->adjustAnimations(); - style->adjustTransitions(); - - // Important: Intrinsic margins get added to controls before the theme has adjusted the style, since the theme will - // alter fonts and heights/widths. - if (e && e->isControl() && style->fontSize() >= 11) { - // Don't apply intrinsic margins to image buttons. The designer knows how big the images are, - // so we have to treat all image buttons as though they were explicitly sized. - if (!e->hasTagName(inputTag) || static_cast<HTMLInputElement*>(e)->inputType() != HTMLInputElement::IMAGE) - addIntrinsicMargins(style); - } - - // Let the theme also have a crack at adjusting the style. - if (style->hasAppearance()) - theme()->adjustStyle(this, style, e, m_hasUAAppearance, m_borderData, m_backgroundData, m_backgroundColor); - -#if ENABLE(SVG) - if (e && e->isSVGElement()) { - // Spec: http://www.w3.org/TR/SVG/masking.html#OverflowProperty - if (style->overflowY() == OSCROLL) - style->setOverflowY(OHIDDEN); - else if (style->overflowY() == OAUTO) - style->setOverflowY(OVISIBLE); - - if (style->overflowX() == OSCROLL) - style->setOverflowX(OHIDDEN); - else if (style->overflowX() == OAUTO) - style->setOverflowX(OVISIBLE); - - // Only the root <svg> element in an SVG document fragment tree honors css position - if (!(e->hasTagName(SVGNames::svgTag) && e->parentNode() && !e->parentNode()->isSVGElement())) - style->setPosition(RenderStyle::initialPosition()); - } -#endif -} - -void CSSStyleSelector::updateFont() -{ - checkForTextSizeAdjust(); - checkForGenericFamilyChange(m_style, m_parentStyle); - checkForZoomChange(m_style, m_parentStyle); - m_style->font().update(m_fontSelector); - m_fontDirty = false; -} - -void CSSStyleSelector::cacheBorderAndBackground() -{ - m_hasUAAppearance = m_style->hasAppearance(); - if (m_hasUAAppearance) { - m_borderData = m_style->border(); - m_backgroundData = *m_style->backgroundLayers(); - m_backgroundColor = m_style->backgroundColor(); - } -} - -PassRefPtr<CSSRuleList> CSSStyleSelector::styleRulesForElement(Element* e, bool authorOnly) -{ - if (!e || !e->document()->haveStylesheetsLoaded()) - return 0; - - m_checker.m_collectRulesOnly = true; - - initElementAndPseudoState(e); - initForStyleResolve(e); - - if (!authorOnly) { - int firstUARule = -1, lastUARule = -1; - // First we match rules from the user agent sheet. - matchUARules(firstUARule, lastUARule); - - // Now we check user sheet rules. - if (m_matchAuthorAndUserStyles) { - int firstUserRule = -1, lastUserRule = -1; - matchRules(m_userStyle, firstUserRule, lastUserRule); - } - } - - if (m_matchAuthorAndUserStyles) { - // Check the rules in author sheets. - int firstAuthorRule = -1, lastAuthorRule = -1; - matchRules(m_authorStyle, firstAuthorRule, lastAuthorRule); - } - - m_checker.m_collectRulesOnly = false; - - return m_ruleList.release(); -} - -PassRefPtr<CSSRuleList> CSSStyleSelector::pseudoStyleRulesForElement(Element*, const String& pseudoStyle, bool authorOnly) -{ - // FIXME: Implement this. - return 0; -} - -bool CSSStyleSelector::checkSelector(CSSSelector* sel) -{ - m_dynamicPseudo = RenderStyle::NOPSEUDO; - - // Check the selector - SelectorMatch match = m_checker.checkSelector(sel, m_element, &m_selectorAttrs, m_dynamicPseudo, true, false, m_style, m_parentStyle); - if (match != SelectorMatches) - return false; - - if (m_checker.m_pseudoStyle != RenderStyle::NOPSEUDO && m_checker.m_pseudoStyle != m_dynamicPseudo) - return false; - - return true; -} - -// Recursive check of selectors and combinators -// It can return 3 different values: -// * SelectorMatches - the selector matches the element e -// * SelectorFailsLocally - the selector fails for the element e -// * SelectorFailsCompletely - the selector fails for e and any sibling or ancestor of e -CSSStyleSelector::SelectorMatch CSSStyleSelector::SelectorChecker::checkSelector(CSSSelector* sel, Element* e, HashSet<AtomicStringImpl*>* selectorAttrs, RenderStyle::PseudoId& dynamicPseudo, bool isAncestor, bool isSubSelector, RenderStyle* elementStyle, RenderStyle* elementParentStyle) const -{ -#if ENABLE(SVG) - // Spec: CSS2 selectors cannot be applied to the (conceptually) cloned DOM tree - // because its contents are not part of the formal document structure. - if (e->isSVGElement() && e->isShadowNode()) - return SelectorFailsCompletely; -#endif - - // first selector has to match - if (!checkOneSelector(sel, e, selectorAttrs, dynamicPseudo, isAncestor, isSubSelector, elementStyle, elementParentStyle)) - return SelectorFailsLocally; - - // The rest of the selectors has to match - CSSSelector::Relation relation = sel->relation(); - - // Prepare next sel - sel = sel->m_tagHistory; - if (!sel) - return SelectorMatches; - - if (relation != CSSSelector::SubSelector) - // Bail-out if this selector is irrelevant for the pseudoStyle - if (m_pseudoStyle != RenderStyle::NOPSEUDO && m_pseudoStyle != dynamicPseudo) - return SelectorFailsCompletely; - - switch (relation) { - case CSSSelector::Descendant: - while (true) { - Node* n = e->parentNode(); - if (!n || !n->isElementNode()) - return SelectorFailsCompletely; - e = static_cast<Element*>(n); - SelectorMatch match = checkSelector(sel, e, selectorAttrs, dynamicPseudo, true, false); - if (match != SelectorFailsLocally) - return match; - } - break; - case CSSSelector::Child: - { - Node* n = e->parentNode(); - if (!n || !n->isElementNode()) - return SelectorFailsCompletely; - e = static_cast<Element*>(n); - return checkSelector(sel, e, selectorAttrs, dynamicPseudo, true, false); - } - case CSSSelector::DirectAdjacent: - { - if (!m_collectRulesOnly && e->parentNode() && e->parentNode()->isElementNode()) { - RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle(); - if (parentStyle) - parentStyle->setChildrenAffectedByDirectAdjacentRules(); - } - Node* n = e->previousSibling(); - while (n && !n->isElementNode()) - n = n->previousSibling(); - if (!n) - return SelectorFailsLocally; - e = static_cast<Element*>(n); - return checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, false); - } - case CSSSelector::IndirectAdjacent: - if (!m_collectRulesOnly && e->parentNode() && e->parentNode()->isElementNode()) { - RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle(); - if (parentStyle) - parentStyle->setChildrenAffectedByForwardPositionalRules(); - } - while (true) { - Node* n = e->previousSibling(); - while (n && !n->isElementNode()) - n = n->previousSibling(); - if (!n) - return SelectorFailsLocally; - e = static_cast<Element*>(n); - SelectorMatch match = checkSelector(sel, e, selectorAttrs, dynamicPseudo, false, false); - if (match != SelectorFailsLocally) - return match; - }; - break; - case CSSSelector::SubSelector: - // a selector is invalid if something follows a pseudo-element - if (elementStyle && dynamicPseudo != RenderStyle::NOPSEUDO) - return SelectorFailsCompletely; - return checkSelector(sel, e, selectorAttrs, dynamicPseudo, isAncestor, true, elementStyle, elementParentStyle); - } - - return SelectorFailsCompletely; -} - -static void addLocalNameToSet(HashSet<AtomicStringImpl*>* set, const QualifiedName& qName) -{ - set->add(qName.localName().impl()); -} - -static HashSet<AtomicStringImpl*>* createHtmlCaseInsensitiveAttributesSet() -{ - // This is the list of attributes in HTML 4.01 with values marked as "[CI]" or case-insensitive - // Mozilla treats all other values as case-sensitive, thus so do we. - HashSet<AtomicStringImpl*>* attrSet = new HashSet<AtomicStringImpl*>; - - addLocalNameToSet(attrSet, accept_charsetAttr); - addLocalNameToSet(attrSet, acceptAttr); - addLocalNameToSet(attrSet, alignAttr); - addLocalNameToSet(attrSet, alinkAttr); - addLocalNameToSet(attrSet, axisAttr); - addLocalNameToSet(attrSet, bgcolorAttr); - addLocalNameToSet(attrSet, charsetAttr); - addLocalNameToSet(attrSet, checkedAttr); - addLocalNameToSet(attrSet, clearAttr); - addLocalNameToSet(attrSet, codetypeAttr); - addLocalNameToSet(attrSet, colorAttr); - addLocalNameToSet(attrSet, compactAttr); - addLocalNameToSet(attrSet, declareAttr); - addLocalNameToSet(attrSet, deferAttr); - addLocalNameToSet(attrSet, dirAttr); - addLocalNameToSet(attrSet, disabledAttr); - addLocalNameToSet(attrSet, enctypeAttr); - addLocalNameToSet(attrSet, faceAttr); - addLocalNameToSet(attrSet, frameAttr); - addLocalNameToSet(attrSet, hreflangAttr); - addLocalNameToSet(attrSet, http_equivAttr); - addLocalNameToSet(attrSet, langAttr); - addLocalNameToSet(attrSet, languageAttr); - addLocalNameToSet(attrSet, linkAttr); - addLocalNameToSet(attrSet, mediaAttr); - addLocalNameToSet(attrSet, methodAttr); - addLocalNameToSet(attrSet, multipleAttr); - addLocalNameToSet(attrSet, nohrefAttr); - addLocalNameToSet(attrSet, noresizeAttr); - addLocalNameToSet(attrSet, noshadeAttr); - addLocalNameToSet(attrSet, nowrapAttr); - addLocalNameToSet(attrSet, readonlyAttr); - addLocalNameToSet(attrSet, relAttr); - addLocalNameToSet(attrSet, revAttr); - addLocalNameToSet(attrSet, rulesAttr); - addLocalNameToSet(attrSet, scopeAttr); - addLocalNameToSet(attrSet, scrollingAttr); - addLocalNameToSet(attrSet, selectedAttr); - addLocalNameToSet(attrSet, shapeAttr); - addLocalNameToSet(attrSet, targetAttr); - addLocalNameToSet(attrSet, textAttr); - addLocalNameToSet(attrSet, typeAttr); - addLocalNameToSet(attrSet, valignAttr); - addLocalNameToSet(attrSet, valuetypeAttr); - addLocalNameToSet(attrSet, vlinkAttr); - - return attrSet; -} - -static bool htmlAttributeHasCaseInsensitiveValue(const QualifiedName& attr) -{ - static HashSet<AtomicStringImpl*>* htmlCaseInsensitiveAttributesSet = createHtmlCaseInsensitiveAttributesSet(); - bool isPossibleHTMLAttr = !attr.hasPrefix() && (attr.namespaceURI() == nullAtom); - return isPossibleHTMLAttr && htmlCaseInsensitiveAttributesSet->contains(attr.localName().impl()); -} - -bool CSSStyleSelector::SelectorChecker::checkOneSelector(CSSSelector* sel, Element* e, HashSet<AtomicStringImpl*>* selectorAttrs, RenderStyle::PseudoId& dynamicPseudo, bool isAncestor, bool isSubSelector, RenderStyle* elementStyle, RenderStyle* elementParentStyle) const -{ - if (!e) - return false; - - if (sel->hasTag()) { - const AtomicString& selLocalName = sel->m_tag.localName(); - if (selLocalName != starAtom && selLocalName != e->localName()) - return false; - const AtomicString& selNS = sel->m_tag.namespaceURI(); - if (selNS != starAtom && selNS != e->namespaceURI()) - return false; - } - - if (sel->hasAttribute()) { - if (sel->m_match == CSSSelector::Class) - return e->hasClass() && static_cast<StyledElement*>(e)->classNames().contains(sel->m_value); - - if (sel->m_match == CSSSelector::Id) - return e->hasID() && e->getIDAttribute() == sel->m_value; - - // FIXME: Handle the case were elementStyle is 0. - if (elementStyle && (!e->isStyledElement() || (!static_cast<StyledElement*>(e)->isMappedAttribute(sel->m_attr) && sel->m_attr != typeAttr && sel->m_attr != readonlyAttr))) { - elementStyle->setAffectedByAttributeSelectors(); // Special-case the "type" and "readonly" attributes so input form controls can share style. - if (selectorAttrs) - selectorAttrs->add(sel->m_attr.localName().impl()); - } - - const AtomicString& value = e->getAttribute(sel->m_attr); - if (value.isNull()) - return false; // attribute is not set - - bool caseSensitive = !m_documentIsHTML || !htmlAttributeHasCaseInsensitiveValue(sel->m_attr); - - switch (sel->m_match) { - case CSSSelector::Exact: - if (caseSensitive ? sel->m_value != value : !equalIgnoringCase(sel->m_value, value)) - return false; - break; - case CSSSelector::List: - { - // Ignore empty selectors or selectors containing spaces - if (sel->m_value.contains(' ') || sel->m_value.isEmpty()) - return false; - - int startSearchAt = 0; - while (true) { - int foundPos = value.find(sel->m_value, startSearchAt, caseSensitive); - if (foundPos == -1) - return false; - if (foundPos == 0 || value[foundPos-1] == ' ') { - unsigned endStr = foundPos + sel->m_value.length(); - if (endStr == value.length() || value[endStr] == ' ') - break; // We found a match. - } - - // No match. Keep looking. - startSearchAt = foundPos + 1; - } - break; - } - case CSSSelector::Contain: - if (!value.contains(sel->m_value, caseSensitive) || sel->m_value.isEmpty()) - return false; - break; - case CSSSelector::Begin: - if (!value.startsWith(sel->m_value, caseSensitive) || sel->m_value.isEmpty()) - return false; - break; - case CSSSelector::End: - if (!value.endsWith(sel->m_value, caseSensitive) || sel->m_value.isEmpty()) - return false; - break; - case CSSSelector::Hyphen: - if (value.length() < sel->m_value.length()) - return false; - if (!value.startsWith(sel->m_value, caseSensitive)) - return false; - // It they start the same, check for exact match or following '-': - if (value.length() != sel->m_value.length() && value[sel->m_value.length()] != '-') - return false; - break; - case CSSSelector::PseudoClass: - case CSSSelector::PseudoElement: - default: - break; - } - } - if (sel->m_match == CSSSelector::PseudoClass) { - switch (sel->pseudoType()) { - // Pseudo classes: - case CSSSelector::PseudoEmpty: { - bool result = true; - for (Node* n = e->firstChild(); n; n = n->nextSibling()) { - if (n->isElementNode()) { - result = false; - break; - } else if (n->isTextNode()) { - Text* textNode = static_cast<Text*>(n); - if (!textNode->data().isEmpty()) { - result = false; - break; - } - } - } - if (!m_collectRulesOnly) { - if (elementStyle) - elementStyle->setEmptyState(result); - else if (e->renderStyle() && (e->document()->usesSiblingRules() || e->renderStyle()->unique())) - e->renderStyle()->setEmptyState(result); - } - return result; - } - case CSSSelector::PseudoFirstChild: { - // first-child matches the first child that is an element - if (e->parentNode() && e->parentNode()->isElementNode()) { - bool result = false; - Node* n = e->previousSibling(); - while (n && !n->isElementNode()) - n = n->previousSibling(); - if (!n) - result = true; - if (!m_collectRulesOnly) { - RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle(); - RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle(); - if (parentStyle) - parentStyle->setChildrenAffectedByFirstChildRules(); - if (result && childStyle) - childStyle->setFirstChildState(); - } - return result; - } - break; - } - case CSSSelector::PseudoFirstOfType: { - // first-of-type matches the first element of its type - if (e->parentNode() && e->parentNode()->isElementNode()) { - bool result = false; - const QualifiedName& type = e->tagQName(); - Node* n = e->previousSibling(); - while (n) { - if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type)) - break; - n = n->previousSibling(); - } - if (!n) - result = true; - if (!m_collectRulesOnly) { - RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle(); - if (parentStyle) - parentStyle->setChildrenAffectedByForwardPositionalRules(); - } - return result; - } - break; - } - case CSSSelector::PseudoLastChild: { - // last-child matches the last child that is an element - if (e->parentNode() && e->parentNode()->isElementNode()) { - Element* parentNode = static_cast<Element*>(e->parentNode()); - bool result = false; - if (parentNode->isFinishedParsingChildren()) { - Node* n = e->nextSibling(); - while (n && !n->isElementNode()) - n = n->nextSibling(); - if (!n) - result = true; - } - if (!m_collectRulesOnly) { - RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle(); - RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentNode->renderStyle(); - if (parentStyle) - parentStyle->setChildrenAffectedByLastChildRules(); - if (result && childStyle) - childStyle->setLastChildState(); - } - return result; - } - break; - } - case CSSSelector::PseudoLastOfType: { - // last-of-type matches the last element of its type - if (e->parentNode() && e->parentNode()->isElementNode()) { - Element* parentNode = static_cast<Element*>(e->parentNode()); - if (!m_collectRulesOnly) { - RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentNode->renderStyle(); - if (parentStyle) - parentStyle->setChildrenAffectedByBackwardPositionalRules(); - } - if (!parentNode->isFinishedParsingChildren()) - return false; - bool result = false; - const QualifiedName& type = e->tagQName(); - Node* n = e->nextSibling(); - while (n) { - if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type)) - break; - n = n->nextSibling(); - } - if (!n) - result = true; - return result; - } - break; - } - case CSSSelector::PseudoOnlyChild: { - if (e->parentNode() && e->parentNode()->isElementNode()) { - Element* parentNode = static_cast<Element*>(e->parentNode()); - bool firstChild = false; - bool lastChild = false; - - Node* n = e->previousSibling(); - while (n && !n->isElementNode()) - n = n->previousSibling(); - if (!n) - firstChild = true; - if (firstChild && parentNode->isFinishedParsingChildren()) { - n = e->nextSibling(); - while (n && !n->isElementNode()) - n = n->nextSibling(); - if (!n) - lastChild = true; - } - if (!m_collectRulesOnly) { - RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle(); - RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentNode->renderStyle(); - if (parentStyle) { - parentStyle->setChildrenAffectedByFirstChildRules(); - parentStyle->setChildrenAffectedByLastChildRules(); - } - if (firstChild && childStyle) - childStyle->setFirstChildState(); - if (lastChild && childStyle) - childStyle->setLastChildState(); - } - return firstChild && lastChild; - } - break; - } - case CSSSelector::PseudoOnlyOfType: { - // FIXME: This selector is very slow. - if (e->parentNode() && e->parentNode()->isElementNode()) { - Element* parentNode = static_cast<Element*>(e->parentNode()); - if (!m_collectRulesOnly) { - RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentNode->renderStyle(); - if (parentStyle) { - parentStyle->setChildrenAffectedByForwardPositionalRules(); - parentStyle->setChildrenAffectedByBackwardPositionalRules(); - } - } - if (!parentNode->isFinishedParsingChildren()) - return false; - bool firstChild = false; - bool lastChild = false; - const QualifiedName& type = e->tagQName(); - Node* n = e->previousSibling(); - while (n) { - if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type)) - break; - n = n->previousSibling(); - } - if (!n) - firstChild = true; - if (firstChild) { - n = e->nextSibling(); - while (n) { - if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type)) - break; - n = n->nextSibling(); - } - if (!n) - lastChild = true; - } - return firstChild && lastChild; - } - break; - } - case CSSSelector::PseudoNthChild: { - int a, b; - // calculate a and b every time we run through checkOneSelector - // this should probably be saved after we calculate it once, but currently - // would require increasing the size of CSSSelector - if (!parseNth(sel->m_argument, a, b)) - break; - if (e->parentNode() && e->parentNode()->isElementNode()) { - int count = 1; - Node* n = e->previousSibling(); - while (n) { - if (n->isElementNode()) { - RenderStyle* s = n->renderStyle(); - unsigned index = s ? s->childIndex() : 0; - if (index) { - count += index; - break; - } - count++; - } - n = n->previousSibling(); - } - - if (!m_collectRulesOnly) { - RenderStyle* childStyle = elementStyle ? elementStyle : e->renderStyle(); - RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle(); - if (childStyle) - childStyle->setChildIndex(count); - if (parentStyle) - parentStyle->setChildrenAffectedByForwardPositionalRules(); - } - - if (matchNth(count, a, b)) - return true; - } - break; - } - case CSSSelector::PseudoNthOfType: { - // FIXME: This selector is very slow. - int a, b; - // calculate a and b every time we run through checkOneSelector (see above) - if (!parseNth(sel->m_argument, a, b)) - break; - if (e->parentNode() && e->parentNode()->isElementNode()) { - int count = 1; - const QualifiedName& type = e->tagQName(); - Node* n = e->previousSibling(); - while (n) { - if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type)) - count++; - n = n->previousSibling(); - } - - if (!m_collectRulesOnly) { - RenderStyle* parentStyle = elementStyle ? elementParentStyle : e->parentNode()->renderStyle(); - if (parentStyle) - parentStyle->setChildrenAffectedByForwardPositionalRules(); - } - - if (matchNth(count, a, b)) - return true; - } - break; - } - case CSSSelector::PseudoNthLastChild: { - int a, b; - // calculate a and b every time we run through checkOneSelector - // this should probably be saved after we calculate it once, but currently - // would require increasing the size of CSSSelector - if (!parseNth(sel->m_argument, a, b)) - break; - if (e->parentNode() && e->parentNode()->isElementNode()) { - Element* parentNode = static_cast<Element*>(e->parentNode()); - if (!m_collectRulesOnly) { - RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentNode->renderStyle(); - if (parentStyle) - parentStyle->setChildrenAffectedByBackwardPositionalRules(); - } - if (!parentNode->isFinishedParsingChildren()) - return false; - int count = 1; - Node* n = e->nextSibling(); - while (n) { - if (n->isElementNode()) - count++; - n = n->nextSibling(); - } - if (matchNth(count, a, b)) - return true; - } - break; - } - case CSSSelector::PseudoNthLastOfType: { - // FIXME: This selector is very slow. - int a, b; - // calculate a and b every time we run through checkOneSelector (see above) - if (!parseNth(sel->m_argument, a, b)) - break; - if (e->parentNode() && e->parentNode()->isElementNode()) { - Element* parentNode = static_cast<Element*>(e->parentNode()); - if (!m_collectRulesOnly) { - RenderStyle* parentStyle = elementStyle ? elementParentStyle : parentNode->renderStyle(); - if (parentStyle) - parentStyle->setChildrenAffectedByBackwardPositionalRules(); - } - if (!parentNode->isFinishedParsingChildren()) - return false; - int count = 1; - const QualifiedName& type = e->tagQName(); - Node* n = e->nextSibling(); - while (n) { - if (n->isElementNode() && static_cast<Element*>(n)->hasTagName(type)) - count++; - n = n->nextSibling(); - } - if (matchNth(count, a, b)) - return true; - } - break; - } - case CSSSelector::PseudoTarget: - if (e == e->document()->getCSSTarget()) - return true; - break; - case CSSSelector::PseudoAnyLink: - if (pseudoState == PseudoUnknown) - pseudoState = checkPseudoState(e, false); - if (pseudoState == PseudoAnyLink || pseudoState == PseudoLink || pseudoState == PseudoVisited) - return true; - break; - case CSSSelector::PseudoAutofill: - if (e && e->hasTagName(inputTag)) - return static_cast<HTMLInputElement*>(e)->autofilled(); - break; - case CSSSelector::PseudoLink: - if (pseudoState == PseudoUnknown || pseudoState == PseudoAnyLink) - pseudoState = checkPseudoState(e); - if (pseudoState == PseudoLink) - return true; - break; - case CSSSelector::PseudoVisited: - if (pseudoState == PseudoUnknown || pseudoState == PseudoAnyLink) - pseudoState = checkPseudoState(e); - if (pseudoState == PseudoVisited) - return true; - break; - case CSSSelector::PseudoDrag: { - if (elementStyle) - elementStyle->setAffectedByDragRules(true); - else if (e->renderStyle()) - e->renderStyle()->setAffectedByDragRules(true); - if (e->renderer() && e->renderer()->isDragging()) - return true; - break; - } - case CSSSelector::PseudoFocus: - if (e && e->focused() && e->document()->frame()->selection()->isFocusedAndActive()) - return true; - break; - case CSSSelector::PseudoHover: { - // If we're in quirks mode, then hover should never match anchors with no - // href and *:hover should not match anything. This is important for sites like wsj.com. - if (m_strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) { - if (elementStyle) - elementStyle->setAffectedByHoverRules(true); - else if (e->renderStyle()) - e->renderStyle()->setAffectedByHoverRules(true); - if (e->hovered()) - return true; - } - break; - } - case CSSSelector::PseudoActive: - // If we're in quirks mode, then :active should never match anchors with no - // href and *:active should not match anything. - if (m_strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) { - if (elementStyle) - elementStyle->setAffectedByActiveRules(true); - else if (e->renderStyle()) - e->renderStyle()->setAffectedByActiveRules(true); - if (e->active()) - return true; - } - break; - case CSSSelector::PseudoEnabled: - if (e && e->isControl() && !e->isInputTypeHidden()) - // The UI spec states that you can't match :enabled unless you are an object that can - // "receive focus and be activated." We will limit matching of this pseudo-class to elements - // that are non-"hidden" controls. - return e->isEnabled(); - break; - case CSSSelector::PseudoFullPageMedia: - return e && e->document() && e->document()->isMediaDocument(); - break; - case CSSSelector::PseudoDisabled: - if (e && e->isControl() && !e->isInputTypeHidden()) - // The UI spec states that you can't match :enabled unless you are an object that can - // "receive focus and be activated." We will limit matching of this pseudo-class to elements - // that are non-"hidden" controls. - return !e->isEnabled(); - break; - case CSSSelector::PseudoReadOnly: - return e && e->isTextControl() && e->isReadOnlyControl(); - case CSSSelector::PseudoReadWrite: - return e && e->isTextControl() && !e->isReadOnlyControl(); - case CSSSelector::PseudoChecked: - // Even though WinIE allows checked and indeterminate to co-exist, the CSS selector spec says that - // you can't be both checked and indeterminate. We will behave like WinIE behind the scenes and just - // obey the CSS spec here in the test for matching the pseudo. - if (e && e->isChecked() && !e->isIndeterminate()) - return true; - break; - case CSSSelector::PseudoIndeterminate: - if (e && e->isIndeterminate()) - return true; - break; - case CSSSelector::PseudoRoot: - if (e == e->document()->documentElement()) - return true; - break; - case CSSSelector::PseudoLang: { - Node* n = e; - AtomicString value; - // The language property is inherited, so we iterate over the parents - // to find the first language. - while (n && value.isEmpty()) { - if (n->isElementNode()) { - // Spec: xml:lang takes precedence -- http://www.w3.org/TR/xhtml1/#C_7 - value = static_cast<Element*>(n)->getAttribute(XMLNames::langAttr); - if (value.isEmpty()) - value = static_cast<Element*>(n)->getAttribute(langAttr); - } else if (n->isDocumentNode()) - // checking the MIME content-language - value = static_cast<Document*>(n)->contentLanguage(); - - n = n->parent(); - } - if (value.isEmpty() || !value.startsWith(sel->m_argument, false)) - break; - if (value.length() != sel->m_argument.length() && value[sel->m_argument.length()] != '-') - break; - return true; - } - case CSSSelector::PseudoNot: { - // check the simple selector - for (CSSSelector* subSel = sel->m_simpleSelector; subSel; subSel = subSel->m_tagHistory) { - // :not cannot nest. I don't really know why this is a - // restriction in CSS3, but it is, so let's honour it. - if (subSel->m_simpleSelector) - break; - if (!checkOneSelector(subSel, e, selectorAttrs, dynamicPseudo, isAncestor, true, elementStyle, elementParentStyle)) - return true; - } - break; - } - case CSSSelector::PseudoUnknown: - case CSSSelector::PseudoNotParsed: - default: - ASSERT_NOT_REACHED(); - break; - } - return false; - } - if (sel->m_match == CSSSelector::PseudoElement) { - if (!elementStyle) - return false; - - switch (sel->pseudoType()) { - // Pseudo-elements: - case CSSSelector::PseudoFirstLine: - dynamicPseudo = RenderStyle::FIRST_LINE; - return true; - case CSSSelector::PseudoFirstLetter: - dynamicPseudo = RenderStyle::FIRST_LETTER; - if (Document* doc = e->document()) - doc->setUsesFirstLetterRules(true); - return true; - case CSSSelector::PseudoSelection: - dynamicPseudo = RenderStyle::SELECTION; - return true; - case CSSSelector::PseudoBefore: - dynamicPseudo = RenderStyle::BEFORE; - return true; - case CSSSelector::PseudoAfter: - dynamicPseudo = RenderStyle::AFTER; - return true; - case CSSSelector::PseudoFileUploadButton: - dynamicPseudo = RenderStyle::FILE_UPLOAD_BUTTON; - return true; - case CSSSelector::PseudoSliderThumb: - dynamicPseudo = RenderStyle::SLIDER_THUMB; - return true; - case CSSSelector::PseudoSearchCancelButton: - dynamicPseudo = RenderStyle::SEARCH_CANCEL_BUTTON; - return true; - case CSSSelector::PseudoSearchDecoration: - dynamicPseudo = RenderStyle::SEARCH_DECORATION; - return true; - case CSSSelector::PseudoSearchResultsDecoration: - dynamicPseudo = RenderStyle::SEARCH_RESULTS_DECORATION; - return true; - case CSSSelector::PseudoSearchResultsButton: - dynamicPseudo = RenderStyle::SEARCH_RESULTS_BUTTON; - return true; - case CSSSelector::PseudoMediaControlsPanel: - dynamicPseudo = RenderStyle::MEDIA_CONTROLS_PANEL; - return true; - case CSSSelector::PseudoMediaControlsMuteButton: - dynamicPseudo = RenderStyle::MEDIA_CONTROLS_MUTE_BUTTON; - return true; - case CSSSelector::PseudoMediaControlsPlayButton: - dynamicPseudo = RenderStyle::MEDIA_CONTROLS_PLAY_BUTTON; - return true; - case CSSSelector::PseudoMediaControlsTimeDisplay: - dynamicPseudo = RenderStyle::MEDIA_CONTROLS_TIME_DISPLAY; - return true; - case CSSSelector::PseudoMediaControlsTimeline: - dynamicPseudo = RenderStyle::MEDIA_CONTROLS_TIMELINE; - return true; - case CSSSelector::PseudoMediaControlsSeekBackButton: - dynamicPseudo = RenderStyle::MEDIA_CONTROLS_SEEK_BACK_BUTTON; - return true; - case CSSSelector::PseudoMediaControlsSeekForwardButton: - dynamicPseudo = RenderStyle::MEDIA_CONTROLS_SEEK_FORWARD_BUTTON; - return true; - case CSSSelector::PseudoMediaControlsFullscreenButton: - dynamicPseudo = RenderStyle::MEDIA_CONTROLS_FULLSCREEN_BUTTON; - return true; - case CSSSelector::PseudoUnknown: - case CSSSelector::PseudoNotParsed: - default: - ASSERT_NOT_REACHED(); - break; - } - return false; - } - // ### add the rest of the checks... - return true; -} - -void CSSStyleSelector::addVariables(CSSVariablesRule* variables) -{ - CSSVariablesDeclaration* decl = variables->variables(); - if (!decl) - return; - unsigned size = decl->length(); - for (unsigned i = 0; i < size; ++i) { - String name = decl->item(i); - m_variablesMap.set(name, variables); - } -} - -CSSValue* CSSStyleSelector::resolveVariableDependentValue(CSSVariableDependentValue* val) -{ - return 0; -} - -// ----------------------------------------------------------------- - -CSSRuleSet::CSSRuleSet() -{ - m_universalRules = 0; - m_ruleCount = 0; -} - -CSSRuleSet::~CSSRuleSet() -{ - deleteAllValues(m_idRules); - deleteAllValues(m_classRules); - deleteAllValues(m_tagRules); - - delete m_universalRules; -} - - -void CSSRuleSet::addToRuleSet(AtomicStringImpl* key, AtomRuleMap& map, - CSSStyleRule* rule, CSSSelector* sel) -{ - if (!key) return; - CSSRuleDataList* rules = map.get(key); - if (!rules) { - rules = new CSSRuleDataList(m_ruleCount++, rule, sel); - map.set(key, rules); - } else - rules->append(m_ruleCount++, rule, sel); -} - -void CSSRuleSet::addRule(CSSStyleRule* rule, CSSSelector* sel) -{ - if (sel->m_match == CSSSelector::Id) { - addToRuleSet(sel->m_value.impl(), m_idRules, rule, sel); - return; - } - if (sel->m_match == CSSSelector::Class) { - addToRuleSet(sel->m_value.impl(), m_classRules, rule, sel); - return; - } - - const AtomicString& localName = sel->m_tag.localName(); - if (localName != starAtom) { - addToRuleSet(localName.impl(), m_tagRules, rule, sel); - return; - } - - // Just put it in the universal rule set. - if (!m_universalRules) - m_universalRules = new CSSRuleDataList(m_ruleCount++, rule, sel); - else - m_universalRules->append(m_ruleCount++, rule, sel); -} - -void CSSRuleSet::addRulesFromSheet(CSSStyleSheet* sheet, const MediaQueryEvaluator& medium, CSSStyleSelector* styleSelector) -{ - if (!sheet) - return; - - // No media implies "all", but if a media list exists it must - // contain our current medium - if (sheet->media() && !medium.eval(sheet->media(), styleSelector)) - return; // the style sheet doesn't apply - - int len = sheet->length(); - - for (int i = 0; i < len; i++) { - StyleBase* item = sheet->item(i); - if (item->isStyleRule()) { - CSSStyleRule* rule = static_cast<CSSStyleRule*>(item); - for (CSSSelector* s = rule->selector(); s; s = s->next()) - addRule(rule, s); - } - else if (item->isImportRule()) { - CSSImportRule* import = static_cast<CSSImportRule*>(item); - if (!import->media() || medium.eval(import->media(), styleSelector)) - addRulesFromSheet(import->styleSheet(), medium, styleSelector); - } - else if (item->isMediaRule()) { - CSSMediaRule* r = static_cast<CSSMediaRule*>(item); - CSSRuleList* rules = r->cssRules(); - - if ((!r->media() || medium.eval(r->media(), styleSelector)) && rules) { - // Traverse child elements of the @media rule. - for (unsigned j = 0; j < rules->length(); j++) { - CSSRule *childItem = rules->item(j); - if (childItem->isStyleRule()) { - // It is a StyleRule, so append it to our list - CSSStyleRule* rule = static_cast<CSSStyleRule*>(childItem); - for (CSSSelector* s = rule->selector(); s; s = s->next()) - addRule(rule, s); - } else if (childItem->isFontFaceRule() && styleSelector) { - // Add this font face to our set. - const CSSFontFaceRule* fontFaceRule = static_cast<CSSFontFaceRule*>(childItem); - styleSelector->fontSelector()->addFontFaceRule(fontFaceRule); - } else if (childItem->isKeyframesRule() && styleSelector) { - // Add this keyframe rule to our set. - const WebKitCSSKeyframesRule* keyframesRule = static_cast<WebKitCSSKeyframesRule*>(childItem); - styleSelector->addKeyframeStyle(sheet->doc(), keyframesRule); - } - } // for rules - } // if rules - } else if (item->isFontFaceRule() && styleSelector) { - // Add this font face to our set. - const CSSFontFaceRule* fontFaceRule = static_cast<CSSFontFaceRule*>(item); - styleSelector->fontSelector()->addFontFaceRule(fontFaceRule); - } else if (item->isVariablesRule()) { - // Evaluate the media query and make sure it matches. - CSSVariablesRule* variables = static_cast<CSSVariablesRule*>(item); - if (!variables->media() || medium.eval(variables->media(), styleSelector)) - styleSelector->addVariables(variables); - } else if (item->isKeyframesRule()) { - WebKitCSSKeyframesRule* r = static_cast<WebKitCSSKeyframesRule*>(item); - styleSelector->addKeyframeStyle(sheet->doc(), r); - } - } -} - -// ------------------------------------------------------------------------------------- -// this is mostly boring stuff on how to apply a certain rule to the renderstyle... - -static Length convertToLength(CSSPrimitiveValue *primitiveValue, RenderStyle *style, bool *ok = 0) -{ - Length l; - if (!primitiveValue) { - if (ok) - *ok = false; - } else { - int type = primitiveValue->primitiveType(); - if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) - l = Length(primitiveValue->computeLengthIntForLength(style), Fixed); - else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) - l = Length(primitiveValue->getDoubleValue(), Percent); - else if (type == CSSPrimitiveValue::CSS_NUMBER) - l = Length(primitiveValue->getDoubleValue() * 100.0, Percent); - else if (ok) - *ok = false; - } - return l; -} - -void CSSStyleSelector::applyDeclarations(bool applyFirst, bool isImportant, - int startIndex, int endIndex) -{ - if (startIndex == -1) - return; - - for (int i = startIndex; i <= endIndex; i++) { - CSSMutableStyleDeclaration* decl = m_matchedDecls[i]; - DeprecatedValueListConstIterator<CSSProperty> end; - for (DeprecatedValueListConstIterator<CSSProperty> it = decl->valuesIterator(); it != end; ++it) { - const CSSProperty& current = *it; - // give special priority to font-xxx, color properties - if (isImportant == current.isImportant()) { - bool first; - switch (current.id()) { - case CSSPropertyLineHeight: - m_lineHeightValue = current.value(); - first = !applyFirst; // we apply line-height later - break; - case CSSPropertyColor: - case CSSPropertyDirection: - case CSSPropertyDisplay: - case CSSPropertyFont: - case CSSPropertyFontSize: - case CSSPropertyFontStyle: - case CSSPropertyFontFamily: - case CSSPropertyFontWeight: - case CSSPropertyWebkitTextSizeAdjust: - case CSSPropertyFontVariant: - case CSSPropertyZoom: - // these have to be applied first, because other properties use the computed - // values of these porperties. - first = true; - break; - default: - first = false; - break; - } - if (first == applyFirst) - applyProperty(current.id(), current.value()); - } - } - } -} - -static void applyCounterList(RenderStyle* style, CSSValueList* list, bool isReset) -{ - CounterDirectiveMap& map = style->accessCounterDirectives(); - typedef CounterDirectiveMap::iterator Iterator; - - Iterator end = map.end(); - for (Iterator it = map.begin(); it != end; ++it) - if (isReset) - it->second.m_reset = false; - else - it->second.m_increment = false; - - int length = list ? list->length() : 0; - for (int i = 0; i < length; ++i) { - Pair* pair = static_cast<CSSPrimitiveValue*>(list->itemWithoutBoundsCheck(i))->getPairValue(); - AtomicString identifier = static_cast<CSSPrimitiveValue*>(pair->first())->getStringValue(); - // FIXME: What about overflow? - int value = static_cast<CSSPrimitiveValue*>(pair->second())->getIntValue(); - CounterDirectives& directives = map.add(identifier.impl(), CounterDirectives()).first->second; - if (isReset) { - directives.m_reset = true; - directives.m_resetValue = value; - } else { - if (directives.m_increment) - directives.m_incrementValue += value; - else { - directives.m_increment = true; - directives.m_incrementValue = value; - } - } - } -} - -struct ScriptFamilyState { - bool isGenericAdded; - bool isPerScriptGenericChecked; - ScriptFamilyState() : isGenericAdded(false), isPerScriptGenericChecked(false) - {} -}; - -inline static void handleScriptFamily(const char* webkitFamily, UScriptCode script, - FontDescription::GenericFamilyType generic, - AtomicString& face, ScriptFamilyState& state, FontDescription& fontDescription, - int& familyIndex) -{ - if (!state.isGenericAdded) { - face = webkitFamily; - state.isGenericAdded = true; - fontDescription.setGenericFamily(generic); - // go through this once more to add per-script generic family. - --familyIndex; - } else if (!state.isPerScriptGenericChecked) { - face = FontCache::getGenericFontForScript(script, fontDescription); - state.isPerScriptGenericChecked = true; - } -} - -void CSSStyleSelector::applyPropertyToStyle(int id, CSSValue *value, RenderStyle* style) -{ - initElementAndPseudoState(0); - initForStyleResolve(0, style); - m_style = style; - applyProperty(id, value); -} - -void CSSStyleSelector::applyProperty(int id, CSSValue *value) -{ - CSSPrimitiveValue* primitiveValue = 0; - if (value->isPrimitiveValue()) - primitiveValue = static_cast<CSSPrimitiveValue*>(value); - - float zoomFactor = m_style->effectiveZoom(); - - Length l; - bool apply = false; - - unsigned short valueType = value->cssValueType(); - - bool isInherit = m_parentNode && valueType == CSSValue::CSS_INHERIT; - bool isInitial = valueType == CSSValue::CSS_INITIAL || (!m_parentNode && valueType == CSSValue::CSS_INHERIT); - - // These properties are used to set the correct margins/padding on RTL lists. - if (id == CSSPropertyWebkitMarginStart) - id = m_style->direction() == LTR ? CSSPropertyMarginLeft : CSSPropertyMarginRight; - else if (id == CSSPropertyWebkitPaddingStart) - id = m_style->direction() == LTR ? CSSPropertyPaddingLeft : CSSPropertyPaddingRight; - - // What follows is a list that maps the CSS properties into their corresponding front-end - // RenderStyle values. Shorthands (e.g. border, background) occur in this list as well and - // are only hit when mapping "inherit" or "initial" into front-end values. - switch (static_cast<CSSPropertyID>(id)) { -// ident only properties - case CSSPropertyBackgroundAttachment: - HANDLE_BACKGROUND_VALUE(attachment, Attachment, value) - return; - case CSSPropertyWebkitBackgroundClip: - HANDLE_BACKGROUND_VALUE(clip, Clip, value) - return; - case CSSPropertyWebkitBackgroundComposite: - HANDLE_BACKGROUND_VALUE(composite, Composite, value) - return; - case CSSPropertyWebkitBackgroundOrigin: - HANDLE_BACKGROUND_VALUE(origin, Origin, value) - return; - case CSSPropertyBackgroundRepeat: - HANDLE_BACKGROUND_VALUE(repeat, Repeat, value) - return; - case CSSPropertyWebkitBackgroundSize: - HANDLE_BACKGROUND_VALUE(size, Size, value) - return; - case CSSPropertyWebkitMaskAttachment: - HANDLE_MASK_VALUE(attachment, Attachment, value) - return; - case CSSPropertyWebkitMaskClip: - HANDLE_MASK_VALUE(clip, Clip, value) - return; - case CSSPropertyWebkitMaskComposite: - HANDLE_MASK_VALUE(composite, Composite, value) - return; - case CSSPropertyWebkitMaskOrigin: - HANDLE_MASK_VALUE(origin, Origin, value) - return; - case CSSPropertyWebkitMaskRepeat: - HANDLE_MASK_VALUE(repeat, Repeat, value) - return; - case CSSPropertyWebkitMaskSize: - HANDLE_MASK_VALUE(size, Size, value) - return; - case CSSPropertyBorderCollapse: - HANDLE_INHERIT_AND_INITIAL(borderCollapse, BorderCollapse) - if (!primitiveValue) - return; - switch (primitiveValue->getIdent()) { - case CSSValueCollapse: - m_style->setBorderCollapse(true); - break; - case CSSValueSeparate: - m_style->setBorderCollapse(false); - break; - default: - return; - } - return; - - case CSSPropertyBorderTopStyle: - HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderTopStyle, BorderTopStyle, BorderStyle) - if (primitiveValue) - m_style->setBorderTopStyle(*primitiveValue); - return; - case CSSPropertyBorderRightStyle: - HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderRightStyle, BorderRightStyle, BorderStyle) - if (primitiveValue) - m_style->setBorderRightStyle(*primitiveValue); - return; - case CSSPropertyBorderBottomStyle: - HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderBottomStyle, BorderBottomStyle, BorderStyle) - if (primitiveValue) - m_style->setBorderBottomStyle(*primitiveValue); - return; - case CSSPropertyBorderLeftStyle: - HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(borderLeftStyle, BorderLeftStyle, BorderStyle) - if (primitiveValue) - m_style->setBorderLeftStyle(*primitiveValue); - return; - case CSSPropertyOutlineStyle: - HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(outlineStyle, OutlineStyle, BorderStyle) - if (primitiveValue) { - if (primitiveValue->getIdent() == CSSValueAuto) - m_style->setOutlineStyle(DOTTED, true); - else - m_style->setOutlineStyle(*primitiveValue); - } - return; - case CSSPropertyCaptionSide: - { - HANDLE_INHERIT_AND_INITIAL(captionSide, CaptionSide) - if (primitiveValue) - m_style->setCaptionSide(*primitiveValue); - return; - } - case CSSPropertyClear: - { - HANDLE_INHERIT_AND_INITIAL(clear, Clear) - if (primitiveValue) - m_style->setClear(*primitiveValue); - return; - } - case CSSPropertyDirection: - { - HANDLE_INHERIT_AND_INITIAL(direction, Direction) - if (primitiveValue) - m_style->setDirection(*primitiveValue); - return; - } - case CSSPropertyDisplay: - { - HANDLE_INHERIT_AND_INITIAL(display, Display) - if (primitiveValue) - m_style->setDisplay(*primitiveValue); - return; - } - - case CSSPropertyEmptyCells: - { - HANDLE_INHERIT_AND_INITIAL(emptyCells, EmptyCells) - if (primitiveValue) - m_style->setEmptyCells(*primitiveValue); - return; - } - case CSSPropertyFloat: - { - HANDLE_INHERIT_AND_INITIAL(floating, Floating) - if (primitiveValue) - m_style->setFloating(*primitiveValue); - return; - } - - case CSSPropertyFontStyle: - { - FontDescription fontDescription = m_style->fontDescription(); - if (isInherit) - fontDescription.setItalic(m_parentStyle->fontDescription().italic()); - else if (isInitial) - fontDescription.setItalic(false); - else { - if (!primitiveValue) - return; - switch (primitiveValue->getIdent()) { - case CSSValueOblique: - // FIXME: oblique is the same as italic for the moment... - case CSSValueItalic: - fontDescription.setItalic(true); - break; - case CSSValueNormal: - fontDescription.setItalic(false); - break; - default: - return; - } - } - if (m_style->setFontDescription(fontDescription)) - m_fontDirty = true; - return; - } - - case CSSPropertyFontVariant: - { - FontDescription fontDescription = m_style->fontDescription(); - if (isInherit) - fontDescription.setSmallCaps(m_parentStyle->fontDescription().smallCaps()); - else if (isInitial) - fontDescription.setSmallCaps(false); - else { - if (!primitiveValue) - return; - int id = primitiveValue->getIdent(); - if (id == CSSValueNormal) - fontDescription.setSmallCaps(false); - else if (id == CSSValueSmallCaps) - fontDescription.setSmallCaps(true); - else - return; - } - if (m_style->setFontDescription(fontDescription)) - m_fontDirty = true; - return; - } - - case CSSPropertyFontWeight: - { - FontDescription fontDescription = m_style->fontDescription(); - if (isInherit) - fontDescription.setWeight(m_parentStyle->fontDescription().weight()); - else if (isInitial) - fontDescription.setWeight(FontWeightNormal); - else { - if (!primitiveValue) - return; - if (primitiveValue->getIdent()) { - switch (primitiveValue->getIdent()) { - case CSSValueBolder: - fontDescription.setWeight(fontDescription.bolderWeight()); - break; - case CSSValueLighter: - fontDescription.setWeight(fontDescription.lighterWeight()); - break; - case CSSValueBold: - case CSSValue700: - fontDescription.setWeight(FontWeightBold); - break; - case CSSValueNormal: - case CSSValue400: - fontDescription.setWeight(FontWeightNormal); - break; - case CSSValue900: - fontDescription.setWeight(FontWeight900); - break; - case CSSValue800: - fontDescription.setWeight(FontWeight800); - break; - case CSSValue600: - fontDescription.setWeight(FontWeight600); - break; - case CSSValue500: - fontDescription.setWeight(FontWeight500); - break; - case CSSValue300: - fontDescription.setWeight(FontWeight300); - break; - case CSSValue200: - fontDescription.setWeight(FontWeight200); - break; - case CSSValue100: - fontDescription.setWeight(FontWeight100); - break; - default: - return; - } - } else - ASSERT_NOT_REACHED(); - } - if (m_style->setFontDescription(fontDescription)) - m_fontDirty = true; - return; - } - - case CSSPropertyListStylePosition: - { - HANDLE_INHERIT_AND_INITIAL(listStylePosition, ListStylePosition) - if (primitiveValue) - m_style->setListStylePosition(*primitiveValue); - return; - } - - case CSSPropertyListStyleType: - { - HANDLE_INHERIT_AND_INITIAL(listStyleType, ListStyleType) - if (primitiveValue) - m_style->setListStyleType(*primitiveValue); - return; - } - - case CSSPropertyOverflow: - { - if (isInherit) { - m_style->setOverflowX(m_parentStyle->overflowX()); - m_style->setOverflowY(m_parentStyle->overflowY()); - return; - } - - if (isInitial) { - m_style->setOverflowX(RenderStyle::initialOverflowX()); - m_style->setOverflowY(RenderStyle::initialOverflowY()); - return; - } - - EOverflow o = *primitiveValue; - - m_style->setOverflowX(o); - m_style->setOverflowY(o); - return; - } - - case CSSPropertyOverflowX: - { - HANDLE_INHERIT_AND_INITIAL(overflowX, OverflowX) - m_style->setOverflowX(*primitiveValue); - return; - } - - case CSSPropertyOverflowY: - { - HANDLE_INHERIT_AND_INITIAL(overflowY, OverflowY) - m_style->setOverflowY(*primitiveValue); - return; - } - - case CSSPropertyPageBreakBefore: - { - HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakBefore, PageBreakBefore, PageBreak) - if (primitiveValue) - m_style->setPageBreakBefore(*primitiveValue); - return; - } - - case CSSPropertyPageBreakAfter: - { - HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakAfter, PageBreakAfter, PageBreak) - if (primitiveValue) - m_style->setPageBreakAfter(*primitiveValue); - return; - } - - case CSSPropertyPageBreakInside: { - HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(pageBreakInside, PageBreakInside, PageBreak) - if (!primitiveValue) - return; - EPageBreak pageBreak = *primitiveValue; - if (pageBreak != PBALWAYS) - m_style->setPageBreakInside(pageBreak); - return; - } - - case CSSPropertyPosition: - { - HANDLE_INHERIT_AND_INITIAL(position, Position) - if (primitiveValue) - m_style->setPosition(*primitiveValue); - return; - } - - case CSSPropertyTableLayout: { - HANDLE_INHERIT_AND_INITIAL(tableLayout, TableLayout) - - ETableLayout l = *primitiveValue; - if (l == TAUTO) - l = RenderStyle::initialTableLayout(); - - m_style->setTableLayout(l); - return; - } - - case CSSPropertyUnicodeBidi: { - HANDLE_INHERIT_AND_INITIAL(unicodeBidi, UnicodeBidi) - m_style->setUnicodeBidi(*primitiveValue); - return; - } - case CSSPropertyTextTransform: { - HANDLE_INHERIT_AND_INITIAL(textTransform, TextTransform) - m_style->setTextTransform(*primitiveValue); - return; - } - - case CSSPropertyVisibility: - { - HANDLE_INHERIT_AND_INITIAL(visibility, Visibility) - m_style->setVisibility(*primitiveValue); - return; - } - case CSSPropertyWhiteSpace: - HANDLE_INHERIT_AND_INITIAL(whiteSpace, WhiteSpace) - m_style->setWhiteSpace(*primitiveValue); - return; - - case CSSPropertyBackgroundPosition: - HANDLE_BACKGROUND_INHERIT_AND_INITIAL(xPosition, XPosition); - HANDLE_BACKGROUND_INHERIT_AND_INITIAL(yPosition, YPosition); - return; - case CSSPropertyBackgroundPositionX: { - HANDLE_BACKGROUND_VALUE(xPosition, XPosition, value) - return; - } - case CSSPropertyBackgroundPositionY: { - HANDLE_BACKGROUND_VALUE(yPosition, YPosition, value) - return; - } - case CSSPropertyWebkitMaskPosition: - HANDLE_MASK_INHERIT_AND_INITIAL(xPosition, XPosition); - HANDLE_MASK_INHERIT_AND_INITIAL(yPosition, YPosition); - return; - case CSSPropertyWebkitMaskPositionX: { - HANDLE_MASK_VALUE(xPosition, XPosition, value) - return; - } - case CSSPropertyWebkitMaskPositionY: { - HANDLE_MASK_VALUE(yPosition, YPosition, value) - return; - } - case CSSPropertyBorderSpacing: { - if (isInherit) { - m_style->setHorizontalBorderSpacing(m_parentStyle->horizontalBorderSpacing()); - m_style->setVerticalBorderSpacing(m_parentStyle->verticalBorderSpacing()); - } - else if (isInitial) { - m_style->setHorizontalBorderSpacing(0); - m_style->setVerticalBorderSpacing(0); - } - return; - } - case CSSPropertyWebkitBorderHorizontalSpacing: { - HANDLE_INHERIT_AND_INITIAL(horizontalBorderSpacing, HorizontalBorderSpacing) - if (!primitiveValue) - return; - short spacing = primitiveValue->computeLengthShort(m_style, zoomFactor); - m_style->setHorizontalBorderSpacing(spacing); - return; - } - case CSSPropertyWebkitBorderVerticalSpacing: { - HANDLE_INHERIT_AND_INITIAL(verticalBorderSpacing, VerticalBorderSpacing) - if (!primitiveValue) - return; - short spacing = primitiveValue->computeLengthShort(m_style, zoomFactor); - m_style->setVerticalBorderSpacing(spacing); - return; - } - case CSSPropertyCursor: - if (isInherit) { - m_style->setCursor(m_parentStyle->cursor()); - m_style->setCursorList(m_parentStyle->cursors()); - return; - } - m_style->clearCursorList(); - if (isInitial) { - m_style->setCursor(RenderStyle::initialCursor()); - return; - } - if (value->isValueList()) { - CSSValueList* list = static_cast<CSSValueList*>(value); - int len = list->length(); - m_style->setCursor(CURSOR_AUTO); - for (int i = 0; i < len; i++) { - CSSValue* item = list->itemWithoutBoundsCheck(i); - if (!item->isPrimitiveValue()) - continue; - primitiveValue = static_cast<CSSPrimitiveValue*>(item); - int type = primitiveValue->primitiveType(); - if (type == CSSPrimitiveValue::CSS_URI) { - CSSCursorImageValue* image = static_cast<CSSCursorImageValue*>(primitiveValue); - if (image->updateIfSVGCursorIsUsed(m_element)) // Elements with SVG cursors are not allowed to share style. - m_style->setUnique(); - // FIXME: Temporary clumsiness to pass off a CachedImage to an API that will eventually convert to using - // StyleImage. - RefPtr<StyleCachedImage> styleCachedImage(image->cachedImage(m_element->document()->docLoader())); - if (styleCachedImage) - m_style->addCursor(styleCachedImage->cachedImage(), image->hotspot()); - } else if (type == CSSPrimitiveValue::CSS_IDENT) - m_style->setCursor(*primitiveValue); - } - } else if (primitiveValue) { - int type = primitiveValue->primitiveType(); - if (type == CSSPrimitiveValue::CSS_IDENT) - m_style->setCursor(*primitiveValue); - } - return; -// colors || inherit - case CSSPropertyColor: - // If the 'currentColor' keyword is set on the 'color' property itself, - // it is treated as 'color:inherit' at parse time - if (primitiveValue && primitiveValue->getIdent() == CSSValueCurrentcolor) - isInherit = true; - case CSSPropertyBackgroundColor: - case CSSPropertyBorderTopColor: - case CSSPropertyBorderRightColor: - case CSSPropertyBorderBottomColor: - case CSSPropertyBorderLeftColor: - case CSSPropertyOutlineColor: - case CSSPropertyWebkitColumnRuleColor: - case CSSPropertyWebkitTextStrokeColor: - case CSSPropertyWebkitTextFillColor: { - Color col; - if (isInherit) { - HANDLE_INHERIT_COND(CSSPropertyBackgroundColor, backgroundColor, BackgroundColor) - HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyBorderTopColor, borderTopColor, color, BorderTopColor) - HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyBorderBottomColor, borderBottomColor, color, BorderBottomColor) - HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyBorderRightColor, borderRightColor, color, BorderRightColor) - HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyBorderLeftColor, borderLeftColor, color, BorderLeftColor) - HANDLE_INHERIT_COND(CSSPropertyColor, color, Color) - HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyOutlineColor, outlineColor, color, OutlineColor) - HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyWebkitColumnRuleColor, columnRuleColor, color, ColumnRuleColor) - HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyWebkitTextStrokeColor, textStrokeColor, color, TextStrokeColor) - HANDLE_INHERIT_COND_WITH_BACKUP(CSSPropertyWebkitTextFillColor, textFillColor, color, TextFillColor) - return; - } - if (isInitial) { - // The border/outline colors will just map to the invalid color |col| above. This will have the - // effect of forcing the use of the currentColor when it comes time to draw the borders (and of - // not painting the background since the color won't be valid). - if (id == CSSPropertyColor) - col = RenderStyle::initialColor(); - } else { - if (!primitiveValue) - return; - col = getColorFromPrimitiveValue(primitiveValue); - } - - switch (id) { - case CSSPropertyBackgroundColor: - m_style->setBackgroundColor(col); - break; - case CSSPropertyBorderTopColor: - m_style->setBorderTopColor(col); - break; - case CSSPropertyBorderRightColor: - m_style->setBorderRightColor(col); - break; - case CSSPropertyBorderBottomColor: - m_style->setBorderBottomColor(col); - break; - case CSSPropertyBorderLeftColor: - m_style->setBorderLeftColor(col); - break; - case CSSPropertyColor: - m_style->setColor(col); - break; - case CSSPropertyOutlineColor: - m_style->setOutlineColor(col); - break; - case CSSPropertyWebkitColumnRuleColor: - m_style->setColumnRuleColor(col); - break; - case CSSPropertyWebkitTextStrokeColor: - m_style->setTextStrokeColor(col); - break; - case CSSPropertyWebkitTextFillColor: - m_style->setTextFillColor(col); - break; - } - - return; - } - -// uri || inherit - case CSSPropertyBackgroundImage: - HANDLE_BACKGROUND_VALUE(image, Image, value) - return; - case CSSPropertyWebkitMaskImage: - HANDLE_MASK_VALUE(image, Image, value) - return; - case CSSPropertyListStyleImage: - { - HANDLE_INHERIT_AND_INITIAL(listStyleImage, ListStyleImage) - m_style->setListStyleImage(styleImage(value)); - return; - } - -// length - case CSSPropertyBorderTopWidth: - case CSSPropertyBorderRightWidth: - case CSSPropertyBorderBottomWidth: - case CSSPropertyBorderLeftWidth: - case CSSPropertyOutlineWidth: - case CSSPropertyWebkitColumnRuleWidth: - { - if (isInherit) { - HANDLE_INHERIT_COND(CSSPropertyBorderTopWidth, borderTopWidth, BorderTopWidth) - HANDLE_INHERIT_COND(CSSPropertyBorderRightWidth, borderRightWidth, BorderRightWidth) - HANDLE_INHERIT_COND(CSSPropertyBorderBottomWidth, borderBottomWidth, BorderBottomWidth) - HANDLE_INHERIT_COND(CSSPropertyBorderLeftWidth, borderLeftWidth, BorderLeftWidth) - HANDLE_INHERIT_COND(CSSPropertyOutlineWidth, outlineWidth, OutlineWidth) - HANDLE_INHERIT_COND(CSSPropertyWebkitColumnRuleWidth, columnRuleWidth, ColumnRuleWidth) - return; - } - else if (isInitial) { - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderTopWidth, BorderTopWidth, BorderWidth) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderRightWidth, BorderRightWidth, BorderWidth) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderBottomWidth, BorderBottomWidth, BorderWidth) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBorderLeftWidth, BorderLeftWidth, BorderWidth) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyOutlineWidth, OutlineWidth, BorderWidth) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWebkitColumnRuleWidth, ColumnRuleWidth, BorderWidth) - return; - } - - if (!primitiveValue) - return; - short width = 3; - switch (primitiveValue->getIdent()) { - case CSSValueThin: - width = 1; - break; - case CSSValueMedium: - width = 3; - break; - case CSSValueThick: - width = 5; - break; - case CSSValueInvalid: - width = primitiveValue->computeLengthShort(m_style, zoomFactor); - break; - default: - return; - } - - if (width < 0) return; - switch (id) { - case CSSPropertyBorderTopWidth: - m_style->setBorderTopWidth(width); - break; - case CSSPropertyBorderRightWidth: - m_style->setBorderRightWidth(width); - break; - case CSSPropertyBorderBottomWidth: - m_style->setBorderBottomWidth(width); - break; - case CSSPropertyBorderLeftWidth: - m_style->setBorderLeftWidth(width); - break; - case CSSPropertyOutlineWidth: - m_style->setOutlineWidth(width); - break; - case CSSPropertyWebkitColumnRuleWidth: - m_style->setColumnRuleWidth(width); - break; - default: - return; - } - return; - } - - case CSSPropertyLetterSpacing: - case CSSPropertyWordSpacing: - { - - if (isInherit) { - HANDLE_INHERIT_COND(CSSPropertyLetterSpacing, letterSpacing, LetterSpacing) - HANDLE_INHERIT_COND(CSSPropertyWordSpacing, wordSpacing, WordSpacing) - return; - } - else if (isInitial) { - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyLetterSpacing, LetterSpacing, LetterWordSpacing) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWordSpacing, WordSpacing, LetterWordSpacing) - return; - } - - int width = 0; - if (primitiveValue && primitiveValue->getIdent() == CSSValueNormal){ - width = 0; - } else { - if (!primitiveValue) - return; - width = primitiveValue->computeLengthInt(m_style, zoomFactor); - } - switch (id) { - case CSSPropertyLetterSpacing: - m_style->setLetterSpacing(width); - break; - case CSSPropertyWordSpacing: - m_style->setWordSpacing(width); - break; - // ### needs the definitions in renderstyle - default: break; - } - return; - } - - case CSSPropertyWordBreak: { - HANDLE_INHERIT_AND_INITIAL(wordBreak, WordBreak) - m_style->setWordBreak(*primitiveValue); - return; - } - - case CSSPropertyWordWrap: { - HANDLE_INHERIT_AND_INITIAL(wordWrap, WordWrap) - m_style->setWordWrap(*primitiveValue); - return; - } - - case CSSPropertyWebkitNbspMode: - { - HANDLE_INHERIT_AND_INITIAL(nbspMode, NBSPMode) - m_style->setNBSPMode(*primitiveValue); - return; - } - - case CSSPropertyWebkitLineBreak: - { - HANDLE_INHERIT_AND_INITIAL(khtmlLineBreak, KHTMLLineBreak) - m_style->setKHTMLLineBreak(*primitiveValue); - return; - } - - case CSSPropertyWebkitMatchNearestMailBlockquoteColor: - { - HANDLE_INHERIT_AND_INITIAL(matchNearestMailBlockquoteColor, MatchNearestMailBlockquoteColor) - m_style->setMatchNearestMailBlockquoteColor(*primitiveValue); - return; - } - - case CSSPropertyResize: - { - HANDLE_INHERIT_AND_INITIAL(resize, Resize) - - if (!primitiveValue->getIdent()) - return; - - EResize r = RESIZE_NONE; - if (primitiveValue->getIdent() == CSSValueAuto) { - if (Settings* settings = m_checker.m_document->settings()) - r = settings->textAreasAreResizable() ? RESIZE_BOTH : RESIZE_NONE; - } else - r = *primitiveValue; - - m_style->setResize(r); - return; - } - - // length, percent - case CSSPropertyMaxWidth: - // +none +inherit - if (primitiveValue && primitiveValue->getIdent() == CSSValueNone) - apply = true; - case CSSPropertyTop: - case CSSPropertyLeft: - case CSSPropertyRight: - case CSSPropertyBottom: - case CSSPropertyWidth: - case CSSPropertyMinWidth: - case CSSPropertyMarginTop: - case CSSPropertyMarginRight: - case CSSPropertyMarginBottom: - case CSSPropertyMarginLeft: - // +inherit +auto - if (id == CSSPropertyWidth || id == CSSPropertyMinWidth || id == CSSPropertyMaxWidth) { - if (primitiveValue && primitiveValue->getIdent() == CSSValueIntrinsic) { - l = Length(Intrinsic); - apply = true; - } - else if (primitiveValue && primitiveValue->getIdent() == CSSValueMinIntrinsic) { - l = Length(MinIntrinsic); - apply = true; - } - } - if (id != CSSPropertyMaxWidth && primitiveValue && primitiveValue->getIdent() == CSSValueAuto) - apply = true; - case CSSPropertyPaddingTop: - case CSSPropertyPaddingRight: - case CSSPropertyPaddingBottom: - case CSSPropertyPaddingLeft: - case CSSPropertyTextIndent: - // +inherit - { - if (isInherit) { - HANDLE_INHERIT_COND(CSSPropertyMaxWidth, maxWidth, MaxWidth) - HANDLE_INHERIT_COND(CSSPropertyBottom, bottom, Bottom) - HANDLE_INHERIT_COND(CSSPropertyTop, top, Top) - HANDLE_INHERIT_COND(CSSPropertyLeft, left, Left) - HANDLE_INHERIT_COND(CSSPropertyRight, right, Right) - HANDLE_INHERIT_COND(CSSPropertyWidth, width, Width) - HANDLE_INHERIT_COND(CSSPropertyMinWidth, minWidth, MinWidth) - HANDLE_INHERIT_COND(CSSPropertyPaddingTop, paddingTop, PaddingTop) - HANDLE_INHERIT_COND(CSSPropertyPaddingRight, paddingRight, PaddingRight) - HANDLE_INHERIT_COND(CSSPropertyPaddingBottom, paddingBottom, PaddingBottom) - HANDLE_INHERIT_COND(CSSPropertyPaddingLeft, paddingLeft, PaddingLeft) - HANDLE_INHERIT_COND(CSSPropertyMarginTop, marginTop, MarginTop) - HANDLE_INHERIT_COND(CSSPropertyMarginRight, marginRight, MarginRight) - HANDLE_INHERIT_COND(CSSPropertyMarginBottom, marginBottom, MarginBottom) - HANDLE_INHERIT_COND(CSSPropertyMarginLeft, marginLeft, MarginLeft) - HANDLE_INHERIT_COND(CSSPropertyTextIndent, textIndent, TextIndent) - return; - } - else if (isInitial) { - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMaxWidth, MaxWidth, MaxSize) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyBottom, Bottom, Offset) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyTop, Top, Offset) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyLeft, Left, Offset) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyRight, Right, Offset) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWidth, Width, Size) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMinWidth, MinWidth, MinSize) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyPaddingTop, PaddingTop, Padding) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyPaddingRight, PaddingRight, Padding) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyPaddingBottom, PaddingBottom, Padding) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyPaddingLeft, PaddingLeft, Padding) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMarginTop, MarginTop, Margin) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMarginRight, MarginRight, Margin) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMarginBottom, MarginBottom, Margin) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMarginLeft, MarginLeft, Margin) - HANDLE_INITIAL_COND(CSSPropertyTextIndent, TextIndent) - return; - } - - if (primitiveValue && !apply) { - int type = primitiveValue->primitiveType(); - if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) - // Handle our quirky margin units if we have them. - l = Length(primitiveValue->computeLengthIntForLength(m_style, zoomFactor), Fixed, - primitiveValue->isQuirkValue()); - else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) - l = Length(primitiveValue->getDoubleValue(), Percent); - else - return; - if (id == CSSPropertyPaddingLeft || id == CSSPropertyPaddingRight || - id == CSSPropertyPaddingTop || id == CSSPropertyPaddingBottom) - // Padding can't be negative - apply = !((l.isFixed() || l.isPercent()) && l.calcValue(100) < 0); - else - apply = true; - } - if (!apply) return; - switch (id) { - case CSSPropertyMaxWidth: - m_style->setMaxWidth(l); - break; - case CSSPropertyBottom: - m_style->setBottom(l); - break; - case CSSPropertyTop: - m_style->setTop(l); - break; - case CSSPropertyLeft: - m_style->setLeft(l); - break; - case CSSPropertyRight: - m_style->setRight(l); - break; - case CSSPropertyWidth: - m_style->setWidth(l); - break; - case CSSPropertyMinWidth: - m_style->setMinWidth(l); - break; - case CSSPropertyPaddingTop: - m_style->setPaddingTop(l); - break; - case CSSPropertyPaddingRight: - m_style->setPaddingRight(l); - break; - case CSSPropertyPaddingBottom: - m_style->setPaddingBottom(l); - break; - case CSSPropertyPaddingLeft: - m_style->setPaddingLeft(l); - break; - case CSSPropertyMarginTop: - m_style->setMarginTop(l); - break; - case CSSPropertyMarginRight: - m_style->setMarginRight(l); - break; - case CSSPropertyMarginBottom: - m_style->setMarginBottom(l); - break; - case CSSPropertyMarginLeft: - m_style->setMarginLeft(l); - break; - case CSSPropertyTextIndent: - m_style->setTextIndent(l); - break; - default: - break; - } - return; - } - - case CSSPropertyMaxHeight: - if (primitiveValue && primitiveValue->getIdent() == CSSValueNone) { - l = Length(undefinedLength, Fixed); - apply = true; - } - case CSSPropertyHeight: - case CSSPropertyMinHeight: - if (primitiveValue && primitiveValue->getIdent() == CSSValueIntrinsic) { - l = Length(Intrinsic); - apply = true; - } else if (primitiveValue && primitiveValue->getIdent() == CSSValueMinIntrinsic) { - l = Length(MinIntrinsic); - apply = true; - } else if (id != CSSPropertyMaxHeight && primitiveValue && primitiveValue->getIdent() == CSSValueAuto) - apply = true; - if (isInherit) { - HANDLE_INHERIT_COND(CSSPropertyMaxHeight, maxHeight, MaxHeight) - HANDLE_INHERIT_COND(CSSPropertyHeight, height, Height) - HANDLE_INHERIT_COND(CSSPropertyMinHeight, minHeight, MinHeight) - return; - } - if (isInitial) { - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMaxHeight, MaxHeight, MaxSize) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyHeight, Height, Size) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyMinHeight, MinHeight, MinSize) - return; - } - - if (primitiveValue && !apply) { - unsigned short type = primitiveValue->primitiveType(); - if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) - l = Length(primitiveValue->computeLengthIntForLength(m_style, zoomFactor), Fixed); - else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) - l = Length(primitiveValue->getDoubleValue(), Percent); - else - return; - apply = true; - } - if (apply) - switch (id) { - case CSSPropertyMaxHeight: - m_style->setMaxHeight(l); - break; - case CSSPropertyHeight: - m_style->setHeight(l); - break; - case CSSPropertyMinHeight: - m_style->setMinHeight(l); - break; - } - return; - - case CSSPropertyVerticalAlign: - HANDLE_INHERIT_AND_INITIAL(verticalAlign, VerticalAlign) - if (!primitiveValue) - return; - if (primitiveValue->getIdent()) { - EVerticalAlign align; - - switch (primitiveValue->getIdent()) { - case CSSValueTop: - align = TOP; break; - case CSSValueBottom: - align = BOTTOM; break; - case CSSValueMiddle: - align = MIDDLE; break; - case CSSValueBaseline: - align = BASELINE; break; - case CSSValueTextBottom: - align = TEXT_BOTTOM; break; - case CSSValueTextTop: - align = TEXT_TOP; break; - case CSSValueSub: - align = SUB; break; - case CSSValueSuper: - align = SUPER; break; - case CSSValueWebkitBaselineMiddle: - align = BASELINE_MIDDLE; break; - default: - return; - } - m_style->setVerticalAlign(align); - return; - } else { - int type = primitiveValue->primitiveType(); - Length l; - if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) - l = Length(primitiveValue->computeLengthIntForLength(m_style, zoomFactor), Fixed); - else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) - l = Length(primitiveValue->getDoubleValue(), Percent); - - m_style->setVerticalAlign(LENGTH); - m_style->setVerticalAlignLength(l); - } - return; - - case CSSPropertyFontSize: - { - FontDescription fontDescription = m_style->fontDescription(); - fontDescription.setKeywordSize(0); - bool familyIsFixed = fontDescription.genericFamily() == FontDescription::MonospaceFamily; - float oldSize = 0; - float size = 0; - - bool parentIsAbsoluteSize = false; - if (m_parentNode) { - oldSize = m_parentStyle->fontDescription().specifiedSize(); - parentIsAbsoluteSize = m_parentStyle->fontDescription().isAbsoluteSize(); - } - - if (isInherit) { - size = oldSize; - if (m_parentNode) - fontDescription.setKeywordSize(m_parentStyle->fontDescription().keywordSize()); - } else if (isInitial) { - size = fontSizeForKeyword(CSSValueMedium, m_style->htmlHacks(), familyIsFixed); - fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1); - } else if (primitiveValue->getIdent()) { - // Keywords are being used. - switch (primitiveValue->getIdent()) { - case CSSValueXxSmall: - case CSSValueXSmall: - case CSSValueSmall: - case CSSValueMedium: - case CSSValueLarge: - case CSSValueXLarge: - case CSSValueXxLarge: - case CSSValueWebkitXxxLarge: - size = fontSizeForKeyword(primitiveValue->getIdent(), m_style->htmlHacks(), familyIsFixed); - fontDescription.setKeywordSize(primitiveValue->getIdent() - CSSValueXxSmall + 1); - break; - case CSSValueLarger: - size = largerFontSize(oldSize, m_style->htmlHacks()); - break; - case CSSValueSmaller: - size = smallerFontSize(oldSize, m_style->htmlHacks()); - break; - default: - return; - } - - fontDescription.setIsAbsoluteSize(parentIsAbsoluteSize && - (primitiveValue->getIdent() == CSSValueLarger || - primitiveValue->getIdent() == CSSValueSmaller)); - } else { - int type = primitiveValue->primitiveType(); - fontDescription.setIsAbsoluteSize(parentIsAbsoluteSize || - (type != CSSPrimitiveValue::CSS_PERCENTAGE && - type != CSSPrimitiveValue::CSS_EMS && - type != CSSPrimitiveValue::CSS_EXS)); - if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) - size = primitiveValue->computeLengthFloat(m_parentStyle, true); - else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) - size = (primitiveValue->getFloatValue() * oldSize) / 100.0f; - else - return; - } - - if (size < 0) - return; - - setFontSize(fontDescription, size); - if (m_style->setFontDescription(fontDescription)) - m_fontDirty = true; - return; - } - - case CSSPropertyZIndex: { - if (isInherit) { - if (m_parentStyle->hasAutoZIndex()) - m_style->setHasAutoZIndex(); - else - m_style->setZIndex(m_parentStyle->zIndex()); - return; - } else if (isInitial || primitiveValue->getIdent() == CSSValueAuto) { - m_style->setHasAutoZIndex(); - return; - } - - // FIXME: Should clamp all sorts of other integer properties too. - const double minIntAsDouble = INT_MIN; - const double maxIntAsDouble = INT_MAX; - m_style->setZIndex(static_cast<int>(max(minIntAsDouble, min(primitiveValue->getDoubleValue(), maxIntAsDouble)))); - return; - } - case CSSPropertyWidows: - { - HANDLE_INHERIT_AND_INITIAL(widows, Widows) - if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER) - return; - m_style->setWidows(primitiveValue->getIntValue()); - return; - } - - case CSSPropertyOrphans: - { - HANDLE_INHERIT_AND_INITIAL(orphans, Orphans) - if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER) - return; - m_style->setOrphans(primitiveValue->getIntValue()); - return; - } - -// length, percent, number - case CSSPropertyLineHeight: - { - HANDLE_INHERIT_AND_INITIAL(lineHeight, LineHeight) - if (!primitiveValue) - return; - Length lineHeight; - int type = primitiveValue->primitiveType(); - if (primitiveValue->getIdent() == CSSValueNormal) - lineHeight = Length(-100.0, Percent); - else if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) { - double multiplier = m_style->effectiveZoom(); - if (m_style->textSizeAdjust() && m_checker.m_document->frame() && m_checker.m_document->frame()->shouldApplyTextZoom()) - multiplier *= m_checker.m_document->frame()->textZoomFactor(); - lineHeight = Length(primitiveValue->computeLengthIntForLength(m_style, multiplier), Fixed); - } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) - lineHeight = Length((m_style->fontSize() * primitiveValue->getIntValue()) / 100, Fixed); - else if (type == CSSPrimitiveValue::CSS_NUMBER) - lineHeight = Length(primitiveValue->getDoubleValue() * 100.0, Percent); - else - return; - m_style->setLineHeight(lineHeight); - return; - } - -// string - case CSSPropertyTextAlign: - { - HANDLE_INHERIT_AND_INITIAL(textAlign, TextAlign) - if (!primitiveValue) - return; - int id = primitiveValue->getIdent(); - if (id == CSSValueStart) - m_style->setTextAlign(m_style->direction() == LTR ? LEFT : RIGHT); - else if (id == CSSValueEnd) - m_style->setTextAlign(m_style->direction() == LTR ? RIGHT : LEFT); - else - m_style->setTextAlign(*primitiveValue); - return; - } - -// rect - case CSSPropertyClip: - { - Length top; - Length right; - Length bottom; - Length left; - bool hasClip = true; - if (isInherit) { - if (m_parentStyle->hasClip()) { - top = m_parentStyle->clipTop(); - right = m_parentStyle->clipRight(); - bottom = m_parentStyle->clipBottom(); - left = m_parentStyle->clipLeft(); - } - else { - hasClip = false; - top = right = bottom = left = Length(); - } - } else if (isInitial) { - hasClip = false; - top = right = bottom = left = Length(); - } else if (!primitiveValue) { - return; - } else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_RECT) { - Rect* rect = primitiveValue->getRectValue(); - if (!rect) - return; - top = convertToLength(rect->top(), m_style); - right = convertToLength(rect->right(), m_style); - bottom = convertToLength(rect->bottom(), m_style); - left = convertToLength(rect->left(), m_style); - - } else if (primitiveValue->getIdent() != CSSValueAuto) { - return; - } - m_style->setClip(top, right, bottom, left); - m_style->setHasClip(hasClip); - - // rect, ident - return; - } - -// lists - case CSSPropertyContent: - // list of string, uri, counter, attr, i - { - // FIXME: In CSS3, it will be possible to inherit content. In CSS2 it is not. This - // note is a reminder that eventually "inherit" needs to be supported. - - if (isInitial) { - m_style->clearContent(); - return; - } - - if (!value->isValueList()) - return; - - CSSValueList* list = static_cast<CSSValueList*>(value); - int len = list->length(); - - bool didSet = false; - for (int i = 0; i < len; i++) { - CSSValue* item = list->itemWithoutBoundsCheck(i); - if (item->isImageGeneratorValue()) { - m_style->setContent(static_cast<CSSImageGeneratorValue*>(item)->generatedImage(), didSet); - didSet = true; - } - - if (!item->isPrimitiveValue()) - continue; - - CSSPrimitiveValue* val = static_cast<CSSPrimitiveValue*>(item); - switch (val->primitiveType()) { - case CSSPrimitiveValue::CSS_STRING: - m_style->setContent(val->getStringValue().impl(), didSet); - didSet = true; - break; - case CSSPrimitiveValue::CSS_ATTR: { - // FIXME: Can a namespace be specified for an attr(foo)? - if (m_style->styleType() == RenderStyle::NOPSEUDO) - m_style->setUnique(); - else - m_parentStyle->setUnique(); - QualifiedName attr(nullAtom, val->getStringValue().impl(), nullAtom); - m_style->setContent(m_element->getAttribute(attr).impl(), didSet); - didSet = true; - // register the fact that the attribute value affects the style - m_selectorAttrs.add(attr.localName().impl()); - break; - } - case CSSPrimitiveValue::CSS_URI: { - CSSImageValue* image = static_cast<CSSImageValue*>(val); - m_style->setContent(image->cachedImage(m_element->document()->docLoader()), didSet); - didSet = true; - break; - } - case CSSPrimitiveValue::CSS_COUNTER: { - Counter* counterValue = val->getCounterValue(); - CounterContent* counter = new CounterContent(counterValue->identifier(), - (EListStyleType)counterValue->listStyleNumber(), counterValue->separator()); - m_style->setContent(counter, didSet); - didSet = true; - } - } - } - if (!didSet) - m_style->clearContent(); - return; - } - - case CSSPropertyCounterIncrement: - applyCounterList(m_style, value->isValueList() ? static_cast<CSSValueList*>(value) : 0, false); - return; - case CSSPropertyCounterReset: - applyCounterList(m_style, value->isValueList() ? static_cast<CSSValueList*>(value) : 0, true); - return; - - case CSSPropertyFontFamily: { - // list of strings and ids - if (isInherit) { - FontDescription parentFontDescription = m_parentStyle->fontDescription(); - FontDescription fontDescription = m_style->fontDescription(); - fontDescription.setGenericFamily(parentFontDescription.genericFamily()); - fontDescription.setFamily(parentFontDescription.firstFamily()); - if (m_style->setFontDescription(fontDescription)) - m_fontDirty = true; - return; - } - else if (isInitial) { - FontDescription initialDesc = FontDescription(); - FontDescription fontDescription = m_style->fontDescription(); - // We need to adjust the size to account for the generic family change from monospace - // to non-monospace. - if (fontDescription.keywordSize() && fontDescription.genericFamily() == FontDescription::MonospaceFamily) - setFontSize(fontDescription, fontSizeForKeyword(CSSValueXxSmall + fontDescription.keywordSize() - 1, m_style->htmlHacks(), false)); - fontDescription.setGenericFamily(initialDesc.genericFamily()); - if (!initialDesc.firstFamily().familyIsEmpty()) - fontDescription.setFamily(initialDesc.firstFamily()); - if (m_style->setFontDescription(fontDescription)) - m_fontDirty = true; - return; - } - - if (!value->isValueList()) return; - FontDescription fontDescription = m_style->fontDescription(); - CSSValueList *list = static_cast<CSSValueList*>(value); - int len = list->length(); - FontFamily& firstFamily = fontDescription.firstFamily(); - FontFamily *currFamily = 0; - - // Before mapping in a new font-family property, we should reset the generic family. - bool oldFamilyIsMonospace = fontDescription.genericFamily() == FontDescription::MonospaceFamily; - fontDescription.setGenericFamily(FontDescription::NoFamily); - - // |script| is used to add a font per script and per CSS generic family. - // Adding it here is not very efficient because we may never use it - // if all the characters are covered by fonts specified for this element. - // TODO(jungshik): Currently, it's document-wide constant inferred from - // the document charset, but we should infer it from the value of - // xml:lang or lang for |m_element|. - UScriptCode script = m_checker.m_document->dominantScript(); - // serif, sans-serif, cursive, fantasy, monospace - ScriptFamilyState scriptFamilyStates[5]; - Settings* settings = m_checker.m_document->settings(); - for (int i = 0; i < len; i++) { - CSSValue *item = list->itemWithoutBoundsCheck(i); - if (!item->isPrimitiveValue()) continue; - CSSPrimitiveValue *val = static_cast<CSSPrimitiveValue*>(item); - AtomicString face; - if (val->primitiveType() == CSSPrimitiveValue::CSS_STRING) - face = static_cast<FontFamilyValue*>(val)->familyName(); - else if (val->primitiveType() == CSSPrimitiveValue::CSS_IDENT && settings) { - switch (val->getIdent()) { - case CSSValueWebkitBody: - face = settings->standardFontFamily(); - break; - // For each of 5 CSS generic families, - // we add '-webkit-FOO' and a per-script generic family. - // When |Settings| becomes expressive enough to support - // per-script&per-generic family and we have a UI for - // that, we'd just add the latter. Even without that, - // I'm tempted to add per-script generic first, but I can't. - // If I did, our font-selection UI would be all but - // non-functional. Another issue is that we're adding - // these fonts without regard for actual need in page - // rendering. That is, it's not done in a lazy manner. - // Somewhere in getGlyphDataForCharacter() could be - // a better place in terms of performance. - // See https://bugs.webkit.org/show_bug.cgi?id=18085 - // and http://bugs.webkit.org/show_bug.cgi?id=10874 - case CSSValueSerif: - handleScriptFamily("-webkit-serif", script, - FontDescription::SerifFamily, face, - scriptFamilyStates[0], fontDescription, i); - break; - case CSSValueSansSerif: - handleScriptFamily("-webkit-sans-serif", script, - FontDescription::SansSerifFamily, face, - scriptFamilyStates[1], fontDescription, i); - break; - case CSSValueCursive: - handleScriptFamily("-webkit-cursive", script, - FontDescription::CursiveFamily, face, - scriptFamilyStates[2], fontDescription, i); - break; - case CSSValueFantasy: - handleScriptFamily("-webkit-fantasy", script, - FontDescription::FantasyFamily, face, - scriptFamilyStates[3], fontDescription, i); - break; - case CSSValueMonospace: - handleScriptFamily("-webkit-monospace", script, - FontDescription::MonospaceFamily, face, - scriptFamilyStates[4], fontDescription, i); - break; - } - } - - if (!face.isEmpty()) { - if (!currFamily) { - // Filling in the first family. - firstFamily.setFamily(face); - currFamily = &firstFamily; - } - else { - RefPtr<SharedFontFamily> newFamily = SharedFontFamily::create(); - newFamily->setFamily(face); - currFamily->appendFamily(newFamily); - currFamily = newFamily.get(); - } - - if (fontDescription.keywordSize() && (fontDescription.genericFamily() == FontDescription::MonospaceFamily) != oldFamilyIsMonospace) - setFontSize(fontDescription, fontSizeForKeyword(CSSValueXxSmall + fontDescription.keywordSize() - 1, m_style->htmlHacks(), !oldFamilyIsMonospace)); - - if (m_style->setFontDescription(fontDescription)) - m_fontDirty = true; - } - } - - if (fontDescription.genericFamily() == FontDescription::NoFamily && currFamily) { - FontDescription::GenericFamilyType generic; - // TODO(jungshik) : Perhaps, we'd better add isStandardSerif() - // method to |Settings| which will be set via WebPreference. - if (settings) { - if (settings->serifFontFamily() == settings->standardFontFamily()) - generic = FontDescription::SerifFamily ; - else - generic = FontDescription::SansSerifFamily; - } else - generic = FontDescription::StandardFamily; - fontDescription.setGenericFamily(generic); - AtomicString face = FontCache::getGenericFontForScript(script, fontDescription); - if (!face.isEmpty()) { - RefPtr<SharedFontFamily> newFamily = SharedFontFamily::create(); - newFamily->setFamily(face); - currFamily->appendFamily(newFamily); - currFamily = newFamily.get(); - if (m_style->setFontDescription(fontDescription)) - m_fontDirty = true; - } - } - return; - } - case CSSPropertyTextDecoration: { - // list of ident - HANDLE_INHERIT_AND_INITIAL(textDecoration, TextDecoration) - int t = RenderStyle::initialTextDecoration(); - if (primitiveValue && primitiveValue->getIdent() == CSSValueNone) { - // do nothing - } else { - if (!value->isValueList()) return; - CSSValueList *list = static_cast<CSSValueList*>(value); - int len = list->length(); - for (int i = 0; i < len; i++) - { - CSSValue *item = list->itemWithoutBoundsCheck(i); - if (!item->isPrimitiveValue()) continue; - primitiveValue = static_cast<CSSPrimitiveValue*>(item); - switch (primitiveValue->getIdent()) { - case CSSValueNone: - t = TDNONE; break; - case CSSValueUnderline: - t |= UNDERLINE; break; - case CSSValueOverline: - t |= OVERLINE; break; - case CSSValueLineThrough: - t |= LINE_THROUGH; break; - case CSSValueBlink: - t |= BLINK; break; - default: - return; - } - } - } - - m_style->setTextDecoration(t); - return; - } - - case CSSPropertyZoom: - { - // Reset the zoom in effect before we do anything. This allows the setZoom method to accurately compute a new - // zoom in effect. - m_style->setEffectiveZoom(m_parentStyle ? m_parentStyle->effectiveZoom() : RenderStyle::initialZoom()); - - // Now we can handle inherit and initial. - HANDLE_INHERIT_AND_INITIAL(zoom, Zoom) - - // Handle normal/reset, numbers and percentages. - int type = primitiveValue->primitiveType(); - if (primitiveValue->getIdent() == CSSValueNormal) - m_style->setZoom(RenderStyle::initialZoom()); - else if (primitiveValue->getIdent() == CSSValueReset) { - m_style->setEffectiveZoom(RenderStyle::initialZoom()); - m_style->setZoom(RenderStyle::initialZoom()); - } else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) { - if (primitiveValue->getFloatValue()) - m_style->setZoom(primitiveValue->getFloatValue() / 100.0f); - } else if (type == CSSPrimitiveValue::CSS_NUMBER) { - if (primitiveValue->getFloatValue()) - m_style->setZoom(primitiveValue->getFloatValue()); - } - - m_fontDirty = true; - return; - } -// shorthand properties - case CSSPropertyBackground: - if (isInitial) { - m_style->clearBackgroundLayers(); - m_style->setBackgroundColor(Color()); - } - else if (isInherit) { - m_style->inheritBackgroundLayers(*m_parentStyle->backgroundLayers()); - m_style->setBackgroundColor(m_parentStyle->backgroundColor()); - } - return; - case CSSPropertyWebkitMask: - if (isInitial) - m_style->clearMaskLayers(); - else if (isInherit) - m_style->inheritMaskLayers(*m_parentStyle->maskLayers()); - return; - - case CSSPropertyBorder: - case CSSPropertyBorderStyle: - case CSSPropertyBorderWidth: - case CSSPropertyBorderColor: - if (id == CSSPropertyBorder || id == CSSPropertyBorderColor) - { - if (isInherit) { - m_style->setBorderTopColor(m_parentStyle->borderTopColor().isValid() ? m_parentStyle->borderTopColor() : m_parentStyle->color()); - m_style->setBorderBottomColor(m_parentStyle->borderBottomColor().isValid() ? m_parentStyle->borderBottomColor() : m_parentStyle->color()); - m_style->setBorderLeftColor(m_parentStyle->borderLeftColor().isValid() ? m_parentStyle->borderLeftColor() : m_parentStyle->color()); - m_style->setBorderRightColor(m_parentStyle->borderRightColor().isValid() ? m_parentStyle->borderRightColor(): m_parentStyle->color()); - } - else if (isInitial) { - m_style->setBorderTopColor(Color()); // Reset to invalid color so currentColor is used instead. - m_style->setBorderBottomColor(Color()); - m_style->setBorderLeftColor(Color()); - m_style->setBorderRightColor(Color()); - } - } - if (id == CSSPropertyBorder || id == CSSPropertyBorderStyle) - { - if (isInherit) { - m_style->setBorderTopStyle(m_parentStyle->borderTopStyle()); - m_style->setBorderBottomStyle(m_parentStyle->borderBottomStyle()); - m_style->setBorderLeftStyle(m_parentStyle->borderLeftStyle()); - m_style->setBorderRightStyle(m_parentStyle->borderRightStyle()); - } - else if (isInitial) { - m_style->setBorderTopStyle(RenderStyle::initialBorderStyle()); - m_style->setBorderBottomStyle(RenderStyle::initialBorderStyle()); - m_style->setBorderLeftStyle(RenderStyle::initialBorderStyle()); - m_style->setBorderRightStyle(RenderStyle::initialBorderStyle()); - } - } - if (id == CSSPropertyBorder || id == CSSPropertyBorderWidth) - { - if (isInherit) { - m_style->setBorderTopWidth(m_parentStyle->borderTopWidth()); - m_style->setBorderBottomWidth(m_parentStyle->borderBottomWidth()); - m_style->setBorderLeftWidth(m_parentStyle->borderLeftWidth()); - m_style->setBorderRightWidth(m_parentStyle->borderRightWidth()); - } - else if (isInitial) { - m_style->setBorderTopWidth(RenderStyle::initialBorderWidth()); - m_style->setBorderBottomWidth(RenderStyle::initialBorderWidth()); - m_style->setBorderLeftWidth(RenderStyle::initialBorderWidth()); - m_style->setBorderRightWidth(RenderStyle::initialBorderWidth()); - } - } - return; - case CSSPropertyBorderTop: - if (isInherit) { - m_style->setBorderTopColor(m_parentStyle->borderTopColor().isValid() ? m_parentStyle->borderTopColor() : m_parentStyle->color()); - m_style->setBorderTopStyle(m_parentStyle->borderTopStyle()); - m_style->setBorderTopWidth(m_parentStyle->borderTopWidth()); - } - else if (isInitial) - m_style->resetBorderTop(); - return; - case CSSPropertyBorderRight: - if (isInherit) { - m_style->setBorderRightColor(m_parentStyle->borderRightColor().isValid() ? m_parentStyle->borderRightColor() : m_parentStyle->color()); - m_style->setBorderRightStyle(m_parentStyle->borderRightStyle()); - m_style->setBorderRightWidth(m_parentStyle->borderRightWidth()); - } - else if (isInitial) - m_style->resetBorderRight(); - return; - case CSSPropertyBorderBottom: - if (isInherit) { - m_style->setBorderBottomColor(m_parentStyle->borderBottomColor().isValid() ? m_parentStyle->borderBottomColor() : m_parentStyle->color()); - m_style->setBorderBottomStyle(m_parentStyle->borderBottomStyle()); - m_style->setBorderBottomWidth(m_parentStyle->borderBottomWidth()); - } - else if (isInitial) - m_style->resetBorderBottom(); - return; - case CSSPropertyBorderLeft: - if (isInherit) { - m_style->setBorderLeftColor(m_parentStyle->borderLeftColor().isValid() ? m_parentStyle->borderLeftColor() : m_parentStyle->color()); - m_style->setBorderLeftStyle(m_parentStyle->borderLeftStyle()); - m_style->setBorderLeftWidth(m_parentStyle->borderLeftWidth()); - } - else if (isInitial) - m_style->resetBorderLeft(); - return; - case CSSPropertyMargin: - if (isInherit) { - m_style->setMarginTop(m_parentStyle->marginTop()); - m_style->setMarginBottom(m_parentStyle->marginBottom()); - m_style->setMarginLeft(m_parentStyle->marginLeft()); - m_style->setMarginRight(m_parentStyle->marginRight()); - } - else if (isInitial) - m_style->resetMargin(); - return; - case CSSPropertyPadding: - if (isInherit) { - m_style->setPaddingTop(m_parentStyle->paddingTop()); - m_style->setPaddingBottom(m_parentStyle->paddingBottom()); - m_style->setPaddingLeft(m_parentStyle->paddingLeft()); - m_style->setPaddingRight(m_parentStyle->paddingRight()); - } - else if (isInitial) - m_style->resetPadding(); - return; - case CSSPropertyFont: - if (isInherit) { - FontDescription fontDescription = m_parentStyle->fontDescription(); - m_style->setLineHeight(m_parentStyle->lineHeight()); - m_lineHeightValue = 0; - if (m_style->setFontDescription(fontDescription)) - m_fontDirty = true; - } else if (isInitial) { - Settings* settings = m_checker.m_document->settings(); - FontDescription fontDescription; - fontDescription.setGenericFamily(FontDescription::StandardFamily); - fontDescription.setRenderingMode(settings->fontRenderingMode()); - fontDescription.setUsePrinterFont(m_checker.m_document->printing()); - const AtomicString& standardFontFamily = m_checker.m_document->settings()->standardFontFamily(); - if (!standardFontFamily.isEmpty()) { - fontDescription.firstFamily().setFamily(standardFontFamily); - fontDescription.firstFamily().appendFamily(0); - } - fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1); - setFontSize(fontDescription, fontSizeForKeyword(CSSValueMedium, m_style->htmlHacks(), false)); - m_style->setLineHeight(RenderStyle::initialLineHeight()); - m_lineHeightValue = 0; - if (m_style->setFontDescription(fontDescription)) - m_fontDirty = true; - } else if (primitiveValue) { - m_style->setLineHeight(RenderStyle::initialLineHeight()); - m_lineHeightValue = 0; - FontDescription fontDescription; - theme()->systemFont(primitiveValue->getIdent(), m_checker.m_document, fontDescription); - // Double-check and see if the theme did anything. If not, don't bother updating the font. - if (fontDescription.isAbsoluteSize()) { - // Handle the zoom factor. - fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(fontDescription.isAbsoluteSize(), fontDescription.specifiedSize())); - if (m_style->setFontDescription(fontDescription)) - m_fontDirty = true; - } - } else if (value->isFontValue()) { - FontValue *font = static_cast<FontValue*>(value); - if (!font->style || !font->variant || !font->weight || - !font->size || !font->lineHeight || !font->family) - return; - applyProperty(CSSPropertyFontStyle, font->style.get()); - applyProperty(CSSPropertyFontVariant, font->variant.get()); - applyProperty(CSSPropertyFontWeight, font->weight.get()); - applyProperty(CSSPropertyFontSize, font->size.get()); - - m_lineHeightValue = font->lineHeight.get(); - - applyProperty(CSSPropertyFontFamily, font->family.get()); - } - return; - - case CSSPropertyListStyle: - if (isInherit) { - m_style->setListStyleType(m_parentStyle->listStyleType()); - m_style->setListStyleImage(m_parentStyle->listStyleImage()); - m_style->setListStylePosition(m_parentStyle->listStylePosition()); - } - else if (isInitial) { - m_style->setListStyleType(RenderStyle::initialListStyleType()); - m_style->setListStyleImage(RenderStyle::initialListStyleImage()); - m_style->setListStylePosition(RenderStyle::initialListStylePosition()); - } - return; - case CSSPropertyOutline: - if (isInherit) { - m_style->setOutlineWidth(m_parentStyle->outlineWidth()); - m_style->setOutlineColor(m_parentStyle->outlineColor().isValid() ? m_parentStyle->outlineColor() : m_parentStyle->color()); - m_style->setOutlineStyle(m_parentStyle->outlineStyle()); - } - else if (isInitial) - m_style->resetOutline(); - return; - - // CSS3 Properties - case CSSPropertyWebkitAppearance: { - HANDLE_INHERIT_AND_INITIAL(appearance, Appearance) - if (!primitiveValue) - return; - m_style->setAppearance(*primitiveValue); - return; - } - case CSSPropertyWebkitBinding: { -#if ENABLE(XBL) - if (isInitial || (primitiveValue && primitiveValue->getIdent() == CSSValueNone)) { - m_style->deleteBindingURIs(); - return; - } - else if (isInherit) { - if (m_parentStyle->bindingURIs()) - m_style->inheritBindingURIs(m_parentStyle->bindingURIs()); - else - m_style->deleteBindingURIs(); - return; - } - - if (!value->isValueList()) return; - CSSValueList* list = static_cast<CSSValueList*>(value); - bool firstBinding = true; - for (unsigned int i = 0; i < list->length(); i++) { - CSSValue *item = list->itemWithoutBoundsCheck(i); - CSSPrimitiveValue *val = static_cast<CSSPrimitiveValue*>(item); - if (val->primitiveType() == CSSPrimitiveValue::CSS_URI) { - if (firstBinding) { - firstBinding = false; - m_style->deleteBindingURIs(); - } - m_style->addBindingURI(val->getStringValue()); - } - } -#endif - return; - } - - case CSSPropertyWebkitBorderImage: - case CSSPropertyWebkitMaskBoxImage: { - if (isInherit) { - HANDLE_INHERIT_COND(CSSPropertyWebkitBorderImage, borderImage, BorderImage) - HANDLE_INHERIT_COND(CSSPropertyWebkitMaskBoxImage, maskBoxImage, MaskBoxImage) - return; - } else if (isInitial) { - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWebkitBorderImage, BorderImage, NinePieceImage) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWebkitMaskBoxImage, MaskBoxImage, NinePieceImage) - return; - } - - NinePieceImage image; - mapNinePieceImage(value, image); - - if (id == CSSPropertyWebkitBorderImage) - m_style->setBorderImage(image); - else - m_style->setMaskBoxImage(image); - return; - } - - case CSSPropertyWebkitBorderRadius: - if (isInherit) { - m_style->setBorderTopLeftRadius(m_parentStyle->borderTopLeftRadius()); - m_style->setBorderTopRightRadius(m_parentStyle->borderTopRightRadius()); - m_style->setBorderBottomLeftRadius(m_parentStyle->borderBottomLeftRadius()); - m_style->setBorderBottomRightRadius(m_parentStyle->borderBottomRightRadius()); - return; - } - if (isInitial) { - m_style->resetBorderRadius(); - return; - } - // Fall through - case CSSPropertyWebkitBorderTopLeftRadius: - case CSSPropertyWebkitBorderTopRightRadius: - case CSSPropertyWebkitBorderBottomLeftRadius: - case CSSPropertyWebkitBorderBottomRightRadius: { - if (isInherit) { - HANDLE_INHERIT_COND(CSSPropertyWebkitBorderTopLeftRadius, borderTopLeftRadius, BorderTopLeftRadius) - HANDLE_INHERIT_COND(CSSPropertyWebkitBorderTopRightRadius, borderTopRightRadius, BorderTopRightRadius) - HANDLE_INHERIT_COND(CSSPropertyWebkitBorderBottomLeftRadius, borderBottomLeftRadius, BorderBottomLeftRadius) - HANDLE_INHERIT_COND(CSSPropertyWebkitBorderBottomRightRadius, borderBottomRightRadius, BorderBottomRightRadius) - return; - } - - if (isInitial) { - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWebkitBorderTopLeftRadius, BorderTopLeftRadius, BorderRadius) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWebkitBorderTopRightRadius, BorderTopRightRadius, BorderRadius) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWebkitBorderBottomLeftRadius, BorderBottomLeftRadius, BorderRadius) - HANDLE_INITIAL_COND_WITH_VALUE(CSSPropertyWebkitBorderBottomRightRadius, BorderBottomRightRadius, BorderRadius) - return; - } - - if (!primitiveValue) - return; - - Pair* pair = primitiveValue->getPairValue(); - if (!pair) - return; - - int width = pair->first()->computeLengthInt(m_style, zoomFactor); - int height = pair->second()->computeLengthInt(m_style, zoomFactor); - if (width < 0 || height < 0) - return; - - if (width == 0) - height = 0; // Null out the other value. - else if (height == 0) - width = 0; // Null out the other value. - - IntSize size(width, height); - switch (id) { - case CSSPropertyWebkitBorderTopLeftRadius: - m_style->setBorderTopLeftRadius(size); - break; - case CSSPropertyWebkitBorderTopRightRadius: - m_style->setBorderTopRightRadius(size); - break; - case CSSPropertyWebkitBorderBottomLeftRadius: - m_style->setBorderBottomLeftRadius(size); - break; - case CSSPropertyWebkitBorderBottomRightRadius: - m_style->setBorderBottomRightRadius(size); - break; - default: - m_style->setBorderRadius(size); - break; - } - return; - } - - case CSSPropertyOutlineOffset: - HANDLE_INHERIT_AND_INITIAL(outlineOffset, OutlineOffset) - m_style->setOutlineOffset(primitiveValue->computeLengthInt(m_style, zoomFactor)); - return; - - case CSSPropertyTextShadow: - case CSSPropertyWebkitBoxShadow: { - if (isInherit) { - if (id == CSSPropertyTextShadow) - return m_style->setTextShadow(m_parentStyle->textShadow() ? new ShadowData(*m_parentStyle->textShadow()) : 0); - return m_style->setBoxShadow(m_parentStyle->boxShadow() ? new ShadowData(*m_parentStyle->boxShadow()) : 0); - } - if (isInitial || primitiveValue) // initial | none - return id == CSSPropertyTextShadow ? m_style->setTextShadow(0) : m_style->setBoxShadow(0); - - if (!value->isValueList()) - return; - - CSSValueList *list = static_cast<CSSValueList*>(value); - int len = list->length(); - for (int i = 0; i < len; i++) { - ShadowValue* item = static_cast<ShadowValue*>(list->itemWithoutBoundsCheck(i)); - int x = item->x->computeLengthInt(m_style, zoomFactor); - int y = item->y->computeLengthInt(m_style, zoomFactor); - int blur = item->blur ? item->blur->computeLengthInt(m_style, zoomFactor) : 0; - Color color; - if (item->color) - color = getColorFromPrimitiveValue(item->color.get()); - ShadowData* shadowData = new ShadowData(x, y, blur, color.isValid() ? color : Color::transparent); - if (id == CSSPropertyTextShadow) - m_style->setTextShadow(shadowData, i != 0); - else - m_style->setBoxShadow(shadowData, i != 0); - } - return; - } - case CSSPropertyWebkitBoxReflect: { - HANDLE_INHERIT_AND_INITIAL(boxReflect, BoxReflect) - if (primitiveValue) { - m_style->setBoxReflect(RenderStyle::initialBoxReflect()); - return; - } - CSSReflectValue* reflectValue = static_cast<CSSReflectValue*>(value); - RefPtr<StyleReflection> reflection = StyleReflection::create(); - reflection->setDirection(reflectValue->direction()); - if (reflectValue->offset()) { - int type = reflectValue->offset()->primitiveType(); - if (type == CSSPrimitiveValue::CSS_PERCENTAGE) - reflection->setOffset(Length(reflectValue->offset()->getDoubleValue(), Percent)); - else - reflection->setOffset(Length(reflectValue->offset()->computeLengthIntForLength(m_style, zoomFactor), Fixed)); - } - NinePieceImage mask; - mapNinePieceImage(reflectValue->mask(), mask); - reflection->setMask(mask); - - m_style->setBoxReflect(reflection.release()); - return; - } - case CSSPropertyOpacity: - HANDLE_INHERIT_AND_INITIAL(opacity, Opacity) - if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER) - return; // Error case. - // Clamp opacity to the range 0-1 - m_style->setOpacity(min(1.0f, max(0.0f, primitiveValue->getFloatValue()))); - return; - case CSSPropertyWebkitBoxAlign: - { - HANDLE_INHERIT_AND_INITIAL(boxAlign, BoxAlign) - if (!primitiveValue) - return; - EBoxAlignment boxAlignment = *primitiveValue; - if (boxAlignment != BJUSTIFY) - m_style->setBoxAlign(boxAlignment); - return; - } - case CSSPropertySrc: // Only used in @font-face rules. - return; - case CSSPropertyUnicodeRange: // Only used in @font-face rules. - return; - case CSSPropertyWebkitBoxDirection: - HANDLE_INHERIT_AND_INITIAL(boxDirection, BoxDirection) - if (primitiveValue) - m_style->setBoxDirection(*primitiveValue); - return; - case CSSPropertyWebkitBoxLines: - HANDLE_INHERIT_AND_INITIAL(boxLines, BoxLines) - if (primitiveValue) - m_style->setBoxLines(*primitiveValue); - return; - case CSSPropertyWebkitBoxOrient: - HANDLE_INHERIT_AND_INITIAL(boxOrient, BoxOrient) - if (primitiveValue) - m_style->setBoxOrient(*primitiveValue); - return; - case CSSPropertyWebkitBoxPack: - { - HANDLE_INHERIT_AND_INITIAL(boxPack, BoxPack) - if (!primitiveValue) - return; - EBoxAlignment boxPack = *primitiveValue; - if (boxPack != BSTRETCH && boxPack != BBASELINE) - m_style->setBoxPack(boxPack); - return; - } - case CSSPropertyWebkitBoxFlex: - HANDLE_INHERIT_AND_INITIAL(boxFlex, BoxFlex) - if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER) - return; // Error case. - m_style->setBoxFlex(primitiveValue->getFloatValue()); - return; - case CSSPropertyWebkitBoxFlexGroup: - HANDLE_INHERIT_AND_INITIAL(boxFlexGroup, BoxFlexGroup) - if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER) - return; // Error case. - m_style->setBoxFlexGroup((unsigned int)(primitiveValue->getDoubleValue())); - return; - case CSSPropertyWebkitBoxOrdinalGroup: - HANDLE_INHERIT_AND_INITIAL(boxOrdinalGroup, BoxOrdinalGroup) - if (!primitiveValue || primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER) - return; // Error case. - m_style->setBoxOrdinalGroup((unsigned int)(primitiveValue->getDoubleValue())); - return; - case CSSPropertyWebkitBoxSizing: - HANDLE_INHERIT_AND_INITIAL(boxSizing, BoxSizing) - if (!primitiveValue) - return; - if (primitiveValue->getIdent() == CSSValueContentBox) - m_style->setBoxSizing(CONTENT_BOX); - else - m_style->setBoxSizing(BORDER_BOX); - return; - case CSSPropertyWebkitColumnCount: { - if (isInherit) { - if (m_parentStyle->hasAutoColumnCount()) - m_style->setHasAutoColumnCount(); - else - m_style->setColumnCount(m_parentStyle->columnCount()); - return; - } else if (isInitial || primitiveValue->getIdent() == CSSValueAuto) { - m_style->setHasAutoColumnCount(); - return; - } - m_style->setColumnCount(static_cast<unsigned short>(primitiveValue->getDoubleValue())); - return; - } - case CSSPropertyWebkitColumnGap: { - if (isInherit) { - if (m_parentStyle->hasNormalColumnGap()) - m_style->setHasNormalColumnGap(); - else - m_style->setColumnGap(m_parentStyle->columnGap()); - return; - } else if (isInitial || primitiveValue->getIdent() == CSSValueNormal) { - m_style->setHasNormalColumnGap(); - return; - } - m_style->setColumnGap(primitiveValue->computeLengthFloat(m_style, zoomFactor)); - return; - } - case CSSPropertyWebkitColumnWidth: { - if (isInherit) { - if (m_parentStyle->hasAutoColumnWidth()) - m_style->setHasAutoColumnWidth(); - else - m_style->setColumnWidth(m_parentStyle->columnWidth()); - return; - } else if (isInitial || primitiveValue->getIdent() == CSSValueAuto) { - m_style->setHasAutoColumnWidth(); - return; - } - m_style->setColumnWidth(primitiveValue->computeLengthFloat(m_style, zoomFactor)); - return; - } - case CSSPropertyWebkitColumnRuleStyle: - HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(columnRuleStyle, ColumnRuleStyle, BorderStyle) - m_style->setColumnRuleStyle(*primitiveValue); - return; - case CSSPropertyWebkitColumnBreakBefore: { - HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(columnBreakBefore, ColumnBreakBefore, PageBreak) - m_style->setColumnBreakBefore(*primitiveValue); - return; - } - case CSSPropertyWebkitColumnBreakAfter: { - HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(columnBreakAfter, ColumnBreakAfter, PageBreak) - m_style->setColumnBreakAfter(*primitiveValue); - return; - } - case CSSPropertyWebkitColumnBreakInside: { - HANDLE_INHERIT_AND_INITIAL_WITH_VALUE(columnBreakInside, ColumnBreakInside, PageBreak) - EPageBreak pb = *primitiveValue; - if (pb != PBALWAYS) - m_style->setColumnBreakInside(pb); - return; - } - case CSSPropertyWebkitColumnRule: - if (isInherit) { - m_style->setColumnRuleColor(m_parentStyle->columnRuleColor().isValid() ? m_parentStyle->columnRuleColor() : m_parentStyle->color()); - m_style->setColumnRuleStyle(m_parentStyle->columnRuleStyle()); - m_style->setColumnRuleWidth(m_parentStyle->columnRuleWidth()); - } - else if (isInitial) - m_style->resetColumnRule(); - return; - case CSSPropertyWebkitColumns: - if (isInherit) { - if (m_parentStyle->hasAutoColumnWidth()) - m_style->setHasAutoColumnWidth(); - else - m_style->setColumnWidth(m_parentStyle->columnWidth()); - m_style->setColumnCount(m_parentStyle->columnCount()); - } else if (isInitial) { - m_style->setHasAutoColumnWidth(); - m_style->setColumnCount(RenderStyle::initialColumnCount()); - } - return; - case CSSPropertyWebkitMarquee: - if (valueType != CSSValue::CSS_INHERIT || !m_parentNode) return; - m_style->setMarqueeDirection(m_parentStyle->marqueeDirection()); - m_style->setMarqueeIncrement(m_parentStyle->marqueeIncrement()); - m_style->setMarqueeSpeed(m_parentStyle->marqueeSpeed()); - m_style->setMarqueeLoopCount(m_parentStyle->marqueeLoopCount()); - m_style->setMarqueeBehavior(m_parentStyle->marqueeBehavior()); - return; - case CSSPropertyWebkitMarqueeRepetition: { - HANDLE_INHERIT_AND_INITIAL(marqueeLoopCount, MarqueeLoopCount) - if (!primitiveValue) - return; - if (primitiveValue->getIdent() == CSSValueInfinite) - m_style->setMarqueeLoopCount(-1); // -1 means repeat forever. - else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) - m_style->setMarqueeLoopCount(primitiveValue->getIntValue()); - return; - } - case CSSPropertyWebkitMarqueeSpeed: { - HANDLE_INHERIT_AND_INITIAL(marqueeSpeed, MarqueeSpeed) - if (!primitiveValue) - return; - if (primitiveValue->getIdent()) { - switch (primitiveValue->getIdent()) { - case CSSValueSlow: - m_style->setMarqueeSpeed(500); // 500 msec. - break; - case CSSValueNormal: - m_style->setMarqueeSpeed(85); // 85msec. The WinIE default. - break; - case CSSValueFast: - m_style->setMarqueeSpeed(10); // 10msec. Super fast. - break; - } - } - else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_S) - m_style->setMarqueeSpeed(1000 * primitiveValue->getIntValue()); - else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_MS) - m_style->setMarqueeSpeed(primitiveValue->getIntValue()); - else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) // For scrollamount support. - m_style->setMarqueeSpeed(primitiveValue->getIntValue()); - return; - } - case CSSPropertyWebkitMarqueeIncrement: { - HANDLE_INHERIT_AND_INITIAL(marqueeIncrement, MarqueeIncrement) - if (!primitiveValue) - return; - if (primitiveValue->getIdent()) { - switch (primitiveValue->getIdent()) { - case CSSValueSmall: - m_style->setMarqueeIncrement(Length(1, Fixed)); // 1px. - break; - case CSSValueNormal: - m_style->setMarqueeIncrement(Length(6, Fixed)); // 6px. The WinIE default. - break; - case CSSValueLarge: - m_style->setMarqueeIncrement(Length(36, Fixed)); // 36px. - break; - } - } - else { - bool ok = true; - Length l = convertToLength(primitiveValue, m_style, &ok); - if (ok) - m_style->setMarqueeIncrement(l); - } - return; - } - case CSSPropertyWebkitMarqueeStyle: { - HANDLE_INHERIT_AND_INITIAL(marqueeBehavior, MarqueeBehavior) - if (primitiveValue) - m_style->setMarqueeBehavior(*primitiveValue); - return; - } - case CSSPropertyWebkitMarqueeDirection: { - HANDLE_INHERIT_AND_INITIAL(marqueeDirection, MarqueeDirection) - if (primitiveValue) - m_style->setMarqueeDirection(*primitiveValue); - return; - } - case CSSPropertyWebkitUserDrag: { - HANDLE_INHERIT_AND_INITIAL(userDrag, UserDrag) - if (primitiveValue) - m_style->setUserDrag(*primitiveValue); - return; - } - case CSSPropertyWebkitUserModify: { - HANDLE_INHERIT_AND_INITIAL(userModify, UserModify) - if (primitiveValue) - m_style->setUserModify(*primitiveValue); - return; - } - case CSSPropertyWebkitUserSelect: { - HANDLE_INHERIT_AND_INITIAL(userSelect, UserSelect) - if (primitiveValue) - m_style->setUserSelect(*primitiveValue); - return; - } - case CSSPropertyTextOverflow: { - // This property is supported by WinIE, and so we leave off the "-webkit-" in order to - // work with WinIE-specific pages that use the property. - HANDLE_INHERIT_AND_INITIAL(textOverflow, TextOverflow) - if (!primitiveValue || !primitiveValue->getIdent()) - return; - m_style->setTextOverflow(primitiveValue->getIdent() == CSSValueEllipsis); - return; - } - case CSSPropertyWebkitMarginCollapse: { - if (isInherit) { - m_style->setMarginTopCollapse(m_parentStyle->marginTopCollapse()); - m_style->setMarginBottomCollapse(m_parentStyle->marginBottomCollapse()); - } - else if (isInitial) { - m_style->setMarginTopCollapse(MCOLLAPSE); - m_style->setMarginBottomCollapse(MCOLLAPSE); - } - return; - } - case CSSPropertyWebkitMarginTopCollapse: { - HANDLE_INHERIT_AND_INITIAL(marginTopCollapse, MarginTopCollapse) - if (primitiveValue) - m_style->setMarginTopCollapse(*primitiveValue); - return; - } - case CSSPropertyWebkitMarginBottomCollapse: { - HANDLE_INHERIT_AND_INITIAL(marginBottomCollapse, MarginBottomCollapse) - if (primitiveValue) - m_style->setMarginBottomCollapse(*primitiveValue); - return; - } - - // Apple-specific changes. Do not merge these properties into KHTML. - case CSSPropertyWebkitLineClamp: { - HANDLE_INHERIT_AND_INITIAL(lineClamp, LineClamp) - if (!primitiveValue) - return; - m_style->setLineClamp(primitiveValue->getIntValue(CSSPrimitiveValue::CSS_PERCENTAGE)); - return; - } - case CSSPropertyWebkitHighlight: { - HANDLE_INHERIT_AND_INITIAL(highlight, Highlight); - if (primitiveValue->getIdent() == CSSValueNone) - m_style->setHighlight(nullAtom); - else - m_style->setHighlight(primitiveValue->getStringValue()); - return; - } - case CSSPropertyWebkitBorderFit: { - HANDLE_INHERIT_AND_INITIAL(borderFit, BorderFit); - if (primitiveValue->getIdent() == CSSValueBorder) - m_style->setBorderFit(BorderFitBorder); - else - m_style->setBorderFit(BorderFitLines); - return; - } - case CSSPropertyWebkitTextSizeAdjust: { - HANDLE_INHERIT_AND_INITIAL(textSizeAdjust, TextSizeAdjust) - if (!primitiveValue || !primitiveValue->getIdent()) return; - m_style->setTextSizeAdjust(primitiveValue->getIdent() == CSSValueAuto); - m_fontDirty = true; - return; - } - case CSSPropertyWebkitTextSecurity: { - HANDLE_INHERIT_AND_INITIAL(textSecurity, TextSecurity) - if (primitiveValue) - m_style->setTextSecurity(*primitiveValue); - return; - } -#if ENABLE(DASHBOARD_SUPPORT) - case CSSPropertyWebkitDashboardRegion: { - HANDLE_INHERIT_AND_INITIAL(dashboardRegions, DashboardRegions) - if (!primitiveValue) - return; - - if (primitiveValue->getIdent() == CSSValueNone) { - m_style->setDashboardRegions(RenderStyle::noneDashboardRegions()); - return; - } - - DashboardRegion *region = primitiveValue->getDashboardRegionValue(); - if (!region) - return; - - DashboardRegion *first = region; - while (region) { - Length top = convertToLength (region->top(), m_style); - Length right = convertToLength (region->right(), m_style); - Length bottom = convertToLength (region->bottom(), m_style); - Length left = convertToLength (region->left(), m_style); - if (region->m_isCircle) - m_style->setDashboardRegion(StyleDashboardRegion::Circle, region->m_label, top, right, bottom, left, region == first ? false : true); - else if (region->m_isRectangle) - m_style->setDashboardRegion(StyleDashboardRegion::Rectangle, region->m_label, top, right, bottom, left, region == first ? false : true); - region = region->m_next.get(); - } - - m_element->document()->setHasDashboardRegions(true); - - return; - } -#endif - case CSSPropertyWebkitRtlOrdering: - HANDLE_INHERIT_AND_INITIAL(visuallyOrdered, VisuallyOrdered) - if (!primitiveValue || !primitiveValue->getIdent()) - return; - m_style->setVisuallyOrdered(primitiveValue->getIdent() == CSSValueVisual); - return; - case CSSPropertyWebkitTextStrokeWidth: { - HANDLE_INHERIT_AND_INITIAL(textStrokeWidth, TextStrokeWidth) - float width = 0; - switch (primitiveValue->getIdent()) { - case CSSValueThin: - case CSSValueMedium: - case CSSValueThick: { - double result = 1.0 / 48; - if (primitiveValue->getIdent() == CSSValueMedium) - result *= 3; - else if (primitiveValue->getIdent() == CSSValueThick) - result *= 5; - width = CSSPrimitiveValue::create(result, CSSPrimitiveValue::CSS_EMS)->computeLengthFloat(m_style, zoomFactor); - break; - } - default: - width = primitiveValue->computeLengthFloat(m_style, zoomFactor); - break; - } - m_style->setTextStrokeWidth(width); - return; - } - case CSSPropertyWebkitTransform: { - HANDLE_INHERIT_AND_INITIAL(transform, Transform); - TransformOperations operations; - if (!value->isPrimitiveValue()) { - CSSValueList* list = static_cast<CSSValueList*>(value); - unsigned size = list->length(); - for (unsigned i = 0; i < size; i++) { - WebKitCSSTransformValue* val = static_cast<WebKitCSSTransformValue*>(list->itemWithoutBoundsCheck(i)); - - CSSPrimitiveValue* firstValue = static_cast<CSSPrimitiveValue*>(val->itemWithoutBoundsCheck(0)); - - switch (val->operationType()) { - case WebKitCSSTransformValue::ScaleTransformOperation: - case WebKitCSSTransformValue::ScaleXTransformOperation: - case WebKitCSSTransformValue::ScaleYTransformOperation: { - double sx = 1.0; - double sy = 1.0; - if (val->operationType() == WebKitCSSTransformValue::ScaleYTransformOperation) - sy = firstValue->getDoubleValue(); - else { - sx = firstValue->getDoubleValue(); - if (val->operationType() == WebKitCSSTransformValue::ScaleTransformOperation) { - if (val->length() > 1) { - CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(val->itemWithoutBoundsCheck(1)); - sy = secondValue->getDoubleValue(); - } else - sy = sx; - } - } - operations.append(ScaleTransformOperation::create(sx, sy)); - break; - } - case WebKitCSSTransformValue::TranslateTransformOperation: - case WebKitCSSTransformValue::TranslateXTransformOperation: - case WebKitCSSTransformValue::TranslateYTransformOperation: { - bool ok = true; - Length tx = Length(0, Fixed); - Length ty = Length(0, Fixed); - if (val->operationType() == WebKitCSSTransformValue::TranslateYTransformOperation) - ty = convertToLength(firstValue, m_style, &ok); - else { - tx = convertToLength(firstValue, m_style, &ok); - if (val->operationType() == WebKitCSSTransformValue::TranslateTransformOperation) { - if (val->length() > 1) { - CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(val->itemWithoutBoundsCheck(1)); - ty = convertToLength(secondValue, m_style, &ok); - } - } - } - - if (!ok) - return; - - operations.append(TranslateTransformOperation::create(tx, ty)); - break; - } - case WebKitCSSTransformValue::RotateTransformOperation: { - double angle = firstValue->getDoubleValue(); - if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_RAD) - angle = rad2deg(angle); - else if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_GRAD) - angle = grad2deg(angle); - operations.append(RotateTransformOperation::create(angle)); - break; - } - case WebKitCSSTransformValue::SkewTransformOperation: - case WebKitCSSTransformValue::SkewXTransformOperation: - case WebKitCSSTransformValue::SkewYTransformOperation: { - double angleX = 0; - double angleY = 0; - double angle = firstValue->getDoubleValue(); - if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_RAD) - angle = rad2deg(angle); - else if (firstValue->primitiveType() == CSSPrimitiveValue::CSS_GRAD) - angle = grad2deg(angle); - if (val->operationType() == WebKitCSSTransformValue::SkewYTransformOperation) - angleY = angle; - else { - angleX = angle; - if (val->operationType() == WebKitCSSTransformValue::SkewTransformOperation) { - if (val->length() > 1) { - CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(val->itemWithoutBoundsCheck(1)); - angleY = secondValue->getDoubleValue(); - if (secondValue->primitiveType() == CSSPrimitiveValue::CSS_RAD) - angleY = rad2deg(angle); - else if (secondValue->primitiveType() == CSSPrimitiveValue::CSS_GRAD) - angleY = grad2deg(angle); - } - } - } - operations.append(SkewTransformOperation::create(angleX, angleY)); - break; - } - case WebKitCSSTransformValue::MatrixTransformOperation: { - double a = firstValue->getDoubleValue(); - double b = static_cast<CSSPrimitiveValue*>(val->itemWithoutBoundsCheck(1))->getDoubleValue(); - double c = static_cast<CSSPrimitiveValue*>(val->itemWithoutBoundsCheck(2))->getDoubleValue(); - double d = static_cast<CSSPrimitiveValue*>(val->itemWithoutBoundsCheck(3))->getDoubleValue(); - double e = static_cast<CSSPrimitiveValue*>(val->itemWithoutBoundsCheck(4))->getDoubleValue(); - double f = static_cast<CSSPrimitiveValue*>(val->itemWithoutBoundsCheck(5))->getDoubleValue(); - operations.append(MatrixTransformOperation::create(a, b, c, d, e, f)); - break; - } - case WebKitCSSTransformValue::UnknownTransformOperation: - ASSERT_NOT_REACHED(); - break; - } - } - } - m_style->setTransform(operations); - return; - } - case CSSPropertyWebkitTransformOrigin: - HANDLE_INHERIT_AND_INITIAL(transformOriginX, TransformOriginX) - HANDLE_INHERIT_AND_INITIAL(transformOriginY, TransformOriginY) - return; - case CSSPropertyWebkitTransformOriginX: { - HANDLE_INHERIT_AND_INITIAL(transformOriginX, TransformOriginX) - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); - Length l; - int type = primitiveValue->primitiveType(); - if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) - l = Length(primitiveValue->computeLengthIntForLength(m_style, zoomFactor), Fixed); - else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) - l = Length(primitiveValue->getDoubleValue(), Percent); - else - return; - m_style->setTransformOriginX(l); - break; - } - case CSSPropertyWebkitTransformOriginY: { - HANDLE_INHERIT_AND_INITIAL(transformOriginY, TransformOriginY) - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); - Length l; - int type = primitiveValue->primitiveType(); - if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) - l = Length(primitiveValue->computeLengthIntForLength(m_style, zoomFactor), Fixed); - else if(type == CSSPrimitiveValue::CSS_PERCENTAGE) - l = Length(primitiveValue->getDoubleValue(), Percent); - else - return; - m_style->setTransformOriginY(l); - break; - } - case CSSPropertyWebkitAnimation: - if (isInitial) - m_style->clearAnimations(); - else if (isInherit) - m_style->inheritAnimations(m_parentStyle->animations()); - return; - case CSSPropertyWebkitAnimationDelay: - HANDLE_ANIMATION_VALUE(delay, Delay, value) - return; - case CSSPropertyWebkitAnimationDirection: - HANDLE_ANIMATION_VALUE(direction, Direction, value) - return; - case CSSPropertyWebkitAnimationDuration: - HANDLE_ANIMATION_VALUE(duration, Duration, value) - return; - case CSSPropertyWebkitAnimationIterationCount: - HANDLE_ANIMATION_VALUE(iterationCount, IterationCount, value) - return; - case CSSPropertyWebkitAnimationName: - HANDLE_ANIMATION_VALUE(name, Name, value) - return; - case CSSPropertyWebkitAnimationPlayState: - HANDLE_ANIMATION_VALUE(playState, PlayState, value) - return; - case CSSPropertyWebkitAnimationTimingFunction: - HANDLE_ANIMATION_VALUE(timingFunction, TimingFunction, value) - return; - case CSSPropertyWebkitTransition: - if (isInitial) - m_style->clearTransitions(); - else if (isInherit) - m_style->inheritTransitions(m_parentStyle->transitions()); - return; - case CSSPropertyWebkitTransitionDelay: - HANDLE_TRANSITION_VALUE(delay, Delay, value) - return; - case CSSPropertyWebkitTransitionDuration: - HANDLE_TRANSITION_VALUE(duration, Duration, value) - return; - case CSSPropertyWebkitTransitionProperty: - HANDLE_TRANSITION_VALUE(property, Property, value) - return; - case CSSPropertyWebkitTransitionTimingFunction: - HANDLE_TRANSITION_VALUE(timingFunction, TimingFunction, value) - return; - case CSSPropertyInvalid: - return; - case CSSPropertyFontStretch: - case CSSPropertyPage: - case CSSPropertyQuotes: - case CSSPropertyScrollbar3dlightColor: - case CSSPropertyScrollbarArrowColor: - case CSSPropertyScrollbarDarkshadowColor: - case CSSPropertyScrollbarFaceColor: - case CSSPropertyScrollbarHighlightColor: - case CSSPropertyScrollbarShadowColor: - case CSSPropertyScrollbarTrackColor: - case CSSPropertySize: - case CSSPropertyTextLineThrough: - case CSSPropertyTextLineThroughColor: - case CSSPropertyTextLineThroughMode: - case CSSPropertyTextLineThroughStyle: - case CSSPropertyTextLineThroughWidth: - case CSSPropertyTextOverline: - case CSSPropertyTextOverlineColor: - case CSSPropertyTextOverlineMode: - case CSSPropertyTextOverlineStyle: - case CSSPropertyTextOverlineWidth: - case CSSPropertyTextUnderline: - case CSSPropertyTextUnderlineColor: - case CSSPropertyTextUnderlineMode: - case CSSPropertyTextUnderlineStyle: - case CSSPropertyTextUnderlineWidth: - case CSSPropertyWebkitFontSizeDelta: - case CSSPropertyWebkitMarginStart: - case CSSPropertyWebkitPaddingStart: - case CSSPropertyWebkitTextDecorationsInEffect: - case CSSPropertyWebkitTextStroke: - return; -#if ENABLE(SVG) - default: - // Try the SVG properties - applySVGProperty(id, value); -#endif - } -} - -void CSSStyleSelector::mapFillAttachment(FillLayer* layer, CSSValue* value) -{ - if (value->cssValueType() == CSSValue::CSS_INITIAL) { - layer->setAttachment(FillLayer::initialFillAttachment(layer->type())); - return; - } - - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); - switch (primitiveValue->getIdent()) { - case CSSValueFixed: - layer->setAttachment(false); - break; - case CSSValueScroll: - layer->setAttachment(true); - break; - default: - return; - } -} - -void CSSStyleSelector::mapFillClip(FillLayer* layer, CSSValue* value) -{ - if (value->cssValueType() == CSSValue::CSS_INITIAL) { - layer->setClip(FillLayer::initialFillClip(layer->type())); - return; - } - - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); - layer->setClip(*primitiveValue); -} - -void CSSStyleSelector::mapFillComposite(FillLayer* layer, CSSValue* value) -{ - if (value->cssValueType() == CSSValue::CSS_INITIAL) { - layer->setComposite(FillLayer::initialFillComposite(layer->type())); - return; - } - - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); - layer->setComposite(*primitiveValue); -} - -void CSSStyleSelector::mapFillOrigin(FillLayer* layer, CSSValue* value) -{ - if (value->cssValueType() == CSSValue::CSS_INITIAL) { - layer->setOrigin(FillLayer::initialFillOrigin(layer->type())); - return; - } - - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); - layer->setOrigin(*primitiveValue); -} - -StyleImage* CSSStyleSelector::styleImage(CSSValue* value) -{ - if (value->isImageValue()) - return static_cast<CSSImageValue*>(value)->cachedImage(m_element->document()->docLoader()); - if (value->isImageGeneratorValue()) - return static_cast<CSSImageGeneratorValue*>(value)->generatedImage(); - return 0; -} - -void CSSStyleSelector::mapFillImage(FillLayer* layer, CSSValue* value) -{ - if (value->cssValueType() == CSSValue::CSS_INITIAL) { - layer->setImage(FillLayer::initialFillImage(layer->type())); - return; - } - - layer->setImage(styleImage(value)); -} - -void CSSStyleSelector::mapFillRepeat(FillLayer* layer, CSSValue* value) -{ - if (value->cssValueType() == CSSValue::CSS_INITIAL) { - layer->setRepeat(FillLayer::initialFillRepeat(layer->type())); - return; - } - - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); - layer->setRepeat(*primitiveValue); -} - -void CSSStyleSelector::mapFillSize(FillLayer* layer, CSSValue* value) -{ - LengthSize b = FillLayer::initialFillSize(layer->type()); - - if (value->cssValueType() == CSSValue::CSS_INITIAL) { - layer->setSize(b); - return; - } - - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); - Pair* pair = primitiveValue->getPairValue(); - if (!pair) - return; - - CSSPrimitiveValue* first = static_cast<CSSPrimitiveValue*>(pair->first()); - CSSPrimitiveValue* second = static_cast<CSSPrimitiveValue*>(pair->second()); - - if (!first || !second) - return; - - Length firstLength, secondLength; - int firstType = first->primitiveType(); - int secondType = second->primitiveType(); - - float zoomFactor = m_style->effectiveZoom(); - - if (firstType == CSSPrimitiveValue::CSS_UNKNOWN) - firstLength = Length(Auto); - else if (firstType > CSSPrimitiveValue::CSS_PERCENTAGE && firstType < CSSPrimitiveValue::CSS_DEG) - firstLength = Length(first->computeLengthIntForLength(m_style, zoomFactor), Fixed); - else if (firstType == CSSPrimitiveValue::CSS_PERCENTAGE) - firstLength = Length(first->getDoubleValue(), Percent); - else - return; - - if (secondType == CSSPrimitiveValue::CSS_UNKNOWN) - secondLength = Length(Auto); - else if (secondType > CSSPrimitiveValue::CSS_PERCENTAGE && secondType < CSSPrimitiveValue::CSS_DEG) - secondLength = Length(second->computeLengthIntForLength(m_style, zoomFactor), Fixed); - else if (secondType == CSSPrimitiveValue::CSS_PERCENTAGE) - secondLength = Length(second->getDoubleValue(), Percent); - else - return; - - b.width = firstLength; - b.height = secondLength; - layer->setSize(b); -} - -void CSSStyleSelector::mapFillXPosition(FillLayer* layer, CSSValue* value) -{ - if (value->cssValueType() == CSSValue::CSS_INITIAL) { - layer->setXPosition(FillLayer::initialFillXPosition(layer->type())); - return; - } - - if (!value->isPrimitiveValue()) - return; - - float zoomFactor = m_style->effectiveZoom(); - - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); - Length l; - int type = primitiveValue->primitiveType(); - if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) - l = Length(primitiveValue->computeLengthIntForLength(m_style, zoomFactor), Fixed); - else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) - l = Length(primitiveValue->getDoubleValue(), Percent); - else - return; - layer->setXPosition(l); -} - -void CSSStyleSelector::mapFillYPosition(FillLayer* layer, CSSValue* value) -{ - if (value->cssValueType() == CSSValue::CSS_INITIAL) { - layer->setYPosition(FillLayer::initialFillYPosition(layer->type())); - return; - } - - if (!value->isPrimitiveValue()) - return; - - float zoomFactor = m_style->effectiveZoom(); - - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); - Length l; - int type = primitiveValue->primitiveType(); - if (type > CSSPrimitiveValue::CSS_PERCENTAGE && type < CSSPrimitiveValue::CSS_DEG) - l = Length(primitiveValue->computeLengthIntForLength(m_style, zoomFactor), Fixed); - else if (type == CSSPrimitiveValue::CSS_PERCENTAGE) - l = Length(primitiveValue->getDoubleValue(), Percent); - else - return; - layer->setYPosition(l); -} - -void CSSStyleSelector::mapAnimationDelay(Animation* animation, CSSValue* value) -{ - if (value->cssValueType() == CSSValue::CSS_INITIAL) { - animation->setDelay(RenderStyle::initialAnimationDelay()); - return; - } - - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); - if (primitiveValue->getIdent() == CSSValueNow) - animation->setDelay(0); - else { - if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_S) - animation->setDelay(primitiveValue->getFloatValue()); - else - animation->setDelay(primitiveValue->getFloatValue()/1000.0f); - } -} - -void CSSStyleSelector::mapAnimationDirection(Animation* layer, CSSValue* value) -{ - if (value->cssValueType() == CSSValue::CSS_INITIAL) { - layer->setDirection(RenderStyle::initialAnimationDirection()); - return; - } - - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); - layer->setDirection(primitiveValue->getIdent() == CSSValueAlternate); -} - -void CSSStyleSelector::mapAnimationDuration(Animation* animation, CSSValue* value) -{ - if (value->cssValueType() == CSSValue::CSS_INITIAL) { - animation->setDuration(RenderStyle::initialAnimationDuration()); - return; - } - - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); - if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_S) - animation->setDuration(primitiveValue->getFloatValue()); - else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_MS) - animation->setDuration(primitiveValue->getFloatValue()/1000.0f); -} - -void CSSStyleSelector::mapAnimationIterationCount(Animation* animation, CSSValue* value) -{ - if (value->cssValueType() == CSSValue::CSS_INITIAL) { - animation->setIterationCount(RenderStyle::initialAnimationIterationCount()); - return; - } - - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); - if (primitiveValue->getIdent() == CSSValueInfinite) - animation->setIterationCount(-1); - else - animation->setIterationCount(int(primitiveValue->getFloatValue())); -} - -void CSSStyleSelector::mapAnimationName(Animation* layer, CSSValue* value) -{ - if (value->cssValueType() == CSSValue::CSS_INITIAL) { - layer->setName(RenderStyle::initialAnimationName()); - return; - } - - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); - - if (primitiveValue->getIdent() == CSSValueNone) { - layer->setIsNoneAnimation(true); - } else { - layer->setName(primitiveValue->getStringValue()); - - // resolve to the keyframes - RefPtr<KeyframeList> keyframe = findKeyframeRule(primitiveValue->getStringValue()); - layer->setAnimationKeyframe(keyframe); - } -} - -void CSSStyleSelector::mapAnimationPlayState(Animation* layer, CSSValue* value) -{ - if (value->cssValueType() == CSSValue::CSS_INITIAL) { - layer->setPlayState(RenderStyle::initialAnimationPlayState()); - return; - } - - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); - layer->setPlayState((primitiveValue->getIdent() == CSSValuePaused) ? AnimPlayStatePaused : AnimPlayStatePlaying); -} - -void CSSStyleSelector::mapAnimationProperty(Animation* animation, CSSValue* value) -{ - if (value->cssValueType() == CSSValue::CSS_INITIAL) { - animation->setProperty(RenderStyle::initialAnimationProperty()); - return; - } - - if (!value->isPrimitiveValue()) - return; - - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); - animation->setProperty(static_cast<CSSPropertyID>(primitiveValue->getIdent())); -} - -void CSSStyleSelector::mapAnimationTimingFunction(Animation* animation, CSSValue* value) -{ - if (value->cssValueType() == CSSValue::CSS_INITIAL) { - animation->setTimingFunction(RenderStyle::initialAnimationTimingFunction()); - return; - } - - if (value->isPrimitiveValue()) { - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value); - switch (primitiveValue->getIdent()) { - case CSSValueLinear: - animation->setTimingFunction(TimingFunction(LinearTimingFunction, 0.0, 0.0, 1.0, 1.0)); - break; - case CSSValueEase: - animation->setTimingFunction(TimingFunction()); - break; - case CSSValueEaseIn: - animation->setTimingFunction(TimingFunction(CubicBezierTimingFunction, 0.42, 0.0, 1.0, 1.0)); - break; - case CSSValueEaseOut: - animation->setTimingFunction(TimingFunction(CubicBezierTimingFunction, 0.0, 0.0, 0.58, 1.0)); - break; - case CSSValueEaseInOut: - animation->setTimingFunction(TimingFunction(CubicBezierTimingFunction, 0.42, 0.0, 0.58, 1.0)); - break; - } - return; - } - - if (value->isTimingFunctionValue()) { - CSSTimingFunctionValue* timingFunction = static_cast<CSSTimingFunctionValue*>(value); - animation->setTimingFunction(TimingFunction(CubicBezierTimingFunction, timingFunction->x1(), timingFunction->y1(), timingFunction->x2(), timingFunction->y2())); - } -} - -void CSSStyleSelector::mapNinePieceImage(CSSValue* value, NinePieceImage& image) -{ - // If we're a primitive value, then we are "none" and don't need to alter the empty image at all. - if (!value || value->isPrimitiveValue()) - return; - - // Retrieve the border image value. - CSSBorderImageValue* borderImage = static_cast<CSSBorderImageValue*>(value); - - // Set the image (this kicks off the load). - image.m_image = styleImage(borderImage->imageValue()); - - // Set up a length box to represent our image slices. - LengthBox& l = image.m_slices; - Rect* r = borderImage->m_imageSliceRect.get(); - if (r->top()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) - l.top = Length(r->top()->getDoubleValue(), Percent); - else - l.top = Length(r->top()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); - if (r->bottom()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) - l.bottom = Length(r->bottom()->getDoubleValue(), Percent); - else - l.bottom = Length((int)r->bottom()->getFloatValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); - if (r->left()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) - l.left = Length(r->left()->getDoubleValue(), Percent); - else - l.left = Length(r->left()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); - if (r->right()->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) - l.right = Length(r->right()->getDoubleValue(), Percent); - else - l.right = Length(r->right()->getIntValue(CSSPrimitiveValue::CSS_NUMBER), Fixed); - - // Set the appropriate rules for stretch/round/repeat of the slices - switch (borderImage->m_horizontalSizeRule) { - case CSSValueStretch: - image.m_horizontalRule = StretchImageRule; - break; - case CSSValueRound: - image.m_horizontalRule = RoundImageRule; - break; - default: // CSSValueRepeat - image.m_horizontalRule = RepeatImageRule; - break; - } - - switch (borderImage->m_verticalSizeRule) { - case CSSValueStretch: - image.m_verticalRule = StretchImageRule; - break; - case CSSValueRound: - image.m_verticalRule = RoundImageRule; - break; - default: // CSSValueRepeat - image.m_verticalRule = RepeatImageRule; - break; - } -} - -void CSSStyleSelector::checkForTextSizeAdjust() -{ - if (m_style->textSizeAdjust()) - return; - - FontDescription newFontDescription(m_style->fontDescription()); - newFontDescription.setComputedSize(newFontDescription.specifiedSize()); - m_style->setFontDescription(newFontDescription); -} - -void CSSStyleSelector::checkForZoomChange(RenderStyle* style, RenderStyle* parentStyle) -{ - if (style->effectiveZoom() == parentStyle->effectiveZoom()) - return; - - const FontDescription& childFont = style->fontDescription(); - FontDescription newFontDescription(childFont); - setFontSize(newFontDescription, childFont.specifiedSize()); - style->setFontDescription(newFontDescription); -} - -void CSSStyleSelector::checkForGenericFamilyChange(RenderStyle* style, RenderStyle* parentStyle) -{ - const FontDescription& childFont = style->fontDescription(); - - if (childFont.isAbsoluteSize() || !parentStyle) - return; - - const FontDescription& parentFont = parentStyle->fontDescription(); - - if (childFont.genericFamily() == parentFont.genericFamily()) - return; - - // For now, lump all families but monospace together. - if (childFont.genericFamily() != FontDescription::MonospaceFamily && - parentFont.genericFamily() != FontDescription::MonospaceFamily) - return; - - // We know the parent is monospace or the child is monospace, and that font - // size was unspecified. We want to scale our font size as appropriate. - // If the font uses a keyword size, then we refetch from the table rather than - // multiplying by our scale factor. - float size; - if (childFont.keywordSize()) { - size = fontSizeForKeyword(CSSValueXxSmall + childFont.keywordSize() - 1, style->htmlHacks(), - childFont.genericFamily() == FontDescription::MonospaceFamily); - } else { - Settings* settings = m_checker.m_document->settings(); - float fixedScaleFactor = settings - ? static_cast<float>(settings->defaultFixedFontSize()) / settings->defaultFontSize() - : 1; - size = (parentFont.genericFamily() == FontDescription::MonospaceFamily) ? - childFont.specifiedSize()/fixedScaleFactor : - childFont.specifiedSize()*fixedScaleFactor; - } - - FontDescription newFontDescription(childFont); - setFontSize(newFontDescription, size); - style->setFontDescription(newFontDescription); -} - -void CSSStyleSelector::setFontSize(FontDescription& fontDescription, float size) -{ - fontDescription.setSpecifiedSize(size); - fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(fontDescription.isAbsoluteSize(), size)); -} - -float CSSStyleSelector::getComputedSizeFromSpecifiedSize(bool isAbsoluteSize, float specifiedSize) -{ - // We support two types of minimum font size. The first is a hard override that applies to - // all fonts. This is "minSize." The second type of minimum font size is a "smart minimum" - // that is applied only when the Web page can't know what size it really asked for, e.g., - // when it uses logical sizes like "small" or expresses the font-size as a percentage of - // the user's default font setting. - - // With the smart minimum, we never want to get smaller than the minimum font size to keep fonts readable. - // However we always allow the page to set an explicit pixel size that is smaller, - // since sites will mis-render otherwise (e.g., http://www.gamespot.com with a 9px minimum). - - Settings* settings = m_checker.m_document->settings(); - if (!settings) - return 1.0f; - - int minSize = settings->minimumFontSize(); - int minLogicalSize = settings->minimumLogicalFontSize(); - - float zoomFactor = m_style->effectiveZoom(); - if (m_checker.m_document->frame() && m_checker.m_document->frame()->shouldApplyTextZoom()) - zoomFactor *= m_checker.m_document->frame()->textZoomFactor(); - - float zoomedSize = specifiedSize * zoomFactor; - - // Apply the hard minimum first. We only apply the hard minimum if after zooming we're still too small. - if (zoomedSize < minSize) - zoomedSize = minSize; - - // Now apply the "smart minimum." This minimum is also only applied if we're still too small - // after zooming. The font size must either be relative to the user default or the original size - // must have been acceptable. In other words, we only apply the smart minimum whenever we're positive - // doing so won't disrupt the layout. - if (zoomedSize < minLogicalSize && (specifiedSize >= minLogicalSize || !isAbsoluteSize)) - zoomedSize = minLogicalSize; - - // Also clamp to a reasonable maximum to prevent insane font sizes from causing crashes on various - // platforms (I'm looking at you, Windows.) - return min(1000000.0f, max(zoomedSize, 1.0f)); -} - -const int fontSizeTableMax = 16; -const int fontSizeTableMin = 9; -const int totalKeywords = 8; - -// WinIE/Nav4 table for font sizes. Designed to match the legacy font mapping system of HTML. -static const int quirksFontSizeTable[fontSizeTableMax - fontSizeTableMin + 1][totalKeywords] = -{ - { 9, 9, 9, 9, 11, 14, 18, 28 }, - { 9, 9, 9, 10, 12, 15, 20, 31 }, - { 9, 9, 9, 11, 13, 17, 22, 34 }, - { 9, 9, 10, 12, 14, 18, 24, 37 }, - { 9, 9, 10, 13, 16, 20, 26, 40 }, // fixed font default (13) - { 9, 9, 11, 14, 17, 21, 28, 42 }, - { 9, 10, 12, 15, 17, 23, 30, 45 }, - { 9, 10, 13, 16, 18, 24, 32, 48 } // proportional font default (16) -}; -// HTML 1 2 3 4 5 6 7 -// CSS xxs xs s m l xl xxl -// | -// user pref - -// Strict mode table matches MacIE and Mozilla's settings exactly. -static const int strictFontSizeTable[fontSizeTableMax - fontSizeTableMin + 1][totalKeywords] = -{ - { 9, 9, 9, 9, 11, 14, 18, 27 }, - { 9, 9, 9, 10, 12, 15, 20, 30 }, - { 9, 9, 10, 11, 13, 17, 22, 33 }, - { 9, 9, 10, 12, 14, 18, 24, 36 }, - { 9, 10, 12, 13, 16, 20, 26, 39 }, // fixed font default (13) - { 9, 10, 12, 14, 17, 21, 28, 42 }, - { 9, 10, 13, 15, 18, 23, 30, 45 }, - { 9, 10, 13, 16, 18, 24, 32, 48 } // proportional font default (16) -}; -// HTML 1 2 3 4 5 6 7 -// CSS xxs xs s m l xl xxl -// | -// user pref - -// For values outside the range of the table, we use Todd Fahrner's suggested scale -// factors for each keyword value. -static const float fontSizeFactors[totalKeywords] = { 0.60f, 0.75f, 0.89f, 1.0f, 1.2f, 1.5f, 2.0f, 3.0f }; - -float CSSStyleSelector::fontSizeForKeyword(int keyword, bool quirksMode, bool fixed) const -{ - Settings* settings = m_checker.m_document->settings(); - if (!settings) - return 1.0f; - - int mediumSize = fixed ? settings->defaultFixedFontSize() : settings->defaultFontSize(); - if (mediumSize >= fontSizeTableMin && mediumSize <= fontSizeTableMax) { - // Look up the entry in the table. - int row = mediumSize - fontSizeTableMin; - int col = (keyword - CSSValueXxSmall); - return quirksMode ? quirksFontSizeTable[row][col] : strictFontSizeTable[row][col]; - } - - // Value is outside the range of the table. Apply the scale factor instead. - float minLogicalSize = max(settings->minimumLogicalFontSize(), 1); - return max(fontSizeFactors[keyword - CSSValueXxSmall]*mediumSize, minLogicalSize); -} - -float CSSStyleSelector::largerFontSize(float size, bool quirksMode) const -{ - // FIXME: Figure out where we fall in the size ranges (xx-small to xxx-large) and scale up to - // the next size level. - return size * 1.2f; -} - -float CSSStyleSelector::smallerFontSize(float size, bool quirksMode) const -{ - // FIXME: Figure out where we fall in the size ranges (xx-small to xxx-large) and scale down to - // the next size level. - return size / 1.2f; -} - -static Color colorForCSSValue(int cssValueId) -{ - struct ColorValue { - int cssValueId; - RGBA32 color; - }; - - static const ColorValue colorValues[] = { - { CSSValueAqua, 0xFF00FFFF }, - { CSSValueBlack, 0xFF000000 }, - { CSSValueBlue, 0xFF0000FF }, - { CSSValueFuchsia, 0xFFFF00FF }, - { CSSValueGray, 0xFF808080 }, - { CSSValueGreen, 0xFF008000 }, - { CSSValueGrey, 0xFF808080 }, - { CSSValueLime, 0xFF00FF00 }, - { CSSValueMaroon, 0xFF800000 }, - { CSSValueNavy, 0xFF000080 }, - { CSSValueOlive, 0xFF808000 }, - { CSSValueOrange, 0xFFFFA500 }, - { CSSValuePurple, 0xFF800080 }, - { CSSValueRed, 0xFFFF0000 }, - { CSSValueSilver, 0xFFC0C0C0 }, - { CSSValueTeal, 0xFF008080 }, - { CSSValueTransparent, 0x00000000 }, - { CSSValueWhite, 0xFFFFFFFF }, - { CSSValueYellow, 0xFFFFFF00 }, - { 0, 0 } - }; - - for (const ColorValue* col = colorValues; col->cssValueId; ++col) { - if (col->cssValueId == cssValueId) - return col->color; - } - return theme()->systemColor(cssValueId); -} - -Color CSSStyleSelector::getColorFromPrimitiveValue(CSSPrimitiveValue* primitiveValue) -{ - Color col; - int ident = primitiveValue->getIdent(); - if (ident) { - if (ident == CSSValueWebkitText) - col = m_element->document()->textColor(); - else if (ident == CSSValueWebkitLink) { - const Color& linkColor = m_element->document()->linkColor(); - const Color& visitedColor = m_element->document()->visitedLinkColor(); - if (linkColor == visitedColor) - col = linkColor; - else { - if (pseudoState == PseudoUnknown || pseudoState == PseudoAnyLink) - pseudoState = m_checker.checkPseudoState(m_element); - col = (pseudoState == PseudoLink) ? linkColor : visitedColor; - } - } else if (ident == CSSValueWebkitActivelink) - col = m_element->document()->activeLinkColor(); - else if (ident == CSSValueWebkitFocusRingColor) - col = focusRingColor(); - else if (ident == CSSValueCurrentcolor) - col = m_style->color(); - else - col = colorForCSSValue(ident); - } else if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_RGBCOLOR) - col.setRGB(primitiveValue->getRGBColorValue()); - return col; -} - -bool CSSStyleSelector::hasSelectorForAttribute(const AtomicString &attrname) -{ - return m_selectorAttrs.contains(attrname.impl()); -} - -void CSSStyleSelector::addViewportDependentMediaQueryResult(const MediaQueryExp* expr, bool result) -{ - m_viewportDependentMediaQueryResults.append(new MediaQueryResult(*expr, result)); -} - -bool CSSStyleSelector::affectedByViewportChange() const -{ - unsigned s = m_viewportDependentMediaQueryResults.size(); - for (unsigned i = 0; i < s; i++) { - if (m_medium->eval(&m_viewportDependentMediaQueryResults[i]->m_expression) != m_viewportDependentMediaQueryResults[i]->m_result) - return true; - } - return false; -} - -void CSSStyleSelector::SelectorChecker::allVisitedStateChanged() -{ - if (m_linksCheckedForVisitedState.isEmpty()) - return; - for (Node* node = m_document; node; node = node->traverseNextNode()) { - if (node->isLink()) - node->setChanged(); - } -} - -void CSSStyleSelector::SelectorChecker::visitedStateChanged(unsigned visitedHash) -{ - if (!m_linksCheckedForVisitedState.contains(visitedHash)) - return; - for (Node* node = m_document; node; node = node->traverseNextNode()) { - const AtomicString* attr = linkAttribute(node); - if (attr && m_document->visitedLinkHash(*attr) == visitedHash) - node->setChanged(); - } -} - -} // namespace WebCore diff --git a/webkit/pending/CachedCSSStyleSheet.cpp b/webkit/pending/CachedCSSStyleSheet.cpp deleted file mode 100644 index 8b9ee31..0000000 --- a/webkit/pending/CachedCSSStyleSheet.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de) - Copyright (C) 2001 Dirk Mueller (mueller@kde.org) - Copyright (C) 2002 Waldo Bastian (bastian@kde.org) - Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - 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 "CachedCSSStyleSheet.h" - -#include "CachedResourceClient.h" -#include "CachedResourceClientWalker.h" -#include "TextResourceDecoder.h" -#include "loader.h" -#include <wtf/Vector.h> - -namespace WebCore { - -CachedCSSStyleSheet::CachedCSSStyleSheet(const String& url, const String& charset) - : CachedResource(url, CSSStyleSheet) - , m_decoder(TextResourceDecoder::create("text/css", charset)) -{ - // Prefer text/css but accept any type (dell.com serves a stylesheet - // as text/html; see <http://bugs.webkit.org/show_bug.cgi?id=11451>). - setAccept("text/css,*/*;q=0.1"); -} - -CachedCSSStyleSheet::~CachedCSSStyleSheet() -{ -} - -void CachedCSSStyleSheet::addClient(CachedResourceClient *c) -{ - CachedResource::addClient(c); - - if (!m_loading) - c->setCSSStyleSheet(m_url, m_decoder->encoding().name(), this); -} - -void CachedCSSStyleSheet::setEncoding(const String& chs) -{ - m_decoder->setEncoding(chs, TextResourceDecoder::EncodingFromHTTPHeader); -} - -String CachedCSSStyleSheet::encoding() const -{ - return m_decoder->encoding().name(); -} - -void CachedCSSStyleSheet::data(PassRefPtr<SharedBuffer> data, bool allDataReceived) -{ - if (!allDataReceived) - return; - - m_data = data; - setEncodedSize(m_data.get() ? m_data->size() : 0); - if (m_data.get()) { - m_sheet = m_decoder->decode(m_data->data(), encodedSize()); - m_sheet += m_decoder->flush(); - m_data = 0; // We no longer need the raw buffer. - } - m_loading = false; - checkNotify(); -} - -void CachedCSSStyleSheet::checkNotify() -{ - if (m_loading) - return; - - CachedResourceClientWalker w(m_clients); - while (CachedResourceClient *c = w.next()) - c->setCSSStyleSheet(m_response.url().string(), m_decoder->encoding().name(), this); - -#if USE(LOW_BANDWIDTH_DISPLAY) - // if checkNotify() is called from error(), client's setCSSStyleSheet(...) - // can't find "this" from url, so they can't do clean up if needed. - // call notifyFinished() to make sure they have a chance. - CachedResourceClientWalker n(m_clients); - while (CachedResourceClient* s = n.next()) - s->notifyFinished(this); -#endif -} - -void CachedCSSStyleSheet::error() -{ - m_loading = false; - m_errorOccurred = true; - checkNotify(); -} - -bool CachedCSSStyleSheet::canUseSheet(bool enforceMIMEType) const -{ - if (errorOccurred()) - return false; - - if (!enforceMIMEType) - return true; - - // This check exactly matches Firefox. - String mimeType = response().mimeType(); - return mimeType.isEmpty() || equalIgnoringCase(mimeType, "text/css") || equalIgnoringCase(mimeType, "application/x-unknown-content-type"); -} - -} diff --git a/webkit/pending/CachedResource.h b/webkit/pending/CachedResource.h deleted file mode 100644 index bcd03e0..0000000 --- a/webkit/pending/CachedResource.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de) - Copyright (C) 2001 Dirk Mueller <mueller@kde.org> - Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - Copyright (C) 2004, 2005, 2006, 2007 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. -*/ - -#ifndef CachedResource_h -#define CachedResource_h - -#include "PlatformString.h" -#include "ResourceResponse.h" -#include "SharedBuffer.h" -#include <wtf/HashCountedSet.h> -#include <wtf/Vector.h> -#include <time.h> - -namespace WebCore { - -class Cache; -class CachedResourceClient; -class CacheHandleBase; -class DocLoader; -class Request; - -// A resource that is held in the cache. Classes who want to use this object should derive -// from CachedResourceClient, to get the function calls in case the requested data has arrived. -// This class also does the actual communication with the loader to obtain the resource from the network. -class CachedResource { - friend class Cache; - -public: - enum Type { - ImageResource, - CSSStyleSheet, - Script, - FontResource -#if ENABLE(XSLT) - , XSLStyleSheet -#endif -#if ENABLE(XBL) - , XBL -#endif - }; - - enum Status { - NotCached, // this URL is not cached - Unknown, // let cache decide what to do with it - New, // inserting new item - Pending, // only partially loaded - Cached // regular case - }; - - CachedResource(const String& url, Type); - virtual ~CachedResource(); - - virtual void load(DocLoader* docLoader) { load(docLoader, false, false, true); } - void load(DocLoader*, bool incremental, bool skipCanLoadCheck, bool sendResourceLoadCallbacks); - - virtual void setEncoding(const String&) { } - virtual String encoding() const { return String(); } - virtual void data(PassRefPtr<SharedBuffer> data, bool allDataReceived) = 0; - virtual void error() = 0; - - const String &url() const { return m_url; } - Type type() const { return m_type; } - - virtual void addClient(CachedResourceClient*); - void removeClient(CachedResourceClient*); - bool hasClients() const { return !m_clients.isEmpty(); } - - enum PreloadResult { - PreloadNotReferenced, - PreloadReferenced, - PreloadReferencedWhileLoading, - PreloadReferencedWhileComplete - }; - PreloadResult preloadResult() const { return m_preloadResult; } - void setRequestedFromNetworkingLayer() { m_requestedFromNetworkingLayer = true; } - - virtual void allClientsRemoved() { }; - - unsigned count() const { return m_clients.size(); } - - Status status() const { return m_status; } - - unsigned size() const { return encodedSize() + decodedSize(); } - unsigned encodedSize() const { return m_encodedSize; } - unsigned decodedSize() const { return m_decodedSize; } - - bool isLoaded() const { return !m_loading; } - void setLoading(bool b) { m_loading = b; } - - virtual bool isImage() const { return false; } - - unsigned accessCount() const { return m_accessCount; } - void increaseAccessCount() { m_accessCount++; } - - // Computes the status of an object after loading. - // Updates the expire date on the cache entry file - void finish(); - - // Called by the cache if the object has been removed from the cache - // while still being referenced. This means the object should delete itself - // if the number of clients observing it ever drops to 0. - void setInCache(bool b) { m_inCache = b; } - bool inCache() const { return m_inCache; } - - void setInLiveDecodedResourcesList(bool b) { m_inLiveDecodedResourcesList = b; } - bool inLiveDecodedResourcesList() { return m_inLiveDecodedResourcesList; } - - void setRequest(Request*); - - void setResponse(const ResourceResponse& response) { m_response = response; } - const ResourceResponse& response() const { return m_response; } - - bool canDelete() const { return !hasClients() && !m_request && !m_preloadCount; } - - bool isExpired() const; - - virtual bool schedule() const { return false; } - - // List of acceptable MIME types seperated by ",". - // A MIME type may contain a wildcard, e.g. "text/*". - String accept() const { return m_accept; } - void setAccept(const String& accept) { m_accept = accept; } - - bool errorOccurred() const { return m_errorOccurred; } - bool sendResourceLoadCallbacks() const { return m_sendResourceLoadCallbacks; } - - virtual void destroyDecodedData() {}; - - void setDocLoader(DocLoader* docLoader) { m_docLoader = docLoader; } - -#if PLATFORM(MAC) - SharedBuffer* data() const { return m_data.get(); } -#endif - - bool isPreloaded() const { return m_preloadCount; } - void increasePreloadCount() { ++m_preloadCount; } - void decreasePreloadCount() { ASSERT(m_preloadCount); --m_preloadCount; } - -protected: - void setEncodedSize(unsigned); - void setDecodedSize(unsigned); - void didAccessDecodedData(double timeStamp); - - HashCountedSet<CachedResourceClient*> m_clients; - - String m_url; - String m_accept; - Request* m_request; - - ResourceResponse m_response; - RefPtr<SharedBuffer> m_data; - - Type m_type; - Status m_status; - - bool m_errorOccurred; - -private: - unsigned m_encodedSize; - unsigned m_decodedSize; - unsigned m_accessCount; - unsigned m_inLiveDecodedResourcesList; - double m_lastDecodedAccessTime; // Used as a "thrash guard" in the cache - - bool m_sendResourceLoadCallbacks; - - unsigned m_preloadCount; - PreloadResult m_preloadResult; - bool m_requestedFromNetworkingLayer; - -protected: - bool m_inCache; - bool m_loading; - bool m_expireDateChanged; -#ifndef NDEBUG - bool m_deleted; - unsigned m_lruIndex; -#endif - -private: - CachedResource* m_nextInAllResourcesList; - CachedResource* m_prevInAllResourcesList; - - CachedResource* m_nextInLiveResourcesList; - CachedResource* m_prevInLiveResourcesList; - - DocLoader* m_docLoader; // only non-0 for resources that are not in the cache -}; - -} - -#endif diff --git a/webkit/pending/CachedScript.cpp b/webkit/pending/CachedScript.cpp deleted file mode 100644 index 6a67c6f..0000000 --- a/webkit/pending/CachedScript.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - This file is part of the KDE libraries - - Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de) - Copyright (C) 2001 Dirk Mueller (mueller@kde.org) - Copyright (C) 2002 Waldo Bastian (bastian@kde.org) - Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - 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 "CachedScript.h" - -#include "CachedResourceClient.h" -#include "CachedResourceClientWalker.h" -#include <wtf/Vector.h> - -namespace WebCore { - -CachedScript::CachedScript(const String& url, const String& charset) - : CachedResource(url, Script) - , m_encoding(charset) -{ - // It's javascript we want. - // But some websites think their scripts are <some wrong mimetype here> - // and refuse to serve them if we only accept application/x-javascript. - setAccept("*/*"); - if (!m_encoding.isValid()) - m_encoding = Latin1Encoding(); -} - -CachedScript::~CachedScript() -{ -} - -void CachedScript::addClient(CachedResourceClient* c) -{ - CachedResource::addClient(c); - if (!m_loading) - c->notifyFinished(this); -} - -void CachedScript::setEncoding(const String& chs) -{ - TextEncoding encoding(chs); - if (encoding.isValid()) - m_encoding = encoding; -} - -String CachedScript::encoding() const -{ - return m_encoding.name(); -} - -void CachedScript::data(PassRefPtr<SharedBuffer> data, bool allDataReceived) -{ - if (!allDataReceived) - return; - - m_data = data; - setEncodedSize(m_data.get() ? m_data->size() : 0); - if (m_data.get()) { - m_script = m_encoding.decode(m_data->data(), encodedSize()); - m_data = 0; // We no longer need the raw buffer. - } - m_loading = false; - checkNotify(); -} - -void CachedScript::checkNotify() -{ - if (m_loading) - return; - - CachedResourceClientWalker w(m_clients); - while (CachedResourceClient* c = w.next()) - c->notifyFinished(this); -} - -void CachedScript::error() -{ - m_loading = false; - m_errorOccurred = true; - checkNotify(); -} - -} diff --git a/webkit/pending/CanvasRenderingContext2D.cpp b/webkit/pending/CanvasRenderingContext2D.cpp deleted file mode 100644 index 12cdcd4..0000000 --- a/webkit/pending/CanvasRenderingContext2D.cpp +++ /dev/null @@ -1,1352 +0,0 @@ -/* - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2007 Trolltech ASA - * Copyright (C) 2007 Alp Toker <alp@atoker.com> - * Copyright (C) 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 - * 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 "CanvasRenderingContext2D.h" - -#include "AffineTransform.h" -#include "CSSParser.h" -#include "CachedImage.h" -#include "CanvasGradient.h" -#include "CanvasPattern.h" -#include "CanvasPixelArray.h" -#include "CanvasStyle.h" -#include "CSSPropertyNames.h" -#include "CSSStyleSelector.h" -#include "Document.h" -#include "ExceptionCode.h" -#include "FloatConversion.h" -#include "Frame.h" -#include "GraphicsContext.h" -#include "HTMLCanvasElement.h" -#include "HTMLImageElement.h" -#include "HTMLNames.h" -#include "ImageBuffer.h" -#include "ImageData.h" -#include "KURL.h" -#include "NotImplemented.h" -#include "Page.h" -#include "RenderHTMLCanvas.h" -#include "SecurityOrigin.h" -#include "Settings.h" -#include "TextMetrics.h" -#include <kjs/interpreter.h> -#include <stdio.h> -#include <wtf/MathExtras.h> - -using namespace std; - -namespace WebCore { - -using namespace HTMLNames; - -const char* defaultFont = "10px sans-serif"; - -CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas) - : m_canvas(canvas) - , m_stateStack(1) -#if USE(V8) - , m_peer(0) -#endif -{ -} - -void CanvasRenderingContext2D::ref() -{ - m_canvas->ref(); -} - -void CanvasRenderingContext2D::deref() -{ - m_canvas->deref(); -} - -void CanvasRenderingContext2D::reset() -{ - m_stateStack.resize(1); - m_stateStack.first() = State(); -} - -CanvasRenderingContext2D::State::State() - : m_strokeStyle(CanvasStyle::create("black")) - , m_fillStyle(CanvasStyle::create("black")) - , m_lineWidth(1) - , m_lineCap(ButtCap) - , m_lineJoin(MiterJoin) - , m_miterLimit(10) - , m_shadowBlur(0) - , m_shadowColor("black") - , m_globalAlpha(1) - , m_globalComposite(CompositeSourceOver) - , m_textAlign(StartTextAlign) - , m_textBaseline(AlphabeticTextBaseline) - , m_unparsedFont(defaultFont) - , m_realizedFont(false) -{ -} - -void CanvasRenderingContext2D::save() -{ - ASSERT(m_stateStack.size() >= 1); - m_stateStack.append(state()); - GraphicsContext* c = drawingContext(); - if (!c) - return; - c->save(); -} - -void CanvasRenderingContext2D::restore() -{ - ASSERT(m_stateStack.size() >= 1); - if (m_stateStack.size() <= 1) - return; - m_path.transform(state().m_transform); - m_stateStack.removeLast(); - m_path.transform(state().m_transform.inverse()); - GraphicsContext* c = drawingContext(); - if (!c) - return; - c->restore(); -} - -CanvasStyle* CanvasRenderingContext2D::strokeStyle() const -{ - return state().m_strokeStyle.get(); -} - -void CanvasRenderingContext2D::setStrokeStyle(PassRefPtr<CanvasStyle> style) -{ - if (!style) - return; - - if (m_canvas->originClean()) { - if (CanvasPattern* pattern = style->canvasPattern()) { - if (!pattern->originClean()) - m_canvas->setOriginTainted(); - } - } - - state().m_strokeStyle = style; - GraphicsContext* c = drawingContext(); - if (!c) - return; - state().m_strokeStyle->applyStrokeColor(c); -} - -CanvasStyle* CanvasRenderingContext2D::fillStyle() const -{ - return state().m_fillStyle.get(); -} - -void CanvasRenderingContext2D::setFillStyle(PassRefPtr<CanvasStyle> style) -{ - if (!style) - return; - - if (m_canvas->originClean()) { - if (CanvasPattern* pattern = style->canvasPattern()) { - if (!pattern->originClean()) - m_canvas->setOriginTainted(); - } - } - - state().m_fillStyle = style; - GraphicsContext* c = drawingContext(); - if (!c) - return; - state().m_fillStyle->applyFillColor(c); -} - -float CanvasRenderingContext2D::lineWidth() const -{ - return state().m_lineWidth; -} - -void CanvasRenderingContext2D::setLineWidth(float width) -{ - if (!(width > 0)) - return; - state().m_lineWidth = width; - GraphicsContext* c = drawingContext(); - if (!c) - return; - c->setStrokeThickness(width); -} - -String CanvasRenderingContext2D::lineCap() const -{ - return lineCapName(state().m_lineCap); -} - -void CanvasRenderingContext2D::setLineCap(const String& s) -{ - LineCap cap; - if (!parseLineCap(s, cap)) - return; - state().m_lineCap = cap; - GraphicsContext* c = drawingContext(); - if (!c) - return; - c->setLineCap(cap); -} - -String CanvasRenderingContext2D::lineJoin() const -{ - return lineJoinName(state().m_lineJoin); -} - -void CanvasRenderingContext2D::setLineJoin(const String& s) -{ - LineJoin join; - if (!parseLineJoin(s, join)) - return; - state().m_lineJoin = join; - GraphicsContext* c = drawingContext(); - if (!c) - return; - c->setLineJoin(join); -} - -float CanvasRenderingContext2D::miterLimit() const -{ - return state().m_miterLimit; -} - -void CanvasRenderingContext2D::setMiterLimit(float limit) -{ - if (!(limit > 0)) - return; - state().m_miterLimit = limit; - GraphicsContext* c = drawingContext(); - if (!c) - return; - c->setMiterLimit(limit); -} - -float CanvasRenderingContext2D::shadowOffsetX() const -{ - return state().m_shadowOffset.width(); -} - -void CanvasRenderingContext2D::setShadowOffsetX(float x) -{ - state().m_shadowOffset.setWidth(x); - applyShadow(); -} - -float CanvasRenderingContext2D::shadowOffsetY() const -{ - return state().m_shadowOffset.height(); -} - -void CanvasRenderingContext2D::setShadowOffsetY(float y) -{ - state().m_shadowOffset.setHeight(y); - applyShadow(); -} - -float CanvasRenderingContext2D::shadowBlur() const -{ - return state().m_shadowBlur; -} - -void CanvasRenderingContext2D::setShadowBlur(float blur) -{ - state().m_shadowBlur = blur; - applyShadow(); -} - -String CanvasRenderingContext2D::shadowColor() const -{ - // FIXME: What should this return if you called setShadow with a non-string color? - return state().m_shadowColor; -} - -void CanvasRenderingContext2D::setShadowColor(const String& color) -{ - state().m_shadowColor = color; - applyShadow(); -} - -float CanvasRenderingContext2D::globalAlpha() const -{ - return state().m_globalAlpha; -} - -void CanvasRenderingContext2D::setGlobalAlpha(float alpha) -{ - if (!(alpha >= 0 && alpha <= 1)) - return; - state().m_globalAlpha = alpha; - GraphicsContext* c = drawingContext(); - if (!c) - return; - c->setAlpha(alpha); -} - -String CanvasRenderingContext2D::globalCompositeOperation() const -{ - return compositeOperatorName(state().m_globalComposite); -} - -void CanvasRenderingContext2D::setGlobalCompositeOperation(const String& operation) -{ - CompositeOperator op; - if (!parseCompositeOperator(operation, op)) - return; - state().m_globalComposite = op; - GraphicsContext* c = drawingContext(); - if (!c) - return; - c->setCompositeOperation(op); -} - -void CanvasRenderingContext2D::scale(float sx, float sy) -{ - GraphicsContext* c = drawingContext(); - if (!c) - return; - c->scale(FloatSize(sx, sy)); - state().m_transform.scale(sx, sy); - m_path.transform(AffineTransform().scale(1.0/sx, 1.0/sy)); -} - -void CanvasRenderingContext2D::rotate(float angleInRadians) -{ - GraphicsContext* c = drawingContext(); - if (!c) - return; - c->rotate(angleInRadians); - state().m_transform.rotate(angleInRadians / piDouble * 180.0); - m_path.transform(AffineTransform().rotate(-angleInRadians / piDouble * 180.0)); -} - -void CanvasRenderingContext2D::translate(float tx, float ty) -{ - GraphicsContext* c = drawingContext(); - if (!c) - return; - c->translate(tx, ty); - state().m_transform.translate(tx, ty); - m_path.transform(AffineTransform().translate(-tx, -ty)); -} - -void CanvasRenderingContext2D::transform(float m11, float m12, float m21, float m22, float dx, float dy) -{ - GraphicsContext* c = drawingContext(); - if (!c) - return; - - // HTML5 3.14.11.1 -- ignore any calls that pass non-finite numbers - if (!isfinite(m11) | !isfinite(m21) | !isfinite(dx) | - !isfinite(m12) | !isfinite(m22) | !isfinite(dy)) - return; - AffineTransform transform(m11, m12, m21, m22, dx, dy); - c->concatCTM(transform); - state().m_transform.multiply(transform); - m_path.transform(transform.inverse()); -} - -void CanvasRenderingContext2D::setStrokeColor(const String& color) -{ - setStrokeStyle(CanvasStyle::create(color)); -} - -void CanvasRenderingContext2D::setStrokeColor(float grayLevel) -{ - setStrokeStyle(CanvasStyle::create(grayLevel, 1)); -} - -void CanvasRenderingContext2D::setStrokeColor(const String& color, float alpha) -{ - setStrokeStyle(CanvasStyle::create(color, alpha)); -} - -void CanvasRenderingContext2D::setStrokeColor(float grayLevel, float alpha) -{ - setStrokeStyle(CanvasStyle::create(grayLevel, alpha)); -} - -void CanvasRenderingContext2D::setStrokeColor(float r, float g, float b, float a) -{ - setStrokeStyle(CanvasStyle::create(r, g, b, a)); -} - -void CanvasRenderingContext2D::setStrokeColor(float c, float m, float y, float k, float a) -{ - setStrokeStyle(CanvasStyle::create(c, m, y, k, a)); -} - -void CanvasRenderingContext2D::setFillColor(const String& color) -{ - setFillStyle(CanvasStyle::create(color)); -} - -void CanvasRenderingContext2D::setFillColor(float grayLevel) -{ - setFillStyle(CanvasStyle::create(grayLevel, 1)); -} - -void CanvasRenderingContext2D::setFillColor(const String& color, float alpha) -{ - setFillStyle(CanvasStyle::create(color, 1)); -} - -void CanvasRenderingContext2D::setFillColor(float grayLevel, float alpha) -{ - setFillStyle(CanvasStyle::create(grayLevel, alpha)); -} - -void CanvasRenderingContext2D::setFillColor(float r, float g, float b, float a) -{ - setFillStyle(CanvasStyle::create(r, g, b, a)); -} - -void CanvasRenderingContext2D::setFillColor(float c, float m, float y, float k, float a) -{ - setFillStyle(CanvasStyle::create(c, m, y, k, a)); -} - -void CanvasRenderingContext2D::beginPath() -{ - m_path.clear(); -} - -void CanvasRenderingContext2D::closePath() -{ - m_path.closeSubpath(); -} - -void CanvasRenderingContext2D::moveTo(float x, float y) -{ - if (!isfinite(x) | !isfinite(y)) - return; - m_path.moveTo(FloatPoint(x, y)); -} - -void CanvasRenderingContext2D::lineTo(float x, float y) -{ - if (!isfinite(x) | !isfinite(y)) - return; - m_path.addLineTo(FloatPoint(x, y)); -} - -void CanvasRenderingContext2D::quadraticCurveTo(float cpx, float cpy, float x, float y) -{ - if (!isfinite(cpx) | !isfinite(cpy) | !isfinite(x) | !isfinite(y)) - return; - m_path.addQuadCurveTo(FloatPoint(cpx, cpy), FloatPoint(x, y)); -} - -void CanvasRenderingContext2D::bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y) -{ - if (!isfinite(cp1x) | !isfinite(cp1y) | !isfinite(cp2x) | !isfinite(cp2y) | !isfinite(x) | !isfinite(y)) - return; - m_path.addBezierCurveTo(FloatPoint(cp1x, cp1y), FloatPoint(cp2x, cp2y), FloatPoint(x, y)); -} - -void CanvasRenderingContext2D::arcTo(float x0, float y0, float x1, float y1, float r, ExceptionCode& ec) -{ - ec = 0; - if (!isfinite(x0) | !isfinite(y0) | !isfinite(x1) | !isfinite(y1) | !isfinite(r)) - return; - - if (r < 0) { - ec = INDEX_SIZE_ERR; - return; - } - - m_path.addArcTo(FloatPoint(x0, y0), FloatPoint(x1, y1), r); -} - -void CanvasRenderingContext2D::arc(float x, float y, float r, float sa, float ea, bool anticlockwise, ExceptionCode& ec) -{ - ec = 0; - if (!isfinite(x) | !isfinite(y) | !isfinite(r) | !isfinite(sa) | !isfinite(ea)) - return; - - if (r < 0) { - ec = INDEX_SIZE_ERR; - return; - } - - m_path.addArc(FloatPoint(x, y), r, sa, ea, anticlockwise); -} - -static bool validateRectForCanvas(float& x, float& y, float& width, float& height) -{ - if (!isfinite(x) | !isfinite(y) | !isfinite(width) | !isfinite(height)) - return false; - - if (width < 0) { - width = -width; - x -= width; - } - - if (height < 0) { - height = -height; - y -= height; - } - - return true; -} - -void CanvasRenderingContext2D::rect(float x, float y, float width, float height) -{ - if (!validateRectForCanvas(x, y, width, height)) - return; - - m_path.addRect(FloatRect(x, y, width, height)); -} - -#if ENABLE(DASHBOARD_SUPPORT) -void CanvasRenderingContext2D::clearPathForDashboardBackwardCompatibilityMode() -{ - if (Settings* settings = m_canvas->document()->settings()) - if (settings->usesDashboardBackwardCompatibilityMode()) - m_path.clear(); -} -#endif - -void CanvasRenderingContext2D::fill() -{ - GraphicsContext* c = drawingContext(); - if (!c) - return; - - c->beginPath(); - c->addPath(m_path); - if (!m_path.isEmpty()) - willDraw(m_path.boundingRect()); - - c->fillPath(); - -#if ENABLE(DASHBOARD_SUPPORT) - clearPathForDashboardBackwardCompatibilityMode(); -#endif -} - -void CanvasRenderingContext2D::stroke() -{ - GraphicsContext* c = drawingContext(); - if (!c) - return; - c->beginPath(); - c->addPath(m_path); - - if (!m_path.isEmpty()) { - // FIXME: This is insufficient, need to use CGContextReplacePathWithStrokedPath to expand to required bounds - float lineWidth = state().m_lineWidth; - float inset = lineWidth / 2; - FloatRect boundingRect = m_path.boundingRect(); - boundingRect.inflate(inset); - willDraw(boundingRect); - } - - c->strokePath(); - -#if ENABLE(DASHBOARD_SUPPORT) - clearPathForDashboardBackwardCompatibilityMode(); -#endif -} - -void CanvasRenderingContext2D::clip() -{ - GraphicsContext* c = drawingContext(); - if (!c) - return; - c->clip(m_path); -#if ENABLE(DASHBOARD_SUPPORT) - clearPathForDashboardBackwardCompatibilityMode(); -#endif -} - -bool CanvasRenderingContext2D::isPointInPath(const float x, const float y) -{ - GraphicsContext* c = drawingContext(); - if (!c) - return false; - FloatPoint point(x, y); - // We have to invert the current transform to ensure we correctly handle the - // transforms applied to the current path. - AffineTransform ctm = state().m_transform; - if (!ctm.isInvertible()) - return false; - FloatPoint transformedPoint = ctm.inverse().mapPoint(point); - return m_path.contains(transformedPoint); -} - -void CanvasRenderingContext2D::clearRect(float x, float y, float width, float height) -{ - if (!validateRectForCanvas(x, y, width, height)) - return; - GraphicsContext* c = drawingContext(); - if (!c) - return; - FloatRect rect(x, y, width, height); - willDraw(rect); - c->clearRect(rect); -} - -void CanvasRenderingContext2D::fillRect(float x, float y, float width, float height) -{ - if (!validateRectForCanvas(x, y, width, height)) - return; - - GraphicsContext* c = drawingContext(); - if (!c) - return; - - FloatRect rect(x, y, width, height); - willDraw(rect); - - c->save(); - c->fillRect(rect); - c->restore(); -} - -void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height) -{ - if (!validateRectForCanvas(x, y, width, height)) - return; - strokeRect(x, y, width, height, state().m_lineWidth); -} - -void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float height, float lineWidth) -{ - if (!validateRectForCanvas(x, y, width, height)) - return; - - if (!(lineWidth >= 0)) - return; - - GraphicsContext* c = drawingContext(); - if (!c) - return; - - FloatRect rect(x, y, width, height); - - FloatRect boundingRect = rect; - boundingRect.inflate(lineWidth / 2); - willDraw(boundingRect); - - c->strokeRect(rect, lineWidth); -} - -#if PLATFORM(CG) -static inline CGSize adjustedShadowSize(CGFloat width, CGFloat height) -{ - // Work around <rdar://problem/5539388> by ensuring that shadow offsets will get truncated - // to the desired integer. - static const CGFloat extraShadowOffset = narrowPrecisionToCGFloat(1.0 / 128); - if (width > 0) - width += extraShadowOffset; - else if (width < 0) - width -= extraShadowOffset; - - if (height > 0) - height += extraShadowOffset; - else if (height < 0) - height -= extraShadowOffset; - - return CGSizeMake(width, height); -} -#endif - -void CanvasRenderingContext2D::setShadow(float width, float height, float blur) -{ - state().m_shadowOffset = FloatSize(width, height); - state().m_shadowBlur = blur; - state().m_shadowColor = ""; - applyShadow(); -} - -void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color) -{ - state().m_shadowOffset = FloatSize(width, height); - state().m_shadowBlur = blur; - state().m_shadowColor = color; - applyShadow(); -} - -void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel) -{ - state().m_shadowOffset = FloatSize(width, height); - state().m_shadowBlur = blur; - state().m_shadowColor = ""; - - GraphicsContext* c = drawingContext(); - if (!c) - return; - // FIXME: Do this through platform-independent GraphicsContext API. -#if PLATFORM(CG) - const CGFloat components[2] = { grayLevel, 1 }; - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); - CGColorRef color = CGColorCreate(colorSpace, components); - CGColorSpaceRelease(colorSpace); - CGContextSetShadowWithColor(c->platformContext(), adjustedShadowSize(width, -height), blur, color); - CGColorRelease(color); -#endif -} - -void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color, float alpha) -{ - state().m_shadowOffset = FloatSize(width, height); - state().m_shadowBlur = blur; - state().m_shadowColor = color; - - GraphicsContext* c = drawingContext(); - if (!c) - return; - // FIXME: Do this through platform-independent GraphicsContext API. -#if PLATFORM(CG) - RGBA32 rgba = 0; // default is transparent black - CSSParser::parseColor(rgba, color); - const CGFloat components[4] = { - ((rgba >> 16) & 0xFF) / 255.0f, - ((rgba >> 8) & 0xFF) / 255.0f, - (rgba & 0xFF) / 255.0f, - alpha - }; - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - CGColorRef shadowColor = CGColorCreate(colorSpace, components); - CGColorSpaceRelease(colorSpace); - CGContextSetShadowWithColor(c->platformContext(), adjustedShadowSize(width, -height), blur, shadowColor); - CGColorRelease(shadowColor); -#endif -} - -void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel, float alpha) -{ - state().m_shadowOffset = FloatSize(width, height); - state().m_shadowBlur = blur; - state().m_shadowColor = ""; - - GraphicsContext* c = drawingContext(); - if (!c) - return; - // FIXME: Do this through platform-independent GraphicsContext API. -#if PLATFORM(CG) - const CGFloat components[2] = { grayLevel, alpha }; - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); - CGColorRef color = CGColorCreate(colorSpace, components); - CGColorSpaceRelease(colorSpace); - CGContextSetShadowWithColor(c->platformContext(), adjustedShadowSize(width, -height), blur, color); - CGColorRelease(color); -#endif -} - -void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float r, float g, float b, float a) -{ - state().m_shadowOffset = FloatSize(width, height); - state().m_shadowBlur = blur; - state().m_shadowColor = ""; - - GraphicsContext* c = drawingContext(); - if (!c) - return; - // FIXME: Do this through platform-independent GraphicsContext API. -#if PLATFORM(CG) - const CGFloat components[4] = { r, g, b, a }; - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - CGColorRef shadowColor = CGColorCreate(colorSpace, components); - CGColorSpaceRelease(colorSpace); - CGContextSetShadowWithColor(c->platformContext(), adjustedShadowSize(width, -height), blur, shadowColor); - CGColorRelease(shadowColor); -#endif -} - -void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float c, float m, float y, float k, float a) -{ - state().m_shadowOffset = FloatSize(width, height); - state().m_shadowBlur = blur; - state().m_shadowColor = ""; - - GraphicsContext* dc = drawingContext(); - if (!dc) - return; - // FIXME: Do this through platform-independent GraphicsContext API. -#if PLATFORM(CG) - const CGFloat components[5] = { c, m, y, k, a }; - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceCMYK(); - CGColorRef shadowColor = CGColorCreate(colorSpace, components); - CGColorSpaceRelease(colorSpace); - CGContextSetShadowWithColor(dc->platformContext(), adjustedShadowSize(width, -height), blur, shadowColor); - CGColorRelease(shadowColor); -#endif -} - -void CanvasRenderingContext2D::clearShadow() -{ - state().m_shadowOffset = FloatSize(); - state().m_shadowBlur = 0; - state().m_shadowColor = ""; - applyShadow(); -} - -void CanvasRenderingContext2D::applyShadow() -{ - GraphicsContext* c = drawingContext(); - if (!c) - return; - // FIXME: Do this through platform-independent GraphicsContext API. -#if PLATFORM(CG) - RGBA32 rgba = 0; // default is transparent black - if (!state().m_shadowColor.isEmpty()) - CSSParser::parseColor(rgba, state().m_shadowColor); - const CGFloat components[4] = { - ((rgba >> 16) & 0xFF) / 255.0f, - ((rgba >> 8) & 0xFF) / 255.0f, - (rgba & 0xFF) / 255.0f, - ((rgba >> 24) & 0xFF) / 255.0f - }; - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - CGColorRef color = CGColorCreate(colorSpace, components); - CGColorSpaceRelease(colorSpace); - - CGContextSetShadowWithColor(c->platformContext(), adjustedShadowSize(state().m_shadowOffset.width(), -state().m_shadowOffset.height()), state().m_shadowBlur, color); - CGColorRelease(color); -#endif -} - -static IntSize size(HTMLImageElement* image) -{ - if (CachedImage* cachedImage = image->cachedImage()) - return cachedImage->imageSize(1.0f); // FIXME: Not sure about this. - return IntSize(); -} - -static inline FloatRect normalizeRect(const FloatRect& rect) -{ - return FloatRect(min(rect.x(), rect.right()), - min(rect.y(), rect.bottom()), - max(rect.width(), -rect.width()), - max(rect.height(), -rect.height())); -} - -void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, float x, float y) -{ - ASSERT(image); - IntSize s = size(image); - ExceptionCode ec; - drawImage(image, x, y, s.width(), s.height(), ec); -} - -void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, - float x, float y, float width, float height, ExceptionCode& ec) -{ - ASSERT(image); - IntSize s = size(image); - drawImage(image, FloatRect(0, 0, s.width(), s.height()), FloatRect(x, y, width, height), ec); -} - -void CanvasRenderingContext2D::checkOrigin(const KURL& url) -{ - RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url); - if (!m_canvas->document()->securityOrigin()->canAccess(origin.get())) - m_canvas->setOriginTainted(); -} - -void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRect& srcRect, const FloatRect& dstRect, - ExceptionCode& ec) -{ - ASSERT(image); - - ec = 0; - - FloatRect imageRect = FloatRect(FloatPoint(), size(image)); - if (!imageRect.contains(normalizeRect(srcRect)) || srcRect.width() == 0 || srcRect.height() == 0) { - ec = INDEX_SIZE_ERR; - return; - } - - if (!dstRect.width() || !dstRect.height()) - return; - - GraphicsContext* c = drawingContext(); - if (!c) - return; - - CachedImage* cachedImage = image->cachedImage(); - if (!cachedImage) - return; - - if (m_canvas->originClean()) - checkOrigin(cachedImage->response().url()); - - if (m_canvas->originClean() && !cachedImage->image()->hasSingleSecurityOrigin()) - m_canvas->setOriginTainted(); - - FloatRect sourceRect = c->roundToDevicePixels(srcRect); - FloatRect destRect = c->roundToDevicePixels(dstRect); - willDraw(destRect); - c->drawImage(cachedImage->image(), destRect, sourceRect, state().m_globalComposite); -} - -void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, float x, float y) -{ - ASSERT(canvas); - ExceptionCode ec; - drawImage(canvas, x, y, canvas->width(), canvas->height(), ec); -} - -void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, - float x, float y, float width, float height, ExceptionCode& ec) -{ - ASSERT(canvas); - drawImage(canvas, FloatRect(0, 0, canvas->width(), canvas->height()), FloatRect(x, y, width, height), ec); -} - -void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, const FloatRect& srcRect, - const FloatRect& dstRect, ExceptionCode& ec) -{ - ASSERT(canvas); - - ec = 0; - - FloatRect srcCanvasRect = FloatRect(FloatPoint(), canvas->size()); - if (!srcCanvasRect.contains(normalizeRect(srcRect)) || srcRect.width() == 0 || srcRect.height() == 0) { - ec = INDEX_SIZE_ERR; - return; - } - - if (!dstRect.width() || !dstRect.height()) - return; - - GraphicsContext* c = drawingContext(); - if (!c) - return; - - FloatRect sourceRect = c->roundToDevicePixels(srcRect); - FloatRect destRect = c->roundToDevicePixels(dstRect); - - // FIXME: Do this through platform-independent GraphicsContext API. - ImageBuffer* buffer = canvas->buffer(); - if (!buffer) - return; - - if (!canvas->originClean()) - m_canvas->setOriginTainted(); - - c->drawImage(buffer->image(), destRect, sourceRect, state().m_globalComposite); - willDraw(destRect); // This call comes after drawImage, since the buffer we draw into may be our own, and we need to make sure it is dirty. - // FIXME: Arguably willDraw should become didDraw and occur after drawing calls and not before them to avoid problems like this. -} - -// FIXME: Why isn't this just another overload of drawImage? Why have a different name? -void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image, - float sx, float sy, float sw, float sh, - float dx, float dy, float dw, float dh, - const String& compositeOperation) -{ - if (!image) - return; - - CachedImage* cachedImage = image->cachedImage(); - if (!cachedImage) - return; - - if (m_canvas->originClean()) - checkOrigin(cachedImage->response().url()); - - if (m_canvas->originClean() && !cachedImage->image()->hasSingleSecurityOrigin()) - m_canvas->setOriginTainted(); - - GraphicsContext* c = drawingContext(); - if (!c) - return; - - CompositeOperator op; - if (!parseCompositeOperator(compositeOperation, op)) - op = CompositeSourceOver; - - FloatRect destRect = FloatRect(dx, dy, dw, dh); - willDraw(destRect); - c->drawImage(cachedImage->image(), destRect, FloatRect(sx, sy, sw, sh), op); -} - -void CanvasRenderingContext2D::setAlpha(float alpha) -{ - setGlobalAlpha(alpha); -} - -void CanvasRenderingContext2D::setCompositeOperation(const String& operation) -{ - setGlobalCompositeOperation(operation); -} - -PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createLinearGradient(float x0, float y0, float x1, float y1) -{ - return CanvasGradient::create(FloatPoint(x0, y0), FloatPoint(x1, y1)); -} - -PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1) -{ - return CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1); -} - -PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLImageElement* image, - const String& repetitionType, ExceptionCode& ec) -{ - bool repeatX, repeatY; - ec = 0; - CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec); - if (ec) - return 0; - - if (!image->complete()) { - ec = INVALID_STATE_ERR; - return 0; - } - - CachedImage* cachedImage = image->cachedImage(); - if (!cachedImage || !image->cachedImage()->image()) - return CanvasPattern::create(Image::nullImage(), repeatX, repeatY, true); - - KURL url(cachedImage->url()); - RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url); - bool originClean = m_canvas->document()->securityOrigin()->canAccess(origin.get()); - return CanvasPattern::create(cachedImage->image(), repeatX, repeatY, originClean); -} - -PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLCanvasElement* canvas, - const String& repetitionType, ExceptionCode& ec) -{ - bool repeatX, repeatY; - ec = 0; - CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec); - if (ec) - return 0; - return CanvasPattern::create(canvas->buffer()->image(), repeatX, repeatY, canvas->originClean()); -} - -void CanvasRenderingContext2D::willDraw(const FloatRect& r) -{ - GraphicsContext* c = drawingContext(); - if (!c) - return; - - m_canvas->willDraw(c->getCTM().mapRect(r)); -} - -GraphicsContext* CanvasRenderingContext2D::drawingContext() const -{ - return m_canvas->drawingContext(); -} - -static PassRefPtr<ImageData> createEmptyImageData(const IntSize& size) -{ - PassRefPtr<ImageData> data = ImageData::create(size.width(), size.height()); - memset(data->data()->data().data(), 0, data->data()->length()); - return data; -} - -PassRefPtr<ImageData> CanvasRenderingContext2D::createImageData(float sw, float sh) const -{ - FloatSize unscaledSize(sw, sh); - IntSize scaledSize = m_canvas->convertLogicalToDevice(unscaledSize); - if (scaledSize.width() < 1) - scaledSize.setWidth(1); - if (scaledSize.height() < 1) - scaledSize.setHeight(1); - - return createEmptyImageData(scaledSize); -} - -PassRefPtr<ImageData> CanvasRenderingContext2D::getImageData(float sx, float sy, float sw, float sh, ExceptionCode& ec) const -{ - if (!m_canvas->originClean()) { - ec = SECURITY_ERR; - return 0; - } - - FloatRect unscaledRect(sx, sy, sw, sh); - IntRect scaledRect = m_canvas->convertLogicalToDevice(unscaledRect); - if (scaledRect.width() < 1) - scaledRect.setWidth(1); - if (scaledRect.height() < 1) - scaledRect.setHeight(1); - ImageBuffer* buffer = m_canvas ? m_canvas->buffer() : 0; - if (!buffer) - return createEmptyImageData(scaledRect.size()); - return buffer->getImageData(scaledRect); -} - -void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, ExceptionCode& ec) -{ - if (!data) { - ec = TYPE_MISMATCH_ERR; - return; - } - putImageData(data, dx, dy, 0, 0, data->width(), data->height(), ec); -} - -void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, float dirtyX, float dirtyY, - float dirtyWidth, float dirtyHeight, ExceptionCode& ec) -{ - if (!data) { - ec = TYPE_MISMATCH_ERR; - return; - } - if (!isfinite(dx) || !isfinite(dy) || !isfinite(dirtyX) || - !isfinite(dirtyY) || !isfinite(dirtyWidth) || !isfinite(dirtyHeight)) { - ec = INDEX_SIZE_ERR; - return; - } - - ImageBuffer* buffer = m_canvas->buffer(); - if (!buffer) - return; - - if (dirtyWidth < 0) { - dirtyX += dirtyWidth; - dirtyWidth = -dirtyWidth; - } - - if (dirtyHeight < 0) { - dirtyY += dirtyHeight; - dirtyHeight = -dirtyHeight; - } - - FloatRect clipRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight); - clipRect.intersect(IntRect(0, 0, data->width(), data->height())); - IntSize destOffset(static_cast<int>(dx), static_cast<int>(dy)); - IntRect sourceRect = enclosingIntRect(clipRect); - sourceRect.move(destOffset); - sourceRect.intersect(IntRect(IntPoint(), buffer->size())); - if (sourceRect.isEmpty()) - return; - willDraw(sourceRect); - sourceRect.move(-destOffset); - IntPoint destPoint(destOffset.width(), destOffset.height()); - - buffer->putImageData(data, sourceRect, destPoint); -} - -String CanvasRenderingContext2D::font() const -{ - return state().m_unparsedFont; -} - -void CanvasRenderingContext2D::setFont(const String& newFont) -{ - RefPtr<CSSMutableStyleDeclaration> tempDecl = CSSMutableStyleDeclaration::create(); - CSSParser parser(!m_canvas->document()->inCompatMode()); // Use the parse mode of the canvas' document when parsing CSS. - - String declarationText("font: "); - declarationText += newFont; - parser.parseDeclaration(tempDecl.get(), declarationText); - if (!tempDecl->length()) - return; - - // The parse succeeded. - state().m_unparsedFont = newFont; - - // Map the <canvas> font into the text style. If the font uses keywords like larger/smaller, these will work - // relative to the canvas. - RenderArena* arena = m_canvas->document()->renderArena(); - RenderStyle* newStyle = new (arena) RenderStyle(); - newStyle->ref(); - if (m_canvas->computedStyle()) - newStyle->setFontDescription(m_canvas->computedStyle()->fontDescription()); - - // Now map the font property into the style. - CSSStyleSelector* styleSelector = m_canvas->document()->styleSelector(); - styleSelector->applyPropertyToStyle(CSSPropertyFont, tempDecl->getPropertyCSSValue(CSSPropertyFont).get(), newStyle); - - state().m_font = newStyle->font(); - state().m_font.update(styleSelector->fontSelector()); - state().m_realizedFont = true; - - newStyle->deref(arena); - - // Set the font in the graphics context. - GraphicsContext* c = drawingContext(); - if (!c) - return; - c->setFont(state().m_font); -} - -String CanvasRenderingContext2D::textAlign() const -{ - return textAlignName(state().m_textAlign); -} - -void CanvasRenderingContext2D::setTextAlign(const String& s) -{ - TextAlign align; - if (!parseTextAlign(s, align)) - return; - state().m_textAlign = align; -} - -String CanvasRenderingContext2D::textBaseline() const -{ - return textBaselineName(state().m_textBaseline); -} - -void CanvasRenderingContext2D::setTextBaseline(const String& s) -{ - TextBaseline baseline; - if (!parseTextBaseline(s, baseline)) - return; - state().m_textBaseline = baseline; -} - -void CanvasRenderingContext2D::fillText(const String& text, float x, float y) -{ - drawTextInternal(text, x, y, true); -} - -void CanvasRenderingContext2D::fillText(const String& text, float x, float y, float maxWidth) -{ - drawTextInternal(text, x, y, true, maxWidth, true); -} - -void CanvasRenderingContext2D::strokeText(const String& text, float x, float y) -{ - drawTextInternal(text, x, y, false); -} - -void CanvasRenderingContext2D::strokeText(const String& text, float x, float y, float maxWidth) -{ - drawTextInternal(text, x, y, false, maxWidth, true); -} - -PassRefPtr<TextMetrics> CanvasRenderingContext2D::measureText(const String& text) -{ - RefPtr<TextMetrics> metrics = TextMetrics::create(); - metrics->setWidth(accessFont().width(TextRun(text.characters(), text.length()))); - return metrics; -} - -void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, float y, bool fill, float maxWidth, bool useMaxWidth) -{ - GraphicsContext* c = drawingContext(); - if (!c) - return; - - const Font& font = accessFont(); - - // FIXME: Handle maxWidth. - // FIXME: Need to turn off font smoothing. - - bool rtl = m_canvas->computedStyle() ? m_canvas->computedStyle()->direction() == RTL : false; - bool override = m_canvas->computedStyle() ? m_canvas->computedStyle()->unicodeBidi() == Override : false; - - unsigned length = text.length(); - const UChar* string = text.characters(); - TextRun textRun(string, length, 0, 0, 0, rtl, override, false, false); - - // Draw the item text at the correct point. - FloatPoint location(x, y); - switch (state().m_textBaseline) { - case TopTextBaseline: - case HangingTextBaseline: - location.setY(y + font.ascent()); - break; - case BottomTextBaseline: - case IdeographicTextBaseline: - location.setY(y - font.descent()); - break; - case MiddleTextBaseline: - location.setY(y - font.descent() + font.height() / 2); - break; - case AlphabeticTextBaseline: - default: - // Do nothing. - break; - } - - float width = font.width(TextRun(text, false, 0, 0, rtl, override)); - - TextAlign align = state().m_textAlign; - if (align == StartTextAlign) - align = rtl ? RightTextAlign : LeftTextAlign; - else if (align == EndTextAlign) - align = rtl ? LeftTextAlign : RightTextAlign; - - switch (align) { - case CenterTextAlign: - location.setX(location.x() - width / 2); - break; - case RightTextAlign: - location.setX(location.x() - width); - break; - default: - break; - } - - // The slop built in to this mask rect matches the heuristic used in FontCGWin.cpp for GDI text. - FloatRect textRect = FloatRect(location.x() - font.height() / 2, location.y() - font.ascent() - font.lineGap(), - width + font.height(), font.lineSpacing()); - if (!fill) - textRect.inflate(c->strokeThickness() / 2); - - CanvasStyle* drawStyle = fill ? state().m_fillStyle.get() : state().m_strokeStyle.get(); - if (drawStyle->canvasGradient() || drawStyle->canvasPattern()) { - IntRect maskRect = enclosingIntRect(textRect); - - auto_ptr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size(), false); - - GraphicsContext* maskImageContext = maskImage->context(); - - if (fill) - maskImageContext->setFillColor(Color::black); - else { - maskImageContext->setStrokeColor(Color::black); - maskImageContext->setStrokeThickness(c->strokeThickness()); - } - - maskImageContext->setTextDrawingMode(fill ? cTextFill : cTextStroke); - maskImageContext->translate(-maskRect.x(), -maskRect.y()); - - maskImageContext->setFont(font); - maskImageContext->drawBidiText(textRun, location); - - c->save(); - c->clipToImageBuffer(maskRect, maskImage.get()); - drawStyle->applyFillColor(c); - c->fillRect(maskRect); - c->restore(); - - return; - } - - c->setTextDrawingMode(fill ? cTextFill : cTextStroke); - c->drawBidiText(textRun, location); -} - -const Font& CanvasRenderingContext2D::accessFont() -{ - if (!state().m_realizedFont) - setFont(state().m_unparsedFont); - return state().m_font; -} - -} // namespace WebCore diff --git a/webkit/pending/CanvasRenderingContext2D.h b/webkit/pending/CanvasRenderingContext2D.h deleted file mode 100644 index dfed379..0000000 --- a/webkit/pending/CanvasRenderingContext2D.h +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CanvasRenderingContext2D_h -#define CanvasRenderingContext2D_h - -#include "AffineTransform.h" -#include "FloatSize.h" -#include "Font.h" -#include "GraphicsTypes.h" -#include "Path.h" -#include "PlatformString.h" -#include <wtf/Vector.h> - -#if PLATFORM(CG) -#include <ApplicationServices/ApplicationServices.h> -#endif - -namespace WebCore { - - class CanvasGradient; - class CanvasPattern; - class CanvasStyle; - class FloatRect; - class GraphicsContext; - class HTMLCanvasElement; - class HTMLImageElement; - class ImageData; - class KURL; - class TextMetrics; - - typedef int ExceptionCode; - - class CanvasRenderingContext2D : -#if USE(V8) - Peerable // Already has Noncopyable as a superclass. -#else - Noncopyable -#endif - { - public: - CanvasRenderingContext2D(HTMLCanvasElement*); - - void ref(); - void deref(); - -#if USE(V8) - virtual void setPeer(void* peer) - { - ASSERT(m_peer != peer); - if (peer) - ref(); - else - deref(); - m_peer = peer; - - } - virtual void* peer() const - { - return m_peer; - } -#endif - - HTMLCanvasElement* canvas() const { return m_canvas; } - - CanvasStyle* strokeStyle() const; - void setStrokeStyle(PassRefPtr<CanvasStyle>); - - CanvasStyle* fillStyle() const; - void setFillStyle(PassRefPtr<CanvasStyle>); - - float lineWidth() const; - void setLineWidth(float); - - String lineCap() const; - void setLineCap(const String&); - - String lineJoin() const; - void setLineJoin(const String&); - - float miterLimit() const; - void setMiterLimit(float); - - float shadowOffsetX() const; - void setShadowOffsetX(float); - - float shadowOffsetY() const; - void setShadowOffsetY(float); - - float shadowBlur() const; - void setShadowBlur(float); - - String shadowColor() const; - void setShadowColor(const String&); - - float globalAlpha() const; - void setGlobalAlpha(float); - - String globalCompositeOperation() const; - void setGlobalCompositeOperation(const String&); - - void save(); - void restore(); - - void scale(float sx, float sy); - void rotate(float angleInRadians); - void translate(float tx, float ty); - void transform(float m11, float m12, float m21, float m22, float dx, float dy); - - void setStrokeColor(const String& color); - void setStrokeColor(float grayLevel); - void setStrokeColor(const String& color, float alpha); - void setStrokeColor(float grayLevel, float alpha); - void setStrokeColor(float r, float g, float b, float a); - void setStrokeColor(float c, float m, float y, float k, float a); - - void setFillColor(const String& color); - void setFillColor(float grayLevel); - void setFillColor(const String& color, float alpha); - void setFillColor(float grayLevel, float alpha); - void setFillColor(float r, float g, float b, float a); - void setFillColor(float c, float m, float y, float k, float a); - - void beginPath(); - void closePath(); - - void moveTo(float x, float y); - void lineTo(float x, float y); - void quadraticCurveTo(float cpx, float cpy, float x, float y); - void bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y); - void arcTo(float x0, float y0, float x1, float y1, float radius, ExceptionCode&); - void arc(float x, float y, float r, float sa, float ea, bool clockwise, ExceptionCode&); - void rect(float x, float y, float width, float height); - - void fill(); - void stroke(); - void clip(); - - bool isPointInPath(const float x, const float y); - - void clearRect(float x, float y, float width, float height); - void fillRect(float x, float y, float width, float height); - void strokeRect(float x, float y, float width, float height); - void strokeRect(float x, float y, float width, float height, float lineWidth); - - void setShadow(float width, float height, float blur); - void setShadow(float width, float height, float blur, const String& color); - void setShadow(float width, float height, float blur, float grayLevel); - void setShadow(float width, float height, float blur, const String& color, float alpha); - void setShadow(float width, float height, float blur, float grayLevel, float alpha); - void setShadow(float width, float height, float blur, float r, float g, float b, float a); - void setShadow(float width, float height, float blur, float c, float m, float y, float k, float a); - - void clearShadow(); - - void drawImage(HTMLImageElement*, float x, float y); - void drawImage(HTMLImageElement*, float x, float y, float width, float height, ExceptionCode&); - void drawImage(HTMLImageElement*, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode&); - void drawImage(HTMLCanvasElement*, float x, float y); - void drawImage(HTMLCanvasElement*, float x, float y, float width, float height, ExceptionCode&); - void drawImage(HTMLCanvasElement*, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode&); - - void drawImageFromRect(HTMLImageElement*, float sx, float sy, float sw, float sh, - float dx, float dy, float dw, float dh, const String& compositeOperation); - - void setAlpha(float); - - void setCompositeOperation(const String&); - - PassRefPtr<CanvasGradient> createLinearGradient(float x0, float y0, float x1, float y1); - PassRefPtr<CanvasGradient> createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1); - PassRefPtr<CanvasPattern> createPattern(HTMLImageElement*, const String& repetitionType, ExceptionCode&); - PassRefPtr<CanvasPattern> createPattern(HTMLCanvasElement*, const String& repetitionType, ExceptionCode&); - - PassRefPtr<ImageData> createImageData(float width, float height) const; - PassRefPtr<ImageData> getImageData(float sx, float sy, float sw, float sh, ExceptionCode&) const; - void putImageData(ImageData*, float dx, float dy, ExceptionCode&); - void putImageData(ImageData*, float dx, float dy, float dirtyX, float dirtyY, float dirtyWidth, float dirtyHeight, ExceptionCode&); - - void reset(); - - String font() const; - void setFont(const String&); - - String textAlign() const; - void setTextAlign(const String&); - - String textBaseline() const; - void setTextBaseline(const String&); - - void fillText(const String& text, float x, float y); - void fillText(const String& text, float x, float y, float maxWidth); - void strokeText(const String& text, float x, float y); - void strokeText(const String& text, float x, float y, float maxWidth); - PassRefPtr<TextMetrics> measureText(const String& text); - - private: - struct State { - State(); - - RefPtr<CanvasStyle> m_strokeStyle; - RefPtr<CanvasStyle> m_fillStyle; - float m_lineWidth; - LineCap m_lineCap; - LineJoin m_lineJoin; - float m_miterLimit; - FloatSize m_shadowOffset; - float m_shadowBlur; - String m_shadowColor; - float m_globalAlpha; - CompositeOperator m_globalComposite; - AffineTransform m_transform; - - // Text state. - TextAlign m_textAlign; - TextBaseline m_textBaseline; - - String m_unparsedFont; - Font m_font; - bool m_realizedFont; - }; - Path m_path; - - State& state() { return m_stateStack.last(); } - const State& state() const { return m_stateStack.last(); } - - void applyShadow(); - - void willDraw(const FloatRect&); - - GraphicsContext* drawingContext() const; - - void applyStrokePattern(); - void applyFillPattern(); - - void drawTextInternal(const String& text, float x, float y, bool fill, float maxWidth = 0, bool useMaxWidth = false); - - const Font& accessFont(); - -#if ENABLE(DASHBOARD_SUPPORT) - void clearPathForDashboardBackwardCompatibilityMode(); -#endif - - void checkOrigin(const KURL&); - - HTMLCanvasElement* m_canvas; - Vector<State, 1> m_stateStack; -#if USE(V8) - void* m_peer; -#endif - }; - -} // namespace WebCore - -#endif diff --git a/webkit/pending/CanvasRenderingContext2D.idl b/webkit/pending/CanvasRenderingContext2D.idl deleted file mode 100644 index e1e1e06..0000000 --- a/webkit/pending/CanvasRenderingContext2D.idl +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -module html { - - interface [ - GenerateConstructor, - InterfaceUUID=98fb48ae-7216-489c-862b-8e1217fc4443, - ImplementationUUID=ab4f0781-152f-450e-9546-5b3987491a54 - ] CanvasRenderingContext2D { - - // Web Applications 1.0 draft - - readonly attribute HTMLCanvasElement canvas; - - void save(); - void restore(); - - void scale(in float sx, in float sy); - void rotate(in float angle); - void translate(in float tx, in float ty); - void transform(in float m11, in float m12, in float m21, in float m22, in float dx, in float dy); - - attribute float globalAlpha; - attribute [ConvertNullToNullString] DOMString globalCompositeOperation; - - CanvasGradient createLinearGradient(in float x0, in float y0, in float x1, in float y1); - CanvasGradient createRadialGradient(in float x0, in float y0, in float r0, in float x1, in float y1, in float r1); - - attribute float lineWidth; - attribute [ConvertNullToNullString] DOMString lineCap; - attribute [ConvertNullToNullString] DOMString lineJoin; - attribute float miterLimit; - - attribute float shadowOffsetX; - attribute float shadowOffsetY; - attribute float shadowBlur; - attribute [ConvertNullToNullString] DOMString shadowColor; - - void clearRect(in float x, in float y, in float width, in float height); - void fillRect(in float x, in float y, in float width, in float height); - - void beginPath(); - void closePath(); - void moveTo(in float x, in float y); - void lineTo(in float x, in float y); - void quadraticCurveTo(in float cpx, in float cpy, in float x, in float y); - void bezierCurveTo(in float cp1x, in float cp1y, in float cp2x, in float cp2y, in float x, in float y); - void arcTo(in float x1, in float y1, in float x2, in float y2, in float radius) - raises (DOMException); - void rect(in float x, in float y, in float width, in float height); - void arc(in float x, in float y, in float radius, in float startAngle, in float endAngle, in boolean anticlockwise) - raises (DOMException); - void fill(); - void stroke(); - void clip(); - boolean isPointInPath(in float x, in float y); - - // text - attribute DOMString font; - attribute DOMString textAlign; - attribute DOMString textBaseline; - [Custom] void fillText(/* 4 */); - [Custom] void strokeText(/* 4 */); - TextMetrics measureText(in DOMString text); - - // other - - void setAlpha(in float alpha); - void setCompositeOperation(in DOMString compositeOperation); - - void setLineWidth(in float width); - void setLineCap(in DOMString cap); - void setLineJoin(in DOMString join); - void setMiterLimit(in float limit); - - void clearShadow(); - - [Custom] void setStrokeColor(/* 1 */); - [Custom] void setFillColor(/* 1 */); - [Custom] void strokeRect(/* 4 */); - [Custom] void drawImage(/* 3 */); - [Custom] void drawImageFromRect(/* 10 */); - [Custom] void setShadow(/* 3 */); - [Custom] void createPattern(/* 2 */); - - attribute [Custom] custom strokeStyle; - attribute [Custom] custom fillStyle; - - // pixel manipulation - ImageData createImageData(in float sw, in float sh); - ImageData getImageData(in float sx, in float sy, in float sw, in float sh) - raises(DOMException); - [Custom] void putImageData(/* in ImageData imagedata, in float dx, in float dy [, in float dirtyX, in float dirtyY, in float dirtyWidth, in float dirtyHeight] */); - }; - -} - diff --git a/webkit/pending/CompositeAnimation.h b/webkit/pending/CompositeAnimation.h deleted file mode 100644 index bd7523a..0000000 --- a/webkit/pending/CompositeAnimation.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2007 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CompositeAnimation_h -#define CompositeAnimation_h - -#include "AtomicString.h" - -#include <wtf/HashMap.h> -#include <wtf/Noncopyable.h> - -namespace WebCore { - -class AnimationController; -class RenderStyle; -class RenderObject; -class KeyframeAnimation; -class ImplicitAnimation; - -// A CompositeAnimation represents a collection of animations that are running -// on a single RenderObject, such as a number of properties transitioning at once. -class CompositeAnimation : public Noncopyable { -public: - CompositeAnimation(AnimationController* animationController) - : m_suspended(false) - , m_animationController(animationController) - , m_numStyleAvailableWaiters(0) - { } - - ~CompositeAnimation(); - - RenderStyle* animate(RenderObject*, const RenderStyle* currentStyle, RenderStyle* targetStyle); - - void setAnimating(bool inAnimating); - bool animating(); - - bool hasAnimationForProperty(int prop) const { return m_transitions.contains(prop); } - - void resetTransitions(RenderObject*); - void resetAnimations(RenderObject*); - - void cleanupFinishedAnimations(RenderObject*); - - void setAnimationStartTime(double t); - void setTransitionStartTime(int property, double t); - - void suspendAnimations(); - void resumeAnimations(); - bool suspended() const { return m_suspended; } - - void overrideImplicitAnimations(int property); - void resumeOverriddenImplicitAnimations(int property); - - void styleAvailable(); - - bool isAnimatingProperty(int property, bool isRunningNow) const; - - void setWaitingForStyleAvailable(bool waiting); - -protected: - void updateTransitions(RenderObject* renderer, const RenderStyle* currentStyle, RenderStyle* targetStyle); - void updateKeyframeAnimations(RenderObject* renderer, const RenderStyle* currentStyle, RenderStyle* targetStyle); - - KeyframeAnimation* findKeyframeAnimation(const AtomicString& name); - -private: - typedef HashMap<int, ImplicitAnimation*> CSSPropertyTransitionsMap; - typedef HashMap<AtomicStringImpl*, KeyframeAnimation*> AnimationNameMap; - - CSSPropertyTransitionsMap m_transitions; - AnimationNameMap m_keyframeAnimations; - bool m_suspended; - AnimationController* m_animationController; - uint32_t m_numStyleAvailableWaiters; -}; - -} - -#endif diff --git a/webkit/pending/DOMWindow.cpp b/webkit/pending/DOMWindow.cpp deleted file mode 100644 index fc802c8..0000000 --- a/webkit/pending/DOMWindow.cpp +++ /dev/null @@ -1,1192 +0,0 @@ -/* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "DOMWindow.h" - -#include "BarInfo.h" -#include "CSSComputedStyleDeclaration.h" -#include "CSSRuleList.h" -#include "CSSStyleSelector.h" -#include "CString.h" -#include "Chrome.h" -#include "Console.h" -#include "DOMSelection.h" -#include "Document.h" -#include "Element.h" -#include "ExceptionCode.h" -#include "FloatRect.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "FrameTree.h" -#include "FrameView.h" -#include "HTMLFrameOwnerElement.h" -#include "History.h" -#include "Location.h" -#include "MessageEvent.h" -#include "Navigator.h" -#include "Page.h" -#include "PageGroup.h" -#include "PlatformScreen.h" -#include "PlatformString.h" -#include "Screen.h" -#include "SecurityOrigin.h" -#include "Settings.h" -#include "ScriptController.h" -#include <algorithm> -#include <wtf/MathExtras.h> - -#if ENABLE(DATABASE) -#include "Database.h" -#endif - -#if ENABLE(DOM_STORAGE) -#include "LocalStorage.h" -#include "SessionStorage.h" -#include "Storage.h" -#include "StorageArea.h" -#endif - -#if ENABLE(OFFLINE_WEB_APPLICATIONS) -#include "DOMApplicationCache.h" -#endif - -using std::min; -using std::max; - -#if USE(V8) -#include "Location.h" -#include "Navigator.h" -#include "CString.h" -#include "FloatRect.h" -#include "FrameTree.h" -#include "FrameView.h" -#include "Page.h" -#include "Chrome.h" -#include "WindowFeatures.h" -#include "FrameLoadRequest.h" -#include "ScheduledAction.h" -#include "PausedTimeouts.h" -#include "v8_proxy.h" - -#if PLATFORM(WIN) -#include <windows.h> -#endif // WIN - -#include "CSSHelper.h" // parseURL -#endif // V8 - - -namespace WebCore { - -class PostMessageTimer : public TimerBase { -public: - PostMessageTimer(DOMWindow* window, PassRefPtr<MessageEvent> event, SecurityOrigin* targetOrigin) - : m_window(window) - , m_event(event) - , m_targetOrigin(targetOrigin) - { - } - - MessageEvent* event() const { return m_event.get(); } - SecurityOrigin* targetOrigin() const { return m_targetOrigin.get(); } - -private: - virtual void fired() - { - m_window->postMessageTimerFired(this); - } - - RefPtr<DOMWindow> m_window; - RefPtr<MessageEvent> m_event; - RefPtr<SecurityOrigin> m_targetOrigin; -}; - -// This function: -// 1) Validates the pending changes are not changing to NaN -// 2) Constrains the window rect to no smaller than 100 in each dimension and no -// bigger than the the float rect's dimensions. -// 3) Constrain window rect to within the top and left boundaries of the screen rect -// 4) Constraint the window rect to within the bottom and right boundaries of the -// screen rect. -// 5) Translate the window rect coordinates to be within the coordinate space of -// the screen rect. -void DOMWindow::adjustWindowRect(const FloatRect& screen, FloatRect& window, const FloatRect& pendingChanges) -{ - // Make sure we're in a valid state before adjusting dimensions. - ASSERT(isfinite(screen.x())); - ASSERT(isfinite(screen.y())); - ASSERT(isfinite(screen.width())); - ASSERT(isfinite(screen.height())); - ASSERT(isfinite(window.x())); - ASSERT(isfinite(window.y())); - ASSERT(isfinite(window.width())); - ASSERT(isfinite(window.height())); - - // Update window values if new requested values are not NaN. - if (!isnan(pendingChanges.x())) - window.setX(pendingChanges.x()); - if (!isnan(pendingChanges.y())) - window.setY(pendingChanges.y()); - if (!isnan(pendingChanges.width())) - window.setWidth(pendingChanges.width()); - if (!isnan(pendingChanges.height())) - window.setHeight(pendingChanges.height()); - - // Resize the window to between 100 and the screen width and height. - window.setWidth(min(max(100.0f, window.width()), screen.width())); - window.setHeight(min(max(100.0f, window.height()), screen.height())); - - // Constrain the window position to the screen. - window.setX(max(screen.x(), min(window.x(), screen.right() - window.width()))); - window.setY(max(screen.y(), min(window.y(), screen.bottom() - window.height()))); -} - -#if USE(V8) - -static int lastUsedTimeoutId; -static int timerNestingLevel = 0; -const int kMaxTimerNestingLevel = 5; -const double kMinimumTimerInterval = 0.001; // Change this to speed up Javascript's setTimeout! - -class DOMWindowTimer : public TimerBase { -public: - DOMWindowTimer(int timeoutId, int nestingLevel, - DOMWindow* o, ScheduledAction* a) - : m_timeoutId(timeoutId), m_nestingLevel(nestingLevel), - m_object(o), m_action(a) { } - - virtual ~DOMWindowTimer() { delete m_action; } - - int timeoutId() const { return m_timeoutId; } - - int nestingLevel() const { return m_nestingLevel; } - void setNestingLevel(int n) { m_nestingLevel = n; } - - ScheduledAction* action() const { return m_action; } - ScheduledAction* takeAction() { ScheduledAction* a = m_action; m_action = 0; return a; } - -private: - virtual void fired(); - - int m_timeoutId; - int m_nestingLevel; - DOMWindow* m_object; - ScheduledAction* m_action; -}; - -void DOMWindowTimer::fired() { - timerNestingLevel = m_nestingLevel; - m_object->timerFired(this); - timerNestingLevel = 0; -} - -#endif // V8 - - -DOMWindow::DOMWindow(Frame* frame) - : m_frame(frame) -{ -} - -DOMWindow::~DOMWindow() -{ - if (m_frame) - m_frame->clearFormerDOMWindow(this); -} - -void DOMWindow::disconnectFrame() -{ - m_frame = 0; - clear(); -} - -void DOMWindow::clear() -{ - if (m_screen) - m_screen->disconnectFrame(); - m_screen = 0; - - if (m_selection) - m_selection->disconnectFrame(); - m_selection = 0; - - if (m_history) - m_history->disconnectFrame(); - m_history = 0; - - if (m_locationbar) - m_locationbar->disconnectFrame(); - m_locationbar = 0; - - if (m_menubar) - m_menubar->disconnectFrame(); - m_menubar = 0; - - if (m_personalbar) - m_personalbar->disconnectFrame(); - m_personalbar = 0; - - if (m_scrollbars) - m_scrollbars->disconnectFrame(); - m_scrollbars = 0; - - if (m_statusbar) - m_statusbar->disconnectFrame(); - m_statusbar = 0; - - if (m_toolbar) - m_toolbar->disconnectFrame(); - m_toolbar = 0; - - if (m_console) - m_console->disconnectFrame(); - m_console = 0; - - if (m_navigator) - m_navigator->disconnectFrame(); - m_navigator = 0; - - if (m_location) - m_location->disconnectFrame(); - m_location = 0; - -#if ENABLE(DOM_STORAGE) - if (m_sessionStorage) - m_sessionStorage->disconnectFrame(); - m_sessionStorage = 0; - - if (m_localStorage) - m_localStorage->disconnectFrame(); - m_localStorage = 0; -#endif - -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - if (m_applicationCache) - m_applicationCache->disconnectFrame(); - m_applicationCache = 0; -#endif -} - -Screen* DOMWindow::screen() const -{ - if (!m_screen) - m_screen = Screen::create(m_frame); - return m_screen.get(); -} - -History* DOMWindow::history() const -{ - if (!m_history) - m_history = History::create(m_frame); - return m_history.get(); -} - -BarInfo* DOMWindow::locationbar() const -{ - if (!m_locationbar) - m_locationbar = BarInfo::create(m_frame, BarInfo::Locationbar); - return m_locationbar.get(); -} - -BarInfo* DOMWindow::menubar() const -{ - if (!m_menubar) - m_menubar = BarInfo::create(m_frame, BarInfo::Menubar); - return m_menubar.get(); -} - -BarInfo* DOMWindow::personalbar() const -{ - if (!m_personalbar) - m_personalbar = BarInfo::create(m_frame, BarInfo::Personalbar); - return m_personalbar.get(); -} - -BarInfo* DOMWindow::scrollbars() const -{ - if (!m_scrollbars) - m_scrollbars = BarInfo::create(m_frame, BarInfo::Scrollbars); - return m_scrollbars.get(); -} - -BarInfo* DOMWindow::statusbar() const -{ - if (!m_statusbar) - m_statusbar = BarInfo::create(m_frame, BarInfo::Statusbar); - return m_statusbar.get(); -} - -BarInfo* DOMWindow::toolbar() const -{ - if (!m_toolbar) - m_toolbar = BarInfo::create(m_frame, BarInfo::Toolbar); - return m_toolbar.get(); -} - -Console* DOMWindow::console() const -{ - if (!m_console) - m_console = Console::create(m_frame); - return m_console.get(); -} - -#if ENABLE(OFFLINE_WEB_APPLICATIONS) -DOMApplicationCache* DOMWindow::applicationCache() const -{ - if (!m_applicationCache) - m_applicationCache = DOMApplicationCache::create(m_frame); - return m_applicationCache.get(); -} -#endif - -Navigator* DOMWindow::navigator() const -{ - if (!m_navigator) - m_navigator = Navigator::create(m_frame); - return m_navigator.get(); -} - -Location* DOMWindow::location() const -{ - if (!m_location) - m_location = Location::create(m_frame); - return m_location.get(); -} - -#if ENABLE(DOM_STORAGE) -Storage* DOMWindow::sessionStorage() const -{ - if (m_sessionStorage) - return m_sessionStorage.get(); - - Page* page = m_frame->page(); - if (!page) - return 0; - - Document* document = m_frame->document(); - if (!document) - return 0; - - RefPtr<StorageArea> storageArea = page->sessionStorage()->storageArea(document->securityOrigin()); - m_sessionStorage = Storage::create(m_frame, storageArea.release()); - return m_sessionStorage.get(); -} - -Storage* DOMWindow::localStorage() const -{ - Document* document = this->document(); - if (!document) - return 0; - - Page* page = document->page(); - if (!page) - return 0; - - LocalStorage* localStorage = page->group().localStorage(); - RefPtr<StorageArea> storageArea = localStorage ? localStorage->storageArea(m_frame, document->securityOrigin()) : 0; - if (storageArea) - m_localStorage = Storage::create(m_frame, storageArea.release()); - - return m_localStorage.get(); -} -#endif - -void DOMWindow::postMessage(const String& message, const String& targetOrigin, DOMWindow* source, ExceptionCode& ec) -{ - if (!m_frame) - return; - - // Compute the target origin. We need to do this synchronously in order - // to generate the SYNTAX_ERR exception correctly. - RefPtr<SecurityOrigin> target; - if (targetOrigin != "*") { - target = SecurityOrigin::create(KURL(targetOrigin)); - if (target->isEmpty()) { - ec = SYNTAX_ERR; - return; - } - } - - // Capture the source of the message. We need to do this synchronously - // in order to capture the source of the message correctly. - Document* sourceDocument = source->document(); - if (!sourceDocument) - return; - String sourceOrigin = sourceDocument->securityOrigin()->toString(); - - // Schedule the message. - PostMessageTimer* timer = new PostMessageTimer(this, MessageEvent::create(message, sourceOrigin, "", source), target.get()); - timer->startOneShot(0); -} - -void DOMWindow::postMessageTimerFired(PostMessageTimer* t) -{ - OwnPtr<PostMessageTimer> timer(t); - - if (!document()) - return; - - if (timer->targetOrigin()) { - // Check target origin now since the target document may have changed since the simer was scheduled. - if (!timer->targetOrigin()->isSameSchemeHostPort(document()->securityOrigin())) { - String message = String::format("Unable to post message to %s. Recipient has origin %s.\n", - timer->targetOrigin()->toString().utf8().data(), document()->securityOrigin()->toString().utf8().data()); - console()->addMessage(JSMessageSource, ErrorMessageLevel, message, 0, String()); - return; - } - } - - document()->dispatchWindowEvent(timer->event()); -} - -DOMSelection* DOMWindow::getSelection() -{ - if (!m_selection) - m_selection = DOMSelection::create(m_frame); - return m_selection.get(); -} - -Element* DOMWindow::frameElement() const -{ - if (!m_frame) - return 0; - - return m_frame->ownerElement(); -} - -void DOMWindow::focus() -{ - if (!m_frame) - return; - - m_frame->focusWindow(); -} - -void DOMWindow::blur() -{ - if (!m_frame) - return; - - m_frame->unfocusWindow(); -} - -void DOMWindow::close() -{ - if (!m_frame) - return; - - Settings* settings = m_frame->settings(); - bool allow_scripts_to_close_windows = - (settings && settings->allowScriptsToCloseWindows()); - - if (m_frame->loader()->openedByDOM() - || m_frame->loader()->getHistoryLength() <= 1 - || allow_scripts_to_close_windows) - m_frame->scheduleClose(); -} - -void DOMWindow::print() -{ - if (!m_frame) - return; - - Page* page = m_frame->page(); - if (!page) - return; - - page->chrome()->print(m_frame); -} - -void DOMWindow::stop() -{ - if (!m_frame) - return; - - // Ignores stop() in unload event handlers - if (m_frame->loader()->firingUnloadEvents()) - return; - - // We must check whether the load is complete asynchronously, - // because we might still be parsing the document until the - // callstack unwinds. - m_frame->loader()->stopForUserCancel(true); -} - -void DOMWindow::alert(const String& message) -{ -#if USE(V8) - // Before showing the JavaScript dialog, we give - // the proxy implementation a chance to process any - // pending console messages. - V8Proxy::ProcessConsoleMessages(); -#endif - - if (!m_frame) - return; - - Document* doc = m_frame->document(); - ASSERT(doc); - if (doc) - doc->updateRendering(); - - Page* page = m_frame->page(); - if (!page) - return; - - page->chrome()->runJavaScriptAlert(m_frame, message); -} - -bool DOMWindow::confirm(const String& message) -{ -#if USE(V8) - // Before showing the JavaScript dialog, we give - // the proxy implementation a chance to process any - // pending console messages. - V8Proxy::ProcessConsoleMessages(); -#endif - - if (!m_frame) - return false; - - Document* doc = m_frame->document(); - ASSERT(doc); - if (doc) - doc->updateRendering(); - - Page* page = m_frame->page(); - if (!page) - return false; - - return page->chrome()->runJavaScriptConfirm(m_frame, message); -} - -String DOMWindow::prompt(const String& message, const String& defaultValue) -{ -#if USE(V8) - // Before showing the JavaScript dialog, we give - // the proxy implementation a chance to process any - // pending console messages. - V8Proxy::ProcessConsoleMessages(); -#endif - - if (!m_frame) - return String(); - - Document* doc = m_frame->document(); - ASSERT(doc); - if (doc) - doc->updateRendering(); - - Page* page = m_frame->page(); - if (!page) - return String(); - - String returnValue; - if (page->chrome()->runJavaScriptPrompt(m_frame, message, defaultValue, returnValue)) - return returnValue; - - return String(); -} - -bool DOMWindow::find(const String& string, bool caseSensitive, bool backwards, bool wrap, bool wholeWord, bool searchInFrames, bool showDialog) const -{ - if (!m_frame) - return false; - - // FIXME (13016): Support wholeWord, searchInFrames and showDialog - return m_frame->findString(string, !backwards, caseSensitive, wrap, false); -} - -bool DOMWindow::offscreenBuffering() const -{ - return true; -} - -int DOMWindow::outerHeight() const -{ - if (!m_frame) - return 0; - - Page* page = m_frame->page(); - if (!page) - return 0; - - return static_cast<int>(page->chrome()->windowRect().height()); -} - -int DOMWindow::outerWidth() const -{ - if (!m_frame) - return 0; - - Page* page = m_frame->page(); - if (!page) - return 0; - - return static_cast<int>(page->chrome()->windowRect().width()); -} - -int DOMWindow::innerHeight() const -{ - if (!m_frame) - return 0; - - FrameView* view = m_frame->view(); - if (!view) - return 0; - - return static_cast<int>(view->height() / m_frame->pageZoomFactor()); -} - -int DOMWindow::innerWidth() const -{ - if (!m_frame) - return 0; - - FrameView* view = m_frame->view(); - if (!view) - return 0; - - return static_cast<int>(view->width() / m_frame->pageZoomFactor()); -} - -int DOMWindow::screenX() const -{ - if (!m_frame) - return 0; - - Page* page = m_frame->page(); - if (!page) - return 0; - - return static_cast<int>(page->chrome()->windowRect().x()); -} - -int DOMWindow::screenY() const -{ - if (!m_frame) - return 0; - - Page* page = m_frame->page(); - if (!page) - return 0; - - return static_cast<int>(page->chrome()->windowRect().y()); -} - -int DOMWindow::scrollX() const -{ - if (!m_frame) - return 0; - - FrameView* view = m_frame->view(); - if (!view) - return 0; - - Document* doc = m_frame->document(); - ASSERT(doc); - if (doc) - doc->updateLayoutIgnorePendingStylesheets(); - - return static_cast<int>(view->contentsX() / m_frame->pageZoomFactor()); -} - -int DOMWindow::scrollY() const -{ - if (!m_frame) - return 0; - - FrameView* view = m_frame->view(); - if (!view) - return 0; - - Document* doc = m_frame->document(); - ASSERT(doc); - if (doc) - doc->updateLayoutIgnorePendingStylesheets(); - - return static_cast<int>(view->contentsY() / m_frame->pageZoomFactor()); -} - -bool DOMWindow::closed() const -{ - return !m_frame; -} - -unsigned DOMWindow::length() const -{ - if (!m_frame) - return 0; - - return m_frame->tree()->childCount(); -} - -String DOMWindow::name() const -{ - if (!m_frame) - return String(); - - return m_frame->tree()->name(); -} - -void DOMWindow::setName(const String& string) -{ - if (!m_frame) - return; - - m_frame->tree()->setName(string); -} - -String DOMWindow::status() const -{ - if (!m_frame) - return String(); - - return m_frame->jsStatusBarText(); -} - -void DOMWindow::setStatus(const String& string) -{ - if (!m_frame) - return; - - m_frame->setJSStatusBarText(string); -} - -String DOMWindow::defaultStatus() const -{ - if (!m_frame) - return String(); - - return m_frame->jsDefaultStatusBarText(); -} - -void DOMWindow::setDefaultStatus(const String& string) -{ - if (!m_frame) - return; - - m_frame->setJSDefaultStatusBarText(string); -} - -DOMWindow* DOMWindow::self() const -{ - if (!m_frame) - return 0; - - return m_frame->domWindow(); -} - -DOMWindow* DOMWindow::opener() const -{ - if (!m_frame) - return 0; - - Frame* opener = m_frame->loader()->opener(); - if (!opener) - return 0; - - return opener->domWindow(); -} - -DOMWindow* DOMWindow::parent() const -{ - if (!m_frame) - return 0; - - Frame* parent = m_frame->tree()->parent(true); - if (parent) - return parent->domWindow(); - - return m_frame->domWindow(); -} - -DOMWindow* DOMWindow::top() const -{ - if (!m_frame) - return 0; - - Page* page = m_frame->page(); - if (!page) - return 0; - - return m_frame->tree()->top(true)->domWindow(); -} - -Document* DOMWindow::document() const -{ - if (!m_frame) - return 0; - - ASSERT(m_frame->document()); - return m_frame->document(); -} - -PassRefPtr<CSSStyleDeclaration> DOMWindow::getComputedStyle(Element* elt, const String&) const -{ - if (!elt) - return 0; - - // FIXME: This needs take pseudo elements into account. - return computedStyle(elt); -} - -PassRefPtr<CSSRuleList> DOMWindow::getMatchedCSSRules(Element* elt, const String& pseudoElt, bool authorOnly) const -{ - if (!m_frame) - return 0; - - Document* doc = m_frame->document(); - ASSERT(doc); - if (!doc) - return 0; - - if (!pseudoElt.isEmpty()) - return doc->styleSelector()->pseudoStyleRulesForElement(elt, pseudoElt, authorOnly); - return doc->styleSelector()->styleRulesForElement(elt, authorOnly); -} - -double DOMWindow::devicePixelRatio() const -{ - if (!m_frame) - return 0.0; - - Page* page = m_frame->page(); - if (!page) - return 0.0; - - return page->chrome()->scaleFactor(); -} - -#if USE(V8) - -static void setWindowFeature(const String& keyString, const String& valueString, WindowFeatures& windowFeatures) { - int value; - - if (valueString.length() == 0 || // listing a key with no value is shorthand for key=yes - valueString == "yes") - value = 1; - else - value = valueString.toInt(); - - if (keyString == "left" || keyString == "screenx") { - windowFeatures.xSet = true; - windowFeatures.x = value; - } else if (keyString == "top" || keyString == "screeny") { - windowFeatures.ySet = true; - windowFeatures.y = value; - } else if (keyString == "width" || keyString == "innerwidth") { - windowFeatures.widthSet = true; - windowFeatures.width = value; - } else if (keyString == "height" || keyString == "innerheight") { - windowFeatures.heightSet = true; - windowFeatures.height = value; - } else if (keyString == "menubar") - windowFeatures.menuBarVisible = value; - else if (keyString == "toolbar") - windowFeatures.toolBarVisible = value; - else if (keyString == "location") - windowFeatures.locationBarVisible = value; - else if (keyString == "status") - windowFeatures.statusBarVisible = value; - else if (keyString == "resizable") - windowFeatures.resizable = value; - else if (keyString == "fullscreen") - windowFeatures.fullscreen = value; - else if (keyString == "scrollbars") - windowFeatures.scrollbarsVisible = value; -} - - -void DOMWindow::back() -{ - if (m_history) - m_history->back(); -} - -void DOMWindow::forward() -{ - if (m_history) - m_history->forward(); -} - -Location* DOMWindow::location() -{ - if (!m_location) - m_location = Location::create(m_frame); - return m_location.get(); -} - -void DOMWindow::setLocation(const String& v) { - if (!m_frame) - return; - - Frame* active_frame = ScriptController::retrieveActiveFrame(); - if (!active_frame) - return; - - if (!active_frame->loader()->shouldAllowNavigation(m_frame)) - return; - - if (!parseURL(v).startsWith("javascript:", false) || - ScriptController::isSafeScript(m_frame)) { - String completed_url = active_frame->loader()->completeURL(v).string(); - - m_frame->loader()->scheduleLocationChange(completed_url, - active_frame->loader()->outgoingReferrer(), false, - active_frame->script()->processingUserGesture()); - } -} - -Navigator* DOMWindow::navigator() -{ - if (!m_navigator) - m_navigator = Navigator::create(m_frame); - - return m_navigator.get(); -} - -void DOMWindow::dump(const String& msg) -{ - if (!m_frame) - return; - - m_frame->domWindow()->console()->addMessage(JSMessageSource, - ErrorMessageLevel, msg, 0, m_frame->document()->url()); -} - -void DOMWindow::scheduleClose() -{ - if (!m_frame) - return; - - m_frame->scheduleClose(); -} - -void DOMWindow::timerFired(DOMWindowTimer* timer) { - if (!m_frame) - return; - - // Simple case for non-one-shot timers. - if (timer->isActive()) { - int timeoutId = timer->timeoutId(); - - timer->action()->execute(this); - return; - } - - // Delete timer before executing the action for one-shot timers. - ScheduledAction* action = timer->takeAction(); - m_timeouts.remove(timer->timeoutId()); - delete timer; - action->execute(this); - delete action; -} - - -void DOMWindow::clearAllTimeouts() -{ - deleteAllValues(m_timeouts); - m_timeouts.clear(); -} - -int DOMWindow::installTimeout(ScheduledAction* a, int t, bool singleShot) { - if (!m_frame) - return 0; - - int timeoutId = ++lastUsedTimeoutId; - - // avoid wraparound going negative on us - if (timeoutId <= 0) - timeoutId = 1; - - int nestLevel = timerNestingLevel + 1; - - DOMWindowTimer* timer = new DOMWindowTimer(timeoutId, nestLevel, this, a); - ASSERT(!m_timeouts.get(timeoutId)); - m_timeouts.set(timeoutId, timer); - double interval = max(kMinimumTimerInterval, t * 0.001); - if (singleShot) - timer->startOneShot(interval); - else - timer->startRepeating(interval); - - return timeoutId; -} - -void DOMWindow::clearTimeout(int timeoutId) -{ - // timeout IDs have to be positive, and 0 and -1 are unsafe to - // even look up since they are the empty and deleted value - // respectively - if (timeoutId <= 0) - return; - - delete m_timeouts.take(timeoutId); -} - -void DOMWindow::pauseTimeouts(OwnPtr<PausedTimeouts>& pausedTimeouts) -{ - size_t count = m_timeouts.size(); - if (count == 0) { - pausedTimeouts.clear(); - return; - } - - PausedTimeout* t = new PausedTimeout[count]; - PausedTimeouts* result = new PausedTimeouts(t, count); - - TimeoutsMap::iterator it = m_timeouts.begin(); - for (size_t i = 0; i != count; ++i, ++it) { - int timeoutId = it->first; - DOMWindowTimer* timer = it->second; - t[i].timeoutId = timeoutId; - t[i].nestingLevel = timer->nestingLevel(); - t[i].nextFireInterval = timer->nextFireInterval(); - t[i].repeatInterval = timer->repeatInterval(); - t[i].action = timer->takeAction(); - } - ASSERT(it == m_timeouts.end()); - - deleteAllValues(m_timeouts); - m_timeouts.clear(); - - pausedTimeouts.set(result); -} - -void DOMWindow::resumeTimeouts(OwnPtr<PausedTimeouts>& timeouts) { - if (!timeouts) - return; - size_t count = timeouts->numTimeouts(); - PausedTimeout* array = timeouts->takeTimeouts(); - for (size_t i = 0; i != count; ++i) { - int timeoutId = array[i].timeoutId; - DOMWindowTimer* timer = - new DOMWindowTimer(timeoutId, array[i].nestingLevel, - this, array[i].action); - m_timeouts.set(timeoutId, timer); - timer->start(array[i].nextFireInterval, array[i].repeatInterval); - } - delete[] array; - timeouts.clear(); -} - -#endif // V8 - -void DOMWindow::updateLayout() const { - WebCore::Document* docimpl = m_frame->document(); - if (docimpl) - docimpl->updateLayoutIgnorePendingStylesheets(); -} - -void DOMWindow::moveTo(float x, float y) const { - if (!m_frame || !m_frame->page()) return; - - Page* page = m_frame->page(); - FloatRect fr = page->chrome()->windowRect(); - FloatRect sr = screenAvailableRect(page->mainFrame()->view()); - fr.setLocation(sr.location()); - FloatRect update = fr; - update.move(x, y); - // Security check (the spec talks about UniversalBrowserWrite to disable this check...) - adjustWindowRect(sr, fr, update); - page->chrome()->setWindowRect(fr); -} - -void DOMWindow::moveBy(float x, float y) const { - if (!m_frame || !m_frame->page()) return; - - Page* page = m_frame->page(); - FloatRect fr = page->chrome()->windowRect(); - FloatRect update = fr; - update.move(x, y); - // Security check (the spec talks about UniversalBrowserWrite to disable this check...) - adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update); - page->chrome()->setWindowRect(fr); -} - -void DOMWindow::resizeTo(float x, float y) const { - if (!m_frame || !m_frame->page()) return; - - Page* page = m_frame->page(); - FloatRect fr = page->chrome()->windowRect(); - FloatSize dest = FloatSize(x, y); - FloatRect update(fr.location(), dest); - adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update); - page->chrome()->setWindowRect(fr); -} - -void DOMWindow::resizeBy(float x, float y) const { - if (!m_frame || !m_frame->page()) return; - - Page* page = m_frame->page(); - FloatRect fr = page->chrome()->windowRect(); - FloatSize dest = fr.size() + FloatSize(x, y); - FloatRect update(fr.location(), dest); - adjustWindowRect(screenAvailableRect(page->mainFrame()->view()), fr, update); - page->chrome()->setWindowRect(fr); -} - - -void DOMWindow::scrollTo(int x, int y) const { - if (!m_frame || !m_frame->view()) - return; - - if (m_frame->isDisconnected()) - return; - - updateLayout(); - m_frame->view()->setContentsPos(x, y); -} - -void DOMWindow::scrollBy(int x, int y) const { - if (!m_frame || !m_frame->view()) return; - - updateLayout(); - m_frame->view()->scrollBy(x, y); -} - -#if ENABLE(DATABASE) -PassRefPtr<Database> DOMWindow::openDatabase(const String& name, const String& version, const String& displayName, unsigned long estimatedSize, ExceptionCode& ec) -{ - if (!m_frame) - return 0; - return; - - if (m_frame->isDisconnected()) - return; - - Document* doc = m_frame->document(); - ASSERT(doc); - if (!doc) - return 0; - - return Database::openDatabase(doc, name, version, displayName, estimatedSize, ec); -} -#endif - - -} // namespace WebCore diff --git a/webkit/pending/DOMWindow.h b/webkit/pending/DOMWindow.h deleted file mode 100644 index 4cc00b3..0000000 --- a/webkit/pending/DOMWindow.h +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef DOMWindow_h -#define DOMWindow_h - -#include "KURL.h" -#include "PlatformString.h" -#include "SecurityOrigin.h" -#include <wtf/Forward.h> -#include <wtf/RefCounted.h> - -#if USE(V8) -#include <wtf/HashMap.h> -#endif -#include <wtf/RefPtr.h> - -namespace WebCore { - - class BarInfo; - class CSSRuleList; - class CSSStyleDeclaration; - class Console; - class DOMSelection; - class Database; - class Document; - class Element; - class FloatRect; - class Frame; - class History; - class Location; - class Navigator; - class PostMessageTimer; - class Screen; - class String; - -#if USE(V8) - class ScheduledAction; - class PausedTimeouts; - class DOMWindowTimer; -#endif - -#if ENABLE(DOM_STORAGE) - class SessionStorage; - class Storage; -#endif - -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - class DOMApplicationCache; -#endif - - typedef int ExceptionCode; - - class DOMWindow : public RefCounted<DOMWindow> { - public: - static PassRefPtr<DOMWindow> create(Frame* frame) { return adoptRef(new DOMWindow(frame)); } - virtual ~DOMWindow(); - - Frame* frame() { return m_frame; } - void disconnectFrame(); - - void clear(); - - void setSecurityOrigin(SecurityOrigin* securityOrigin) { m_securityOrigin = securityOrigin; } - SecurityOrigin* securityOrigin() const { return m_securityOrigin.get(); } - - void setURL(const KURL& url) { m_url = url; } - KURL url() const { return m_url; } - - static void adjustWindowRect(const FloatRect& screen, FloatRect& window, const FloatRect& pendingChanges); - - // DOM Level 0 - Screen* screen() const; - History* history() const; - BarInfo* locationbar() const; - BarInfo* menubar() const; - BarInfo* personalbar() const; - BarInfo* scrollbars() const; - BarInfo* statusbar() const; - BarInfo* toolbar() const; - Navigator* navigator() const; - Navigator* clientInformation() const { return navigator(); } - Location* location() const; - - DOMSelection* getSelection(); - - Element* frameElement() const; - - void focus(); - void blur(); - void close(); - void print(); - void stop(); - - void alert(const String& message); - bool confirm(const String& message); - String prompt(const String& message, const String& defaultValue); - - bool find(const String&, bool caseSensitive, bool backwards, bool wrap, bool wholeWord, bool searchInFrames, bool showDialog) const; - - bool offscreenBuffering() const; - - int outerHeight() const; - int outerWidth() const; - int innerHeight() const; - int innerWidth() const; - int screenX() const; - int screenY() const; - int screenLeft() const { return screenX(); } - int screenTop() const { return screenY(); } - int scrollX() const; - int scrollY() const; - int pageXOffset() const { return scrollX(); } - int pageYOffset() const { return scrollY(); } - - bool closed() const; - - unsigned length() const; - - String name() const; - void setName(const String&); - - String status() const; - void setStatus(const String&); - String defaultStatus() const; - void setDefaultStatus(const String&); - // This attribute is an alias of defaultStatus and is necessary for legacy uses. - String defaultstatus() const { return defaultStatus(); } - void setDefaultstatus(const String& status) { setDefaultStatus(status); } - - // Self referential attributes - DOMWindow* self() const; - DOMWindow* window() const { return self(); } - DOMWindow* frames() const { return self(); } - - DOMWindow* opener() const; - DOMWindow* parent() const; - DOMWindow* top() const; - - // DOM Level 2 AbstractView Interface - Document* document() const; - - // DOM Level 2 Style Interface - PassRefPtr<CSSStyleDeclaration> getComputedStyle(Element*, const String& pseudoElt) const; - - // WebKit extensions - PassRefPtr<CSSRuleList> getMatchedCSSRules(Element*, const String& pseudoElt, bool authorOnly = true) const; - double devicePixelRatio() const; - -#if ENABLE(DATABASE) - // HTML 5 client-side database - PassRefPtr<Database> openDatabase(const String& name, const String& version, const String& displayName, unsigned long estimatedSize, ExceptionCode&); -#endif - -#if ENABLE(DOM_STORAGE) - // HTML 5 key/value storage - Storage* sessionStorage() const; - Storage* localStorage() const; -#endif - - Console* console() const; - -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - DOMApplicationCache* applicationCache() const; -#endif - - void postMessage(const String& message, const String& targetOrigin, DOMWindow* source, ExceptionCode&); - void postMessageTimerFired(PostMessageTimer*); - - void scrollBy(int x, int y) const; - void scrollTo(int x, int y) const; - void scroll(int x, int y) const { scrollTo(x, y); } - - void moveBy(float x, float y) const; - void moveTo(float x, float y) const; - - void resizeBy(float x, float y) const; - void resizeTo(float width, float height) const; - - // These methods are used for GC marking. See JSDOMWindow::mark() in - // JSDOMWindowCustom.cpp. - Screen* optionalScreen() const { return m_screen.get(); } - DOMSelection* optionalSelection() const { return m_selection.get(); } - History* optionalHistory() const { return m_history.get(); } - BarInfo* optionalLocationbar() const { return m_locationbar.get(); } - BarInfo* optionalMenubar() const { return m_menubar.get(); } - BarInfo* optionalPersonalbar() const { return m_personalbar.get(); } - BarInfo* optionalScrollbars() const { return m_scrollbars.get(); } - BarInfo* optionalStatusbar() const { return m_statusbar.get(); } - BarInfo* optionalToolbar() const { return m_toolbar.get(); } - Console* optionalConsole() const { return m_console.get(); } - Navigator* optionalNavigator() const { return m_navigator.get(); } - Location* optionalLocation() const { return m_location.get(); } -#if ENABLE(DOM_STORAGE) - Storage* optionalSessionStorage() const { return m_sessionStorage.get(); } - Storage* optionalLocalStorage() const { return m_sessionStorage.get(); } -#endif -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - DOMApplicationCache* optionalApplicationCache() const { return m_applicationCache.get(); } -#endif - - private: - DOMWindow(Frame*); - - RefPtr<SecurityOrigin> m_securityOrigin; - KURL m_url; - - Frame* m_frame; - mutable RefPtr<Screen> m_screen; - mutable RefPtr<DOMSelection> m_selection; - mutable RefPtr<History> m_history; - mutable RefPtr<BarInfo> m_locationbar; - mutable RefPtr<BarInfo> m_menubar; - mutable RefPtr<BarInfo> m_personalbar; - mutable RefPtr<BarInfo> m_scrollbars; - mutable RefPtr<BarInfo> m_statusbar; - mutable RefPtr<BarInfo> m_toolbar; - mutable RefPtr<Console> m_console; - mutable RefPtr<Navigator> m_navigator; - mutable RefPtr<Location> m_location; -#if ENABLE(DOM_STORAGE) - mutable RefPtr<Storage> m_sessionStorage; - mutable RefPtr<Storage> m_localStorage; -#endif -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - mutable RefPtr<DOMApplicationCache> m_applicationCache; -#endif - - private: - void updateLayout() const; - - -#if USE(V8) - public: - // DOM methods & attributes for Window. - - DOMWindow* open(const String& url = "", - const String& name = "_blank", - const String& options = ""); - - void back(); - void forward(); - - Navigator* navigator(); - void dump(const String&); - - Location* location(); - - // Change the current window location to a new location. - // The function checks domain security. - void setLocation(const String& loc); - -// void home(); -// void stop(); - - void clearTimeout(int id); - void clearInterval(int id) { clearTimeout(id); } - - void timerFired(DOMWindowTimer* timer); - -// void updateCommands(const String&); -// -// String escape(const String&); -// String unescape(const String&); - - int installTimeout(ScheduledAction* a, int t, bool singleShot); - - void scheduleClose(); - void clearAllTimeouts(); - - void pauseTimeouts(OwnPtr<PausedTimeouts>&); - void resumeTimeouts(OwnPtr<PausedTimeouts>&); - - private: - typedef HashMap<int, DOMWindowTimer*> TimeoutsMap; - TimeoutsMap m_timeouts; -#endif - }; - -} // namespace WebCore - -#endif diff --git a/webkit/pending/Document.cpp b/webkit/pending/Document.cpp deleted file mode 100644 index 15c5952..0000000 --- a/webkit/pending/Document.cpp +++ /dev/null @@ -1,4455 +0,0 @@ -/* - * 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 "Document.h" - -#include "AnimationController.h" -#include "AXObjectCache.h" -#include "CDATASection.h" -#include "CSSHelper.h" -#include "CSSStyleSelector.h" -#include "CSSStyleSheet.h" -#include "CSSValueKeywords.h" -#include "CString.h" -#include "CachedCSSStyleSheet.h" -#include "Comment.h" -#include "CookieJar.h" -#include "DOMImplementation.h" -#include "DOMWindow.h" -#include "DocLoader.h" -#include "DocumentFragment.h" -#include "DocumentLoader.h" -#include "DocumentType.h" -#include "EditingText.h" -#include "Editor.h" -#include "EntityReference.h" -#include "Event.h" -#include "EventHandler.h" -#include "EventListener.h" -#include "EventNames.h" -#include "ExceptionCode.h" -#include "FocusController.h" -#include "FontCache.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "FrameTree.h" -#include "FrameView.h" -#include "HTMLBodyElement.h" -#include "HTMLCanvasElement.h" -#include "HTMLDocument.h" -#include "HTMLElementFactory.h" -#include "HTMLFrameOwnerElement.h" -#include "HTMLHeadElement.h" -#include "HTMLImageLoader.h" -#include "HTMLInputElement.h" -#include "HTMLLinkElement.h" -#include "HTMLMapElement.h" -#include "HTMLNameCollection.h" -#include "HTMLNames.h" -#include "HTMLStyleElement.h" -#include "HTMLTitleElement.h" -#include "HTTPParsers.h" -#include "HistoryItem.h" -#include "HitTestRequest.h" -#include "HitTestResult.h" -#include "KeyboardEvent.h" -#include "Logging.h" -#include "MessageEvent.h" -#include "MouseEvent.h" -#include "MouseEventWithHitTestResults.h" -#include "MutationEvent.h" -#include "NameNodeList.h" -#include "NodeFilter.h" -#include "NodeIterator.h" -#include "NodeWithIndex.h" -#include "OverflowEvent.h" -#include "Page.h" -#include "PlatformKeyboardEvent.h" -#include "ProcessingInstruction.h" -#include "ProgressEvent.h" -#include "RegisteredEventListener.h" -#include "RegularExpression.h" -#include "RenderArena.h" -#include "RenderView.h" -#include "RenderWidget.h" -#include "SecurityOrigin.h" -#include "SegmentedString.h" -#include "SelectionController.h" -#include "Settings.h" -#include "StringHash.h" -#include "StyleSheetList.h" -#include "SystemTime.h" -#include "TextEvent.h" -#include "TextIterator.h" -#include "TextResourceDecoder.h" -#include "TreeWalker.h" -#include "UIEvent.h" -#include "WheelEvent.h" -#include "XMLHttpRequest.h" -#include "XMLNames.h" -#include "XMLTokenizer.h" -#include "ScriptController.h" - -#if USE(JSC) -#include <kjs/JSLock.h> -#include "JSDOMBinding.h" -#endif - -#if ENABLE(DATABASE) -#include "Database.h" -#include "DatabaseThread.h" -#endif - -#if ENABLE(XPATH) -#include "XPathEvaluator.h" -#include "XPathExpression.h" -#include "XPathNSResolver.h" -#include "XPathResult.h" -#endif - -#if ENABLE(XSLT) -#include "XSLTProcessor.h" -#endif - -#if ENABLE(XBL) -#include "XBLBindingManager.h" -#endif - -#if ENABLE(SVG) -#include "SVGDocumentExtensions.h" -#include "SVGElementFactory.h" -#include "SVGZoomEvent.h" -#include "SVGStyleElement.h" -#endif - -#if defined(__APPLE__) -// we need to be PLATFORM(CHROMIUM) for this file, even if we're not building -// that particular target, for the a11y ifdefs. -#define WTF_PLATFORM_CHROMIUM 1 -#endif - -using namespace std; -using namespace WTF; -using namespace Unicode; - -namespace WebCore { - -using namespace EventNames; -using namespace HTMLNames; - -// #define INSTRUMENT_LAYOUT_SCHEDULING 1 - -// This amount of time must have elapsed before we will even consider scheduling a layout without a delay. -// FIXME: For faster machines this value can really be lowered to 200. 250 is adequate, but a little high -// for dual G5s. :) -static const int cLayoutScheduleThreshold = 250; - -// Use 1 to represent the document's default form. -static HTMLFormElement* const defaultForm = reinterpret_cast<HTMLFormElement*>(1); - -// Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's -static const unsigned PHI = 0x9e3779b9U; - -// DOM Level 2 says (letters added): -// -// a) Name start characters must have one of the categories Ll, Lu, Lo, Lt, Nl. -// b) Name characters other than Name-start characters must have one of the categories Mc, Me, Mn, Lm, or Nd. -// c) Characters in the compatibility area (i.e. with character code greater than #xF900 and less than #xFFFE) are not allowed in XML names. -// d) Characters which have a font or compatibility decomposition (i.e. those with a "compatibility formatting tag" in field 5 of the database -- marked by field 5 beginning with a "<") are not allowed. -// e) The following characters are treated as name-start characters rather than name characters, because the property file classifies them as Alphabetic: [#x02BB-#x02C1], #x0559, #x06E5, #x06E6. -// f) Characters #x20DD-#x20E0 are excluded (in accordance with Unicode, section 5.14). -// g) Character #x00B7 is classified as an extender, because the property list so identifies it. -// h) Character #x0387 is added as a name character, because #x00B7 is its canonical equivalent. -// i) Characters ':' and '_' are allowed as name-start characters. -// j) Characters '-' and '.' are allowed as name characters. -// -// It also contains complete tables. If we decide it's better, we could include those instead of the following code. - -static inline bool isValidNameStart(UChar32 c) -{ - // rule (e) above - if ((c >= 0x02BB && c <= 0x02C1) || c == 0x559 || c == 0x6E5 || c == 0x6E6) - return true; - - // rule (i) above - if (c == ':' || c == '_') - return true; - - // rules (a) and (f) above - const uint32_t nameStartMask = Letter_Lowercase | Letter_Uppercase | Letter_Other | Letter_Titlecase | Number_Letter; - if (!(Unicode::category(c) & nameStartMask)) - return false; - - // rule (c) above - if (c >= 0xF900 && c < 0xFFFE) - return false; - - // rule (d) above - DecompositionType decompType = decompositionType(c); - if (decompType == DecompositionFont || decompType == DecompositionCompat) - return false; - - return true; -} - -static inline bool isValidNamePart(UChar32 c) -{ - // rules (a), (e), and (i) above - if (isValidNameStart(c)) - return true; - - // rules (g) and (h) above - if (c == 0x00B7 || c == 0x0387) - return true; - - // rule (j) above - if (c == '-' || c == '.') - return true; - - // rules (b) and (f) above - const uint32_t otherNamePartMask = Mark_NonSpacing | Mark_Enclosing | Mark_SpacingCombining | Letter_Modifier | Number_DecimalDigit; - if (!(Unicode::category(c) & otherNamePartMask)) - return false; - - // rule (c) above - if (c >= 0xF900 && c < 0xFFFE) - return false; - - // rule (d) above - DecompositionType decompType = decompositionType(c); - if (decompType == DecompositionFont || decompType == DecompositionCompat) - return false; - - return true; -} - -static Widget* widgetForNode(Node* focusedNode) -{ - if (!focusedNode) - return 0; - RenderObject* renderer = focusedNode->renderer(); - if (!renderer || !renderer->isWidget()) - return 0; - return static_cast<RenderWidget*>(renderer)->widget(); -} - -static bool acceptsEditingFocus(Node *node) -{ - ASSERT(node); - ASSERT(node->isContentEditable()); - - Node *root = node->rootEditableElement(); - Frame* frame = node->document()->frame(); - if (!frame || !root) - return false; - - return frame->editor()->shouldBeginEditing(rangeOfContents(root).get()); -} - -static HashSet<Document*>* changedDocuments = 0; - -Document::Document(Frame* frame, bool isXHTML) - : ContainerNode(0) - , m_domtree_version(0) - , m_styleSheets(StyleSheetList::create(this)) - , m_title("") - , m_titleSetExplicitly(false) - , m_imageLoadEventTimer(this, &Document::imageLoadEventTimerFired) - , m_updateFocusAppearanceTimer(this, &Document::updateFocusAppearanceTimerFired) -#if ENABLE(XSLT) - , m_transformSource(0) -#endif - , m_xmlVersion("1.0") - , m_xmlStandalone(false) - , m_dominantScript(USCRIPT_INVALID_CODE) -#if ENABLE(XBL) - , m_bindingManager(new XBLBindingManager(this)) -#endif - , m_savedRenderer(0) - , m_secureForms(0) - , m_designMode(inherit) - , m_selfOnlyRefCount(0) -#if ENABLE(SVG) - , m_svgExtensions(0) -#endif -#if ENABLE(DASHBOARD_SUPPORT) - , m_hasDashboardRegions(false) - , m_dashboardRegionsDirty(false) -#endif - , m_accessKeyMapValid(false) - , m_createRenderers(true) - , m_inPageCache(false) - , m_useSecureKeyboardEntryWhenActive(false) - , m_isXHTML(isXHTML) - , m_numNodeListCaches(0) -#if ENABLE(DATABASE) - , m_hasOpenDatabases(false) -#endif -#if USE(LOW_BANDWIDTH_DISPLAY) - , m_inLowBandwidthDisplay(false) -#endif -{ - m_document.resetSkippingRef(this); - - m_printing = false; - - m_ignoreAutofocus = false; - - m_frame = frame; - m_renderArena = 0; - - m_axObjectCache = 0; - - m_docLoader = new DocLoader(this); - - visuallyOrdered = false; - m_bParsing = false; - m_docChanged = false; - m_tokenizer = 0; - m_wellFormed = false; - - setParseMode(Strict); - - m_textColor = Color::black; - m_listenerTypes = 0; - m_inDocument = true; - m_inStyleRecalc = false; - m_closeAfterStyleRecalc = false; - m_usesDescendantRules = false; - m_usesSiblingRules = false; - m_usesFirstLineRules = false; - m_usesFirstLetterRules = false; - m_gotoAnchorNeededAfterStylesheetsLoad = false; - - m_styleSelector = 0; - m_didCalculateStyleSelector = false; - m_pendingStylesheets = 0; - m_ignorePendingStylesheets = false; - m_hasNodesWithPlaceholderStyle = false; - m_pendingSheetLayout = NoLayoutWithPendingSheets; - - m_cssTarget = 0; - - resetLinkColor(); - resetVisitedLinkColor(); - resetActiveLinkColor(); - - m_processingLoadEvent = false; - m_startTime = currentTime(); - m_overMinimumLayoutThreshold = false; - - initSecurityContext(); - initDNSPrefetchEnabled(); - - static int docID = 0; - m_docID = docID++; -} - -void Document::removedLastRef() -{ - ASSERT(!m_deletionHasBegun); - if (m_selfOnlyRefCount) { - // If removing a child removes the last self-only ref, we don't - // want the document to be destructed until after - // removeAllChildren returns, so we guard ourselves with an - // extra self-only ref. - - DocPtr<Document> guard(this); - - // We must make sure not to be retaining any of our children through - // these extra pointers or we will create a reference cycle. - m_docType = 0; - m_focusedNode = 0; - m_hoverNode = 0; - m_activeNode = 0; - m_titleElement = 0; - m_documentElement = 0; - - removeAllChildren(); - - deleteAllValues(m_markers); - m_markers.clear(); - - delete m_tokenizer; - m_tokenizer = 0; - -#ifndef NDEBUG - m_inRemovedLastRefFunction = false; -#endif - } else { -#ifndef NDEBUG - m_deletionHasBegun = true; -#endif - delete this; - } -} - -Document::~Document() -{ - ASSERT(!renderer()); - ASSERT(!m_inPageCache); - ASSERT(!m_savedRenderer); - ASSERT(m_ranges.isEmpty()); - - removeAllEventListeners(); - -#if ENABLE(SVG) - delete m_svgExtensions; -#endif - - XMLHttpRequest::detachRequests(this); -#if USE(JSC) - { - KJS::JSLock lock(false); - ScriptInterpreter::forgetAllDOMNodesForDocument(this); - } -#endif - - if (m_docChanged && changedDocuments) - changedDocuments->remove(this); - delete m_tokenizer; - m_document.resetSkippingRef(0); - delete m_styleSelector; - delete m_docLoader; - - if (m_renderArena) { - delete m_renderArena; - m_renderArena = 0; - } - -#if ENABLE(XSLT) - xmlFreeDoc((xmlDocPtr)m_transformSource); -#endif - -#if ENABLE(XBL) - delete m_bindingManager; -#endif - - deleteAllValues(m_markers); - - clearAXObjectCache(); - - m_decoder = 0; - - unsigned count = sizeof(m_nameCollectionInfo) / sizeof(m_nameCollectionInfo[0]); - for (unsigned i = 0; i < count; i++) - deleteAllValues(m_nameCollectionInfo[i]); - -#if ENABLE(DATABASE) - if (m_databaseThread) { - ASSERT(m_databaseThread->terminationRequested()); - m_databaseThread = 0; - } -#endif - - if (m_styleSheets) - m_styleSheets->documentDestroyed(); - - m_document = 0; -} - -void Document::resetLinkColor() -{ - m_linkColor = Color(0, 0, 238); -} - -void Document::resetVisitedLinkColor() -{ - m_visitedLinkColor = Color(85, 26, 139); -} - -void Document::resetActiveLinkColor() -{ - m_activeLinkColor.setNamedColor("red"); -} - -void Document::setDocType(PassRefPtr<DocumentType> docType) -{ - // This should never be called more than once. - // Note: This is not a public DOM method and can only be called by the parser. - ASSERT(!m_docType || !docType); - if (m_docType && docType) - return; - m_docType = docType; - if (m_docType) - m_docType->setDocument(this); - determineParseMode(); -} - -DOMImplementation* Document::implementation() const -{ - if (!m_implementation) - m_implementation = DOMImplementation::create(); - return m_implementation.get(); -} - -void Document::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) -{ - ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); - - // Invalidate the document element we have cached in case it was replaced. - m_documentElement = 0; -} - -Element* Document::documentElement() const -{ - if (!m_documentElement) { - Node* n = firstChild(); - while (n && !n->isElementNode()) - n = n->nextSibling(); - m_documentElement = static_cast<Element*>(n); - } - - return m_documentElement.get(); -} - -PassRefPtr<Element> Document::createElement(const AtomicString& name, ExceptionCode& ec) -{ - if (!isValidName(name)) { - ec = INVALID_CHARACTER_ERR; - return 0; - } - - if (m_isXHTML) - return HTMLElementFactory::createHTMLElement(name, this, 0, false); - - return createElement(QualifiedName(nullAtom, name, nullAtom), false, ec); -} - -PassRefPtr<DocumentFragment> Document::createDocumentFragment() -{ - return new DocumentFragment(document()); -} - -PassRefPtr<Text> Document::createTextNode(const String& data) -{ - return new Text(this, data); -} - -PassRefPtr<Comment> Document::createComment(const String& data) -{ - return new Comment(this, data); -} - -PassRefPtr<CDATASection> Document::createCDATASection(const String& data, ExceptionCode& ec) -{ - if (isHTMLDocument()) { - ec = NOT_SUPPORTED_ERR; - return 0; - } - return new CDATASection(this, data); -} - -PassRefPtr<ProcessingInstruction> Document::createProcessingInstruction(const String& target, const String& data, ExceptionCode& ec) -{ - if (!isValidName(target)) { - ec = INVALID_CHARACTER_ERR; - return 0; - } - if (isHTMLDocument()) { - ec = NOT_SUPPORTED_ERR; - return 0; - } - return new ProcessingInstruction(this, target, data); -} - -PassRefPtr<EntityReference> Document::createEntityReference(const String& name, ExceptionCode& ec) -{ - if (!isValidName(name)) { - ec = INVALID_CHARACTER_ERR; - return 0; - } - if (isHTMLDocument()) { - ec = NOT_SUPPORTED_ERR; - return 0; - } - return new EntityReference(this, name); -} - -PassRefPtr<EditingText> Document::createEditingTextNode(const String& text) -{ - return new EditingText(this, text); -} - -PassRefPtr<CSSStyleDeclaration> Document::createCSSStyleDeclaration() -{ - return CSSMutableStyleDeclaration::create(); -} - -PassRefPtr<Node> Document::importNode(Node* importedNode, bool deep, ExceptionCode& ec) -{ - ec = 0; - - if (!importedNode -#if ENABLE(SVG) && ENABLE(DASHBOARD_SUPPORT) - || (importedNode->isSVGElement() && page() && page()->settings()->usesDashboardBackwardCompatibilityMode()) -#endif - ) { - ec = NOT_SUPPORTED_ERR; - return 0; - } - - switch (importedNode->nodeType()) { - case TEXT_NODE: - return createTextNode(importedNode->nodeValue()); - case CDATA_SECTION_NODE: - return createCDATASection(importedNode->nodeValue(), ec); - case ENTITY_REFERENCE_NODE: - return createEntityReference(importedNode->nodeName(), ec); - case PROCESSING_INSTRUCTION_NODE: - return createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue(), ec); - case COMMENT_NODE: - return createComment(importedNode->nodeValue()); - case ELEMENT_NODE: { - Element* oldElement = static_cast<Element*>(importedNode); - RefPtr<Element> newElement = createElementNS(oldElement->namespaceURI(), oldElement->tagQName().toString(), ec); - - if (ec) - return 0; - - NamedAttrMap* attrs = oldElement->attributes(true); - if (attrs) { - unsigned length = attrs->length(); - for (unsigned i = 0; i < length; i++) { - Attribute* attr = attrs->attributeItem(i); - newElement->setAttribute(attr->name(), attr->value().impl(), ec); - if (ec) - return 0; - } - } - - newElement->copyNonAttributeProperties(oldElement); - - if (deep) { - for (Node* oldChild = oldElement->firstChild(); oldChild; oldChild = oldChild->nextSibling()) { - RefPtr<Node> newChild = importNode(oldChild, true, ec); - if (ec) - return 0; - newElement->appendChild(newChild.release(), ec); - if (ec) - return 0; - } - } - - return newElement.release(); - } - case ATTRIBUTE_NODE: { - RefPtr<Attr> newAttr = new Attr(0, this, static_cast<Attr*>(importedNode)->attr()->clone()); - newAttr->createTextChild(); - return newAttr.release(); - } - case DOCUMENT_FRAGMENT_NODE: { - DocumentFragment* oldFragment = static_cast<DocumentFragment*>(importedNode); - RefPtr<DocumentFragment> newFragment = createDocumentFragment(); - if (deep) { - for (Node* oldChild = oldFragment->firstChild(); oldChild; oldChild = oldChild->nextSibling()) { - RefPtr<Node> newChild = importNode(oldChild, true, ec); - if (ec) - return 0; - newFragment->appendChild(newChild.release(), ec); - if (ec) - return 0; - } - } - - return newFragment.release(); - } - case ENTITY_NODE: - case NOTATION_NODE: - // FIXME: It should be possible to import these node types, however in DOM3 the DocumentType is readonly, so there isn't much sense in doing that. - // Ability to add these imported nodes to a DocumentType will be considered for addition to a future release of the DOM. - case DOCUMENT_NODE: - case DOCUMENT_TYPE_NODE: - case XPATH_NAMESPACE_NODE: - break; - } - - ec = NOT_SUPPORTED_ERR; - return 0; -} - - -PassRefPtr<Node> Document::adoptNode(PassRefPtr<Node> source, ExceptionCode& ec) -{ - if (!source) { - ec = NOT_SUPPORTED_ERR; - return 0; - } - - if (source->isReadOnlyNode()) { - ec = NO_MODIFICATION_ALLOWED_ERR; - return 0; - } - - switch (source->nodeType()) { - case ENTITY_NODE: - case NOTATION_NODE: - case DOCUMENT_NODE: - case DOCUMENT_TYPE_NODE: - case XPATH_NAMESPACE_NODE: - ec = NOT_SUPPORTED_ERR; - return 0; - case ATTRIBUTE_NODE: { - Attr* attr = static_cast<Attr*>(source.get()); - if (attr->ownerElement()) - attr->ownerElement()->removeAttributeNode(attr, ec); - attr->setSpecified(true); - break; - } - default: - if (source->parentNode()) - source->parentNode()->removeChild(source.get(), ec); - } - - for (Node* node = source.get(); node; node = node->traverseNextNode(source.get())) - node->setDocument(this); - - return source; -} - -bool Document::hasPrefixNamespaceMismatch(const QualifiedName& qName) -{ - static const AtomicString xmlnsNamespaceURI("http://www.w3.org/2000/xmlns/"); - static const AtomicString xmlns("xmlns"); - static const AtomicString xml("xml"); - - // These checks are from DOM Core Level 2, createElementNS - // http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-DocCrElNS - if (!qName.prefix().isEmpty() && qName.namespaceURI().isNull()) // createElementNS(null, "html:div") - return true; - if (qName.prefix() == xml && qName.namespaceURI() != XMLNames::xmlNamespaceURI) // createElementNS("http://www.example.com", "xml:lang") - return true; - - // Required by DOM Level 3 Core and unspecified by DOM Level 2 Core: - // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-DocCrElNS - // createElementNS("http://www.w3.org/2000/xmlns/", "foo:bar"), createElementNS(null, "xmlns:bar") - if ((qName.prefix() == xmlns && qName.namespaceURI() != xmlnsNamespaceURI) || (qName.prefix() != xmlns && qName.namespaceURI() == xmlnsNamespaceURI)) - return true; - - return false; -} - -// FIXME: This should really be in a possible ElementFactory class -PassRefPtr<Element> Document::createElement(const QualifiedName& qName, bool createdByParser, ExceptionCode& ec) -{ - RefPtr<Element> e; - - // FIXME: Use registered namespaces and look up in a hash to find the right factory. - if (qName.namespaceURI() == xhtmlNamespaceURI) - e = HTMLElementFactory::createHTMLElement(qName.localName(), this, 0, createdByParser); -#if ENABLE(SVG) - else if (qName.namespaceURI() == SVGNames::svgNamespaceURI) - e = SVGElementFactory::createSVGElement(qName, this, createdByParser); -#endif - - if (!e) - e = new Element(qName, document()); - - // FIXME: The element factories should be fixed to not ignore qName.prefix() - // Instead they should pass the entire qName into element creation so we don't - // need to manually set the prefix after creation. - // Then this code can become ASSERT(qName == e.qname()); - // and Document::createElement can stop taking ExceptionCode& as well. - if (e && !qName.prefix().isNull()) { - ec = 0; - e->setPrefix(qName.prefix(), ec); - if (ec) - return 0; - } - - return e.release(); -} - -PassRefPtr<Element> Document::createElementNS(const String& namespaceURI, const String& qualifiedName, ExceptionCode& ec) -{ - String prefix, localName; - if (!parseQualifiedName(qualifiedName, prefix, localName, ec)) - return 0; - - QualifiedName qName(prefix, localName, namespaceURI); - if (hasPrefixNamespaceMismatch(qName)) { - ec = NAMESPACE_ERR; - return 0; - } - - return createElement(qName, false, ec); -} - -Element* Document::getElementById(const AtomicString& elementId) const -{ - if (elementId.isEmpty()) - return 0; - - Element* element = m_elementsById.get(elementId.impl()); - if (element) - return element; - - if (m_duplicateIds.contains(elementId.impl())) { - // We know there's at least one node with this id, but we don't know what the first one is. - for (Node *n = traverseNextNode(); n != 0; n = n->traverseNextNode()) { - if (n->isElementNode()) { - element = static_cast<Element*>(n); - if (element->hasID() && element->getAttribute(idAttr) == elementId) { - m_duplicateIds.remove(elementId.impl()); - m_elementsById.set(elementId.impl(), element); - return element; - } - } - } - ASSERT_NOT_REACHED(); - } - return 0; -} - -String Document::readyState() const -{ - if (Frame* f = frame()) { - if (f->loader()->isComplete()) - return "complete"; - if (parsing()) - return "loading"; - return "loaded"; - // FIXME: What does "interactive" mean? - // FIXME: Missing support for "uninitialized". - } - return String(); -} - -String Document::inputEncoding() const -{ - if (TextResourceDecoder* d = decoder()) - return d->encoding().name(); - return String(); -} - -String Document::defaultCharset() const -{ - if (Settings* settings = this->settings()) - return settings->defaultTextEncodingName(); - return String(); -} - -void Document::setCharset(const String& charset) -{ - if (!decoder()) - return; - decoder()->setEncoding(charset, TextResourceDecoder::UserChosenEncoding); -} - -UScriptCode Document::dominantScript() const -{ - struct EncodingScript { - const char* encoding; - UScriptCode script; - }; - - // inputEncoding() always returns a canonical name. We use - // MIME names and IANA names (if the former is not available). - static const EncodingScript encodingScriptList[] = { - { "GB2312", USCRIPT_SIMPLIFIED_HAN }, - { "GBK", USCRIPT_SIMPLIFIED_HAN }, - { "GB18030", USCRIPT_SIMPLIFIED_HAN }, - { "Big5", USCRIPT_TRADITIONAL_HAN }, - { "Big5-HKSCS", USCRIPT_TRADITIONAL_HAN }, - { "Shift_JIS", USCRIPT_HIRAGANA}, - { "EUC-JP", USCRIPT_HIRAGANA }, // Japanese (USCRIPT_JAPANESE) - { "ISO-2022-KR", USCRIPT_HIRAGANA }, - { "EUC-KR", USCRIPT_HANGUL }, // Korean (USCRIPT_KOREAN) - { "TIS-620", USCRIPT_THAI }, - { "ISO-8859-1", USCRIPT_LATIN }, - { "ISO-8859-15", USCRIPT_LATIN }, - { "windows-1252", USCRIPT_LATIN }, - { "ISO-8859-2", USCRIPT_LATIN }, - { "windows-1250", USCRIPT_LATIN }, - { "ISO-8859-3", USCRIPT_LATIN }, - { "ISO-8859-4", USCRIPT_LATIN }, - { "ISO-8859-13", USCRIPT_LATIN }, - { "windows-1257", USCRIPT_LATIN }, - { "ISO-8859-5", USCRIPT_CYRILLIC }, - { "windows-1251", USCRIPT_CYRILLIC }, - { "KOI8-R", USCRIPT_CYRILLIC }, - { "KOI8-U", USCRIPT_CYRILLIC }, - { "ISO-8859-6", USCRIPT_ARABIC }, - { "windows-1256", USCRIPT_ARABIC }, - { "ISO-8859-7", USCRIPT_GREEK }, - { "windows-1253", USCRIPT_GREEK }, - { "ISO-8859-8", USCRIPT_HEBREW }, - { "windows-1255", USCRIPT_HEBREW }, - { "ISO-8859-9", USCRIPT_LATIN }, // Turkish - { "windows-1254", USCRIPT_LATIN }, - { "ISO-8859-10", USCRIPT_LATIN }, // Nordic - { "ISO-8859-14", USCRIPT_LATIN }, // Celtic - { "ISO-8859-16", USCRIPT_LATIN }, // Romanian - { "windows-1258", USCRIPT_LATIN }, // Vietnamese - }; - - static HashMap<String, UScriptCode> encodingScriptMap; - - if (encodingScriptMap.isEmpty()) { - for (unsigned i = 0; i < sizeof(encodingScriptList) / sizeof(encodingScriptList[0]); ++i) - encodingScriptMap.set(encodingScriptList[i].encoding, - encodingScriptList[i].script); - } - - if (m_dominantScript != USCRIPT_INVALID_CODE) - return m_dominantScript; - String encoding = inputEncoding(); - if (encoding.isEmpty()) - return m_dominantScript; - - HashMap<String, UScriptCode>::iterator it = encodingScriptMap.find(encoding); - if (it != encodingScriptMap.end()) - m_dominantScript = it->second; - else - // TODO(jungshik) : should return a script corresponding to the locale. - m_dominantScript = USCRIPT_COMMON; - return m_dominantScript; -} - -void Document::setXMLVersion(const String& version, ExceptionCode& ec) -{ - if (!implementation()->hasFeature("XML", String())) { - ec = NOT_SUPPORTED_ERR; - return; - } - - // FIXME: Also raise NOT_SUPPORTED_ERR if the version is set to a value that is not supported by this Document. - - m_xmlVersion = version; -} - -void Document::setXMLStandalone(bool standalone, ExceptionCode& ec) -{ - if (!implementation()->hasFeature("XML", String())) { - ec = NOT_SUPPORTED_ERR; - return; - } - - m_xmlStandalone = standalone; -} - -void Document::setDocumentURI(const String& uri) -{ - m_documentURI = uri; - updateBaseURL(); -} - -KURL Document::baseURI() const -{ - return m_baseURL; -} - -Element* Document::elementFromPoint(int x, int y) const -{ - if (!renderer()) - return 0; - - HitTestRequest request(true, true); - HitTestResult result(IntPoint(x, y)); - renderer()->layer()->hitTest(request, result); - - Node* n = result.innerNode(); - while (n && !n->isElementNode()) - n = n->parentNode(); - if (n) - n = n->shadowAncestorNode(); - return static_cast<Element*>(n); -} - -void Document::addElementById(const AtomicString& elementId, Element* element) -{ - typedef HashMap<AtomicStringImpl*, Element*>::iterator iterator; - if (!m_duplicateIds.contains(elementId.impl())) { - // Fast path. The ID is not already in m_duplicateIds, so we assume that it's - // also not already in m_elementsById and do an add. If that add succeeds, we're done. - pair<iterator, bool> addResult = m_elementsById.add(elementId.impl(), element); - if (addResult.second) - return; - // The add failed, so this ID was already cached in m_elementsById. - // There are multiple elements with this ID. Remove the m_elementsById - // cache for this ID so getElementById searches for it next time it is called. - m_elementsById.remove(addResult.first); - m_duplicateIds.add(elementId.impl()); - } else { - // There are multiple elements with this ID. If it exists, remove the m_elementsById - // cache for this ID so getElementById searches for it next time it is called. - iterator cachedItem = m_elementsById.find(elementId.impl()); - if (cachedItem != m_elementsById.end()) { - m_elementsById.remove(cachedItem); - m_duplicateIds.add(elementId.impl()); - } - } - m_duplicateIds.add(elementId.impl()); -} - -void Document::removeElementById(const AtomicString& elementId, Element* element) -{ - if (m_elementsById.get(elementId.impl()) == element) - m_elementsById.remove(elementId.impl()); - else - m_duplicateIds.remove(elementId.impl()); -} - -Element* Document::getElementByAccessKey(const String& key) const -{ - if (key.isEmpty()) - return 0; - if (!m_accessKeyMapValid) { - for (Node* n = firstChild(); n; n = n->traverseNextNode()) { - if (!n->isElementNode()) - continue; - Element* element = static_cast<Element*>(n); - const AtomicString& accessKey = element->getAttribute(accesskeyAttr); - if (!accessKey.isEmpty()) - m_elementsByAccessKey.set(accessKey.impl(), element); - } - m_accessKeyMapValid = true; - } - return m_elementsByAccessKey.get(key.impl()); -} - -void Document::updateTitle() -{ - if (Frame* f = frame()) - f->loader()->setTitle(m_title); -} - -void Document::setTitle(const String& title, Element* titleElement) -{ - if (!titleElement) { - // Title set by JavaScript -- overrides any title elements. - m_titleSetExplicitly = true; - if (!isHTMLDocument()) - m_titleElement = 0; - else if (!m_titleElement) { - if (HTMLElement* headElement = head()) { - ExceptionCode ec = 0; - m_titleElement = createElement("title", ec); - ASSERT(!ec); - headElement->appendChild(m_titleElement, ec); - ASSERT(!ec); - } - } - } else if (titleElement != m_titleElement) { - if (m_titleElement || m_titleSetExplicitly) - // Only allow the first title element to change the title -- others have no effect. - return; - m_titleElement = titleElement; - } - - if (m_title == title) - return; - - m_title = title; - updateTitle(); - - if (m_titleSetExplicitly && m_titleElement && m_titleElement->hasTagName(titleTag)) - static_cast<HTMLTitleElement*>(m_titleElement.get())->setText(m_title); -} - -void Document::removeTitle(Element* titleElement) -{ - if (m_titleElement != titleElement) - return; - - m_titleElement = 0; - m_titleSetExplicitly = false; - - // Update title based on first title element in the head, if one exists. - if (HTMLElement* headElement = head()) { - for (Node* e = headElement->firstChild(); e; e = e->nextSibling()) - if (e->hasTagName(titleTag)) { - HTMLTitleElement* titleElement = static_cast<HTMLTitleElement*>(e); - setTitle(titleElement->text(), titleElement); - break; - } - } - - if (!m_titleElement && !m_title.isEmpty()) { - m_title = ""; - updateTitle(); - } -} - -String Document::nodeName() const -{ - return "#document"; -} - -Node::NodeType Document::nodeType() const -{ - return DOCUMENT_NODE; -} - -FrameView* Document::view() const -{ - return m_frame ? m_frame->view() : 0; -} - -Page* Document::page() const -{ - return m_frame ? m_frame->page() : 0; -} - -Settings* Document::settings() const -{ - return m_frame ? m_frame->settings() : 0; -} - -PassRefPtr<Range> Document::createRange() -{ - return Range::create(this); -} - -PassRefPtr<NodeIterator> Document::createNodeIterator(Node* root, unsigned whatToShow, - PassRefPtr<NodeFilter> filter, bool expandEntityReferences, ExceptionCode& ec) -{ - if (!root) { - ec = NOT_SUPPORTED_ERR; - return 0; - } - return NodeIterator::create(root, whatToShow, filter, expandEntityReferences); -} - -PassRefPtr<TreeWalker> Document::createTreeWalker(Node *root, unsigned whatToShow, - PassRefPtr<NodeFilter> filter, bool expandEntityReferences, ExceptionCode& ec) -{ - if (!root) { - ec = NOT_SUPPORTED_ERR; - return 0; - } - return TreeWalker::create(root, whatToShow, filter, expandEntityReferences); -} - -void Document::setDocumentChanged(bool b) -{ - if (b) { - if (!m_docChanged) { - if (!changedDocuments) - changedDocuments = new HashSet<Document*>; - changedDocuments->add(this); - } - if (m_accessKeyMapValid) { - m_accessKeyMapValid = false; - m_elementsByAccessKey.clear(); - } - } else { - if (m_docChanged && changedDocuments) - changedDocuments->remove(this); - } - - m_docChanged = b; -} - -void Document::recalcStyle(StyleChange change) -{ - // we should not enter style recalc while painting - if (frame() && frame()->isPainting()) { - ASSERT(!frame()->isPainting()); - return; - } - - if (m_inStyleRecalc) - return; // Guard against re-entrancy. -dwh - - m_inStyleRecalc = true; - suspendPostAttachCallbacks(); - - ASSERT(!renderer() || renderArena()); - if (!renderer() || !renderArena()) - goto bail_out; - - if (change == Force) { - // style selector may set this again during recalc - m_hasNodesWithPlaceholderStyle = false; - - RenderStyle* oldStyle = renderer()->style(); - if (oldStyle) - oldStyle->ref(); - RenderStyle* _style = new (m_renderArena) RenderStyle(); - _style->ref(); - _style->setDisplay(BLOCK); - _style->setVisuallyOrdered(visuallyOrdered); - _style->setZoom(frame()->pageZoomFactor()); - m_styleSelector->setStyle(_style); - - FontDescription fontDescription; - fontDescription.setUsePrinterFont(printing()); - // TODO(jungshik): Eventually, we need to derive the dominant script - // for the current node based on 'xml:lang' and 'lang' specified for - // it or inherited from its parent rather than using the document-wide - // value (inferred from charset). Note also that it does not work - // for 'script-agnostic' charsets like UTF-8. In that case, Firefox - // uses the script corresponding to the application locale. - // While a document is loaded, this function is called multiple - // times. At the beginning, the document charset is not known and - // dominantScript remains invalid. Only when it's determined, we - // change the font accordingly. - // See http://bugs.webkit.org/show_bug.cgi?id=10874 and - // https://bugs.webkit.org/show_bug.cgi?id=18085 - UScriptCode script = dominantScript(); - if (script != USCRIPT_INVALID_CODE) - fontDescription.setDominantScript(script); - if (Settings* settings = this->settings()) { - fontDescription.setRenderingMode(settings->fontRenderingMode()); - if (printing() && !settings->shouldPrintBackgrounds()) - _style->setForceBackgroundsToWhite(true); - const AtomicString& stdfont = settings->standardFontFamily(); - if (!stdfont.isEmpty()) { - fontDescription.firstFamily().setFamily(stdfont); - FontFamily& currFamily = fontDescription.firstFamily(); - if (script != USCRIPT_INVALID_CODE) { - // TODO(jungshik) : I might as well modify |genericFamily| of - // |fontDescription| here, but I'm wary of a potential breakage. - // For now, just use a temporary variable. - FontDescription tmpDescription; - tmpDescription.setGenericFamily(FontDescription::StandardFamily); - AtomicString docFont = FontCache::getGenericFontForScript( - script, tmpDescription); - if (!docFont.isEmpty()) { - RefPtr<SharedFontFamily> newFamily(SharedFontFamily::create()); - newFamily->setFamily(docFont); - currFamily.appendFamily(newFamily); - currFamily = *newFamily; - } - } - currFamily.appendFamily(0); - } - fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1); - m_styleSelector->setFontSize(fontDescription, m_styleSelector->fontSizeForKeyword(CSSValueMedium, inCompatMode(), false)); - } - - _style->setFontDescription(fontDescription); - _style->font().update(m_styleSelector->fontSelector()); - if (inCompatMode()) - _style->setHtmlHacks(true); // enable html specific rendering tricks - - StyleChange ch = diff(_style, oldStyle); - if (renderer() && ch != NoChange) - renderer()->setStyle(_style); - if (change != Force) - change = ch; - - _style->deref(m_renderArena); - if (oldStyle) - oldStyle->deref(m_renderArena); - } - - for (Node* n = firstChild(); n; n = n->nextSibling()) - if (change >= Inherit || n->hasChangedChild() || n->changed()) - n->recalcStyle(change); - - if (changed() && view()) - view()->layout(); - -bail_out: - setChanged(NoStyleChange); - setHasChangedChild(false); - setDocumentChanged(false); - - resumePostAttachCallbacks(); - m_inStyleRecalc = false; - - // If we wanted to call implicitClose() during recalcStyle, do so now that we're finished. - if (m_closeAfterStyleRecalc) { - m_closeAfterStyleRecalc = false; - implicitClose(); - } -} - -void Document::updateRendering() -{ - if (hasChangedChild() && !inPageCache()) - recalcStyle(NoChange); - - // Tell the animation controller that the style is available and it can start animations - if (m_frame) - m_frame->animation()->styleAvailable(); -} - -void Document::updateDocumentsRendering() -{ - if (!changedDocuments) - return; - - while (changedDocuments->size()) { - HashSet<Document*>::iterator it = changedDocuments->begin(); - Document* doc = *it; - changedDocuments->remove(it); - - doc->m_docChanged = false; - doc->updateRendering(); - } -} - -void Document::updateLayout() -{ - if (Element* oe = ownerElement()) - oe->document()->updateLayout(); - - // FIXME: Dave Hyatt's pretty sure we can remove this because layout calls recalcStyle as needed. - updateRendering(); - - // Only do a layout if changes have occurred that make it necessary. - FrameView* v = view(); - if (v && renderer() && (v->layoutPending() || renderer()->needsLayout())) - v->layout(); -} - -// FIXME: This is a bad idea and needs to be removed eventually. -// Other browsers load stylesheets before they continue parsing the web page. -// Since we don't, we can run JavaScript code that needs answers before the -// stylesheets are loaded. Doing a layout ignoring the pending stylesheets -// lets us get reasonable answers. The long term solution to this problem is -// to instead suspend JavaScript execution. -void Document::updateLayoutIgnorePendingStylesheets() -{ - bool oldIgnore = m_ignorePendingStylesheets; - - if (!haveStylesheetsLoaded()) { - m_ignorePendingStylesheets = true; - // FIXME: We are willing to attempt to suppress painting with outdated style info only once. Our assumption is that it would be - // dangerous to try to stop it a second time, after page content has already been loaded and displayed - // with accurate style information. (Our suppression involves blanking the whole page at the - // moment. If it were more refined, we might be able to do something better.) - // It's worth noting though that this entire method is a hack, since what we really want to do is - // suspend JS instead of doing a layout with inaccurate information. - if (body() && !body()->renderer() && m_pendingSheetLayout == NoLayoutWithPendingSheets) { - m_pendingSheetLayout = DidLayoutWithPendingSheets; - updateStyleSelector(); - } else if (m_hasNodesWithPlaceholderStyle) - // If new nodes have been added or style recalc has been done with style sheets still pending, some nodes - // may not have had their real style calculated yet. Normally this gets cleaned when style sheets arrive - // but here we need up-to-date style immediatly. - recalcStyle(Force); - } - - updateLayout(); - - m_ignorePendingStylesheets = oldIgnore; -} - -void Document::attach() -{ - ASSERT(!attached()); - ASSERT(!m_inPageCache); - ASSERT(!m_axObjectCache); - - if (!m_renderArena) - m_renderArena = new RenderArena(); - - // Create the rendering tree - setRenderer(new (m_renderArena) RenderView(this, view())); - - if (!m_styleSelector) { - bool matchAuthorAndUserStyles = true; - if (Settings* docSettings = settings()) - matchAuthorAndUserStyles = docSettings->authorAndUserStylesEnabled(); - m_styleSelector = new CSSStyleSelector(this, userStyleSheet(), m_styleSheets.get(), m_mappedElementSheet.get(), !inCompatMode(), matchAuthorAndUserStyles); - } - - recalcStyle(Force); - - RenderObject* render = renderer(); - setRenderer(0); - - ContainerNode::attach(); - - setRenderer(render); -} - -void Document::detach() -{ - ASSERT(attached()); - ASSERT(!m_inPageCache); - - clearAXObjectCache(); - - RenderObject* render = renderer(); - - // indicate destruction mode, i.e. attached() but renderer == 0 - setRenderer(0); - - // Empty out these lists as a performance optimization, since detaching - // all the individual render objects will cause all the RenderImage - // objects to remove themselves from the lists. - m_imageLoadEventDispatchSoonList.clear(); - m_imageLoadEventDispatchingList.clear(); - - m_hoverNode = 0; - m_focusedNode = 0; - m_activeNode = 0; - - ContainerNode::detach(); - - if (render) - render->destroy(); - - // This is required, as our Frame might delete itself as soon as it detaches - // us. However, this violates Node::detach() symantics, as it's never - // possible to re-attach. Eventually Document::detach() should be renamed - // or this call made explicit in each of the callers of Document::detach(). - clearFramePointer(); - - if (m_renderArena) { - delete m_renderArena; - m_renderArena = 0; - } -} - -void Document::clearFramePointer() -{ - m_frame = 0; -} - -void Document::removeAllEventListenersFromAllNodes() -{ - m_windowEventListeners.clear(); - removeAllDisconnectedNodeEventListeners(); - for (Node *n = this; n; n = n->traverseNextNode()) { - if (!n->isEventTargetNode()) - continue; - EventTargetNodeCast(n)->removeAllEventListeners(); - } -} - -void Document::registerDisconnectedNodeWithEventListeners(Node* node) -{ - m_disconnectedNodesWithEventListeners.add(node); -} - -void Document::unregisterDisconnectedNodeWithEventListeners(Node* node) -{ - m_disconnectedNodesWithEventListeners.remove(node); -} - -void Document::removeAllDisconnectedNodeEventListeners() -{ - HashSet<Node*>::iterator end = m_disconnectedNodesWithEventListeners.end(); - for (HashSet<Node*>::iterator i = m_disconnectedNodesWithEventListeners.begin(); i != end; ++i) - EventTargetNodeCast(*i)->removeAllEventListeners(); - m_disconnectedNodesWithEventListeners.clear(); -} - -void Document::clearAXObjectCache() -{ - // clear cache in top document - if (m_axObjectCache) { - delete m_axObjectCache; - m_axObjectCache = 0; - return; - } - - // ask the top-level document to clear its cache - Document* doc = topDocument(); - if (doc != this) - doc->clearAXObjectCache(); -} - -AXObjectCache* Document::axObjectCache() const -{ - // The only document that actually has a AXObjectCache is the top-level - // document. This is because we need to be able to get from any WebCoreAXObject - // to any other WebCoreAXObject on the same page. Using a single cache allows - // lookups across nested webareas (i.e. multiple documents). - - if (m_axObjectCache) { - // return already known top-level cache - if (!ownerElement()) - return m_axObjectCache; - - // In some pages with frames, the cache is created before the sub-webarea is - // inserted into the tree. Here, we catch that case and just toss the old - // cache and start over. - // NOTE: This recovery may no longer be needed. I have been unable to trigger - // it again. See rdar://5794454 - // FIXME: Can this be fixed when inserting the subframe instead of now? - // FIXME: If this function was called to get the cache in order to remove - // an AXObject, we are now deleting the cache as a whole and returning a - // new empty cache that does not contain the AXObject! That should actually - // be OK. I am concerned about other cases like this where accessing the - // cache blows away the AXObject being operated on. - delete m_axObjectCache; - m_axObjectCache = 0; - } - - // ask the top-level document for its cache - Document* doc = topDocument(); - if (doc != this) - return doc->axObjectCache(); - - // this is the top-level document, so install a new cache - m_axObjectCache = new AXObjectCache; - return m_axObjectCache; -} - -void Document::setVisuallyOrdered() -{ - visuallyOrdered = true; - if (renderer()) - renderer()->style()->setVisuallyOrdered(true); -} - -Tokenizer* Document::createTokenizer() -{ - // FIXME: this should probably pass the frame instead - return new XMLTokenizer(this, view()); -} - -void Document::open(Document* ownerDocument) -{ - if (ownerDocument) { - setURL(ownerDocument->url()); - m_cookieURL = ownerDocument->cookieURL(); - m_securityOrigin = ownerDocument->securityOrigin(); - } - - if (m_frame) { - if (m_frame->loader()->isLoadingMainResource() || (tokenizer() && tokenizer()->executingScript())) - return; - - if (m_frame->loader()->state() == FrameStateProvisional) - m_frame->loader()->stopAllLoaders(); - } - - implicitOpen(); - - if (m_frame) - m_frame->loader()->didExplicitOpen(); -} - -void Document::cancelParsing() -{ - if (m_tokenizer) { - // We have to clear the tokenizer to avoid possibly triggering - // the onload handler when closing as a side effect of a cancel-style - // change, such as opening a new document or closing the window while - // still parsing - delete m_tokenizer; - m_tokenizer = 0; - close(); - } -} - -void Document::implicitOpen() -{ - cancelParsing(); - - clear(); - m_tokenizer = createTokenizer(); - setParsing(true); -} - -HTMLElement* Document::body() -{ - Node* de = documentElement(); - if (!de) - return 0; - - // try to prefer a FRAMESET element over BODY - Node* body = 0; - for (Node* i = de->firstChild(); i; i = i->nextSibling()) { - if (i->hasTagName(framesetTag)) - return static_cast<HTMLElement*>(i); - - if (i->hasTagName(bodyTag)) - body = i; - } - return static_cast<HTMLElement*>(body); -} - -void Document::setBody(PassRefPtr<HTMLElement> newBody, ExceptionCode& ec) -{ - if (!newBody || !documentElement()) { - ec = HIERARCHY_REQUEST_ERR; - return; - } - - HTMLElement* b = body(); - if (!b) - documentElement()->appendChild(newBody, ec); - else - documentElement()->replaceChild(newBody, b, ec); -} - -HTMLHeadElement* Document::head() -{ - Node* de = documentElement(); - if (!de) - return 0; - - for (Node* e = de->firstChild(); e; e = e->nextSibling()) - if (e->hasTagName(headTag)) - return static_cast<HTMLHeadElement*>(e); - - return 0; -} - -void Document::close() -{ - Frame* frame = this->frame(); - if (frame) { - // This code calls implicitClose() if all loading has completed. - FrameLoader* frameLoader = frame->loader(); - frameLoader->endIfNotLoadingMainResource(); - frameLoader->checkCompleted(); - } else { - // Because we have no frame, we don't know if all loading has completed, - // so we just call implicitClose() immediately. FIXME: This might fire - // the load event prematurely <http://bugs.webkit.org/show_bug.cgi?id=14568>. - implicitClose(); - } -} - -void Document::implicitClose() -{ - // If we're in the middle of recalcStyle, we need to defer the close until the style information is accurate and all elements are re-attached. - if (m_inStyleRecalc) { - m_closeAfterStyleRecalc = true; - return; - } - - bool wasLocationChangePending = frame() && frame()->loader()->isScheduledLocationChangePending(); - bool doload = !parsing() && m_tokenizer && !m_processingLoadEvent && !wasLocationChangePending; - - if (!doload) - return; - - m_processingLoadEvent = true; - - m_wellFormed = m_tokenizer && m_tokenizer->wellFormed(); - - // We have to clear the tokenizer, in case someone document.write()s from the - // onLoad event handler, as in Radar 3206524. - delete m_tokenizer; - m_tokenizer = 0; - - // Parser should have picked up all preloads by now - m_docLoader->clearPreloads(); - - // Create a body element if we don't already have one. See Radar 3758785. - if (!this->body() && isHTMLDocument()) { - if (Node* documentElement = this->documentElement()) { - ExceptionCode ec = 0; - documentElement->appendChild(new HTMLBodyElement(this), ec); - ASSERT(!ec); - } - } - - // FIXME: We kick off the icon loader when the Document is done parsing. - // There are earlier opportunities we could start it: - // -When the <head> finishes parsing - // -When any new HTMLLinkElement is inserted into the document - // But those add a dynamic component to the favicon that has UI - // ramifications, and we need to decide what is the Right Thing To Do(tm) - Frame* f = frame(); - if (f) - f->loader()->startIconLoader(); - - // Resume the animations (or start them) - if (f) - f->animation()->resumeAnimations(this); - - dispatchImageLoadEventsNow(); - this->dispatchWindowEvent(loadEvent, false, false); - if (f) - f->loader()->handledOnloadEvents(); -#ifdef INSTRUMENT_LAYOUT_SCHEDULING - if (!ownerElement()) - printf("onload fired at %d\n", elapsedTime()); -#endif - - m_processingLoadEvent = false; - - // An event handler may have removed the frame - if (!frame()) - return; - - // Make sure both the initial layout and reflow happen after the onload - // fires. This will improve onload scores, and other browsers do it. - // If they wanna cheat, we can too. -dwh - - if (frame()->loader()->isScheduledLocationChangePending() && elapsedTime() < cLayoutScheduleThreshold) { - // Just bail out. Before or during the onload we were shifted to another page. - // The old i-Bench suite does this. When this happens don't bother painting or laying out. - view()->unscheduleRelayout(); - return; - } - - frame()->loader()->checkCallImplicitClose(); - - // Now do our painting/layout, but only if we aren't in a subframe or if we're in a subframe - // that has been sized already. Otherwise, our view size would be incorrect, so doing any - // layout/painting now would be pointless. - if (!ownerElement() || (ownerElement()->renderer() && !ownerElement()->renderer()->needsLayout())) { - updateRendering(); - - // Always do a layout after loading if needed. - if (view() && renderer() && (!renderer()->firstChild() || renderer()->needsLayout())) - view()->layout(); - - // Paint immediately after the document is ready. We do this to ensure that any timers set by the - // onload don't have a chance to fire before we would have painted. To avoid over-flushing we only - // worry about this for the top-level document. -#if !PLATFORM(MAC) - // FIXME: This causes a timing issue with the dispatchDidFinishLoad delegate callback. - // See <rdar://problem/5092361> - if (view() && !ownerElement()) - view()->update(); -#endif - } - -#if PLATFORM(MAC) - if (renderer() && AXObjectCache::accessibilityEnabled()) - axObjectCache()->postNotificationToElement(renderer(), "AXLoadComplete"); -#endif - -#if ENABLE(SVG) - // FIXME: Officially, time 0 is when the outermost <svg> receives its - // SVGLoad event, but we don't implement those yet. This is close enough - // for now. In some cases we should have fired earlier. - if (svgExtensions()) - accessSVGExtensions()->startAnimations(); -#endif -} - -void Document::setParsing(bool b) -{ - m_bParsing = b; - if (!m_bParsing && view()) - view()->scheduleRelayout(); - -#ifdef INSTRUMENT_LAYOUT_SCHEDULING - if (!ownerElement() && !m_bParsing) - printf("Parsing finished at %d\n", elapsedTime()); -#endif -} - -bool Document::shouldScheduleLayout() -{ - // We can update layout if: - // (a) we actually need a layout - // (b) our stylesheets are all loaded - // (c) we have a <body> - return (renderer() && renderer()->needsLayout() && haveStylesheetsLoaded() && - documentElement() && documentElement()->renderer() && - (!documentElement()->hasTagName(htmlTag) || body())); -} - -int Document::minimumLayoutDelay() -{ - if (m_overMinimumLayoutThreshold) - return 0; - - int elapsed = elapsedTime(); - m_overMinimumLayoutThreshold = elapsed > cLayoutScheduleThreshold; - - // We'll want to schedule the timer to fire at the minimum layout threshold. - return max(0, cLayoutScheduleThreshold - elapsed); -} - -int Document::elapsedTime() const -{ - return static_cast<int>((currentTime() - m_startTime) * 1000); -} - -void Document::write(const String& text, Document* ownerDocument) -{ -#ifdef INSTRUMENT_LAYOUT_SCHEDULING - if (!ownerElement()) - printf("Beginning a document.write at %d\n", elapsedTime()); -#endif - - if (!m_tokenizer) { - open(ownerDocument); - ASSERT(m_tokenizer); - if (!m_tokenizer) - return; - write("<html>", ownerDocument); - } - m_tokenizer->write(text, false); - -#ifdef INSTRUMENT_LAYOUT_SCHEDULING - if (!ownerElement()) - printf("Ending a document.write at %d\n", elapsedTime()); -#endif -} - -void Document::writeln(const String& text, Document* ownerDocument) -{ - write(text, ownerDocument); - write("\n", ownerDocument); -} - -void Document::finishParsing() -{ -#ifdef INSTRUMENT_LAYOUT_SCHEDULING - if (!ownerElement()) - printf("Received all data at %d\n", elapsedTime()); -#endif - - // Let the tokenizer go through as much data as it can. There will be three possible outcomes after - // finish() is called: - // (1) All remaining data is parsed, document isn't loaded yet - // (2) All remaining data is parsed, document is loaded, tokenizer gets deleted - // (3) Data is still remaining to be parsed. - if (m_tokenizer) - m_tokenizer->finish(); -} - -void Document::clear() -{ - delete m_tokenizer; - m_tokenizer = 0; - - removeChildren(); - - m_windowEventListeners.clear(); -} - -void Document::setURL(const KURL& url) -{ - const KURL& newURL = url.isEmpty() ? blankURL() : url; - if (newURL == m_url) - return; - - m_url = newURL; - m_documentURI = m_url.string(); - updateBaseURL(); -} - -void Document::setBaseElementURL(const KURL& baseElementURL) -{ - m_baseElementURL = baseElementURL; - updateBaseURL(); -} - -void Document::updateBaseURL() -{ - m_baseURL = m_baseElementURL.isEmpty() ? KURL(documentURI()) : m_baseElementURL; - if (!m_baseURL.isValid()) - m_baseURL = KURL(); - - if (m_elemSheet) - m_elemSheet->setHref(m_baseURL.string()); - if (m_mappedElementSheet) - m_mappedElementSheet->setHref(m_baseURL.string()); -} - -void Document::setCSSStyleSheet(const String& url, const String& charset, const CachedCSSStyleSheet* sheet) -{ - m_sheet = CSSStyleSheet::create(this, url, charset); - m_sheet->parseString(sheet->sheetText()); - - updateStyleSelector(); -} - -#if FRAME_LOADS_USER_STYLESHEET -void Document::setUserStyleSheet(const String& sheet) -{ - if (m_usersheet != sheet) { - m_usersheet = sheet; - updateStyleSelector(); - } -} -#endif - -String Document::userStyleSheet() const -{ -#if FRAME_LOADS_USER_STYLESHEET - return m_usersheet; -#else - Page* page = this->page(); - if (!page) - return String(); - return page->userStyleSheet(); -#endif -} - -CSSStyleSheet* Document::elementSheet() -{ - if (!m_elemSheet) - m_elemSheet = CSSStyleSheet::create(this, m_baseURL.string()); - return m_elemSheet.get(); -} - -CSSStyleSheet* Document::mappedElementSheet() -{ - if (!m_mappedElementSheet) - m_mappedElementSheet = CSSStyleSheet::create(this, m_baseURL.string()); - return m_mappedElementSheet.get(); -} - -static Node* nextNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event) -{ - // Search is inclusive of start - for (Node* n = start; n; n = n->traverseNextNode()) - if (n->isKeyboardFocusable(event) && n->tabIndex() == tabIndex) - return n; - - return 0; -} - -static Node* previousNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event) -{ - // Search is inclusive of start - for (Node* n = start; n; n = n->traversePreviousNode()) - if (n->isKeyboardFocusable(event) && n->tabIndex() == tabIndex) - return n; - - return 0; -} - -static Node* nextNodeWithGreaterTabIndex(Node* start, int tabIndex, KeyboardEvent* event) -{ - // Search is inclusive of start - int winningTabIndex = SHRT_MAX + 1; - Node* winner = 0; - for (Node* n = start; n; n = n->traverseNextNode()) - if (n->isKeyboardFocusable(event) && n->tabIndex() > tabIndex && n->tabIndex() < winningTabIndex) { - winner = n; - winningTabIndex = n->tabIndex(); - } - - return winner; -} - -static Node* previousNodeWithLowerTabIndex(Node* start, int tabIndex, KeyboardEvent* event) -{ - // Search is inclusive of start - int winningTabIndex = 0; - Node* winner = 0; - for (Node* n = start; n; n = n->traversePreviousNode()) - if (n->isKeyboardFocusable(event) && n->tabIndex() < tabIndex && n->tabIndex() > winningTabIndex) { - winner = n; - winningTabIndex = n->tabIndex(); - } - - return winner; -} - -Node* Document::nextFocusableNode(Node* start, KeyboardEvent* event) -{ - if (start) { - // If a node is excluded from the normal tabbing cycle, the next focusable node is determined by tree order - if (start->tabIndex() < 0) { - for (Node* n = start->traverseNextNode(); n; n = n->traverseNextNode()) - if (n->isKeyboardFocusable(event) && n->tabIndex() >= 0) - return n; - } - - // First try to find a node with the same tabindex as start that comes after start in the document. - if (Node* winner = nextNodeWithExactTabIndex(start->traverseNextNode(), start->tabIndex(), event)) - return winner; - - if (start->tabIndex() == 0) - // We've reached the last node in the document with a tabindex of 0. This is the end of the tabbing order. - return 0; - } - - // Look for the first node in the document that: - // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and - // 2) comes first in the document, if there's a tie. - if (Node* winner = nextNodeWithGreaterTabIndex(this, start ? start->tabIndex() : 0, event)) - return winner; - - // There are no nodes with a tabindex greater than start's tabindex, - // so find the first node with a tabindex of 0. - return nextNodeWithExactTabIndex(this, 0, event); -} - -Node* Document::previousFocusableNode(Node* start, KeyboardEvent* event) -{ - Node* last; - for (last = this; last->lastChild(); last = last->lastChild()) - ; // Empty loop. - - // First try to find the last node in the document that comes before start and has the same tabindex as start. - // If start is null, find the last node in the document with a tabindex of 0. - Node* startingNode; - int startingTabIndex; - if (start) { - startingNode = start->traversePreviousNode(); - startingTabIndex = start->tabIndex(); - } else { - startingNode = last; - startingTabIndex = 0; - } - - // However, if a node is excluded from the normal tabbing cycle, the previous focusable node is determined by tree order - if (startingTabIndex < 0) { - for (Node* n = startingNode; n; n = n->traversePreviousNode()) - if (n->isKeyboardFocusable(event) && n->tabIndex() >= 0) - return n; - } - - if (Node* winner = previousNodeWithExactTabIndex(startingNode, startingTabIndex, event)) - return winner; - - // There are no nodes before start with the same tabindex as start, so look for a node that: - // 1) has the highest non-zero tabindex (that is less than start's tabindex), and - // 2) comes last in the document, if there's a tie. - startingTabIndex = (start && start->tabIndex()) ? start->tabIndex() : SHRT_MAX; - return previousNodeWithLowerTabIndex(last, startingTabIndex, event); -} - -int Document::nodeAbsIndex(Node *node) -{ - ASSERT(node->document() == this); - - int absIndex = 0; - for (Node *n = node; n && n != this; n = n->traversePreviousNode()) - absIndex++; - return absIndex; -} - -Node *Document::nodeWithAbsIndex(int absIndex) -{ - Node *n = this; - for (int i = 0; n && (i < absIndex); i++) { - n = n->traverseNextNode(); - } - return n; -} - -void Document::processHttpEquiv(const String &equiv, const String &content) -{ - ASSERT(!equiv.isNull() && !content.isNull()); - - Frame *frame = this->frame(); - - if (equalIgnoringCase(equiv, "default-style")) { - // The preferred style set has been overridden as per section - // 14.3.2 of the HTML4.0 specification. We need to update the - // sheet used variable and then update our style selector. - // For more info, see the test at: - // http://www.hixie.ch/tests/evil/css/import/main/preferred.html - // -dwh - m_selectedStylesheetSet = content; - m_preferredStylesheetSet = content; - updateStyleSelector(); - } else if (equalIgnoringCase(equiv, "refresh")) { - double delay; - String url; - if (frame && parseHTTPRefresh(content, true, delay, url)) { - if (url.isEmpty()) - url = frame->loader()->url().string(); - else - url = completeURL(url).string(); - frame->loader()->scheduleHTTPRedirection(delay, url); - } - } else if (equalIgnoringCase(equiv, "set-cookie")) { - // FIXME: make setCookie work on XML documents too; e.g. in case of <html:meta .....> - if (isHTMLDocument()) - static_cast<HTMLDocument*>(this)->setCookie(content); - } else if (equalIgnoringCase(equiv, "content-language")) - setContentLanguage(content); - else if (equalIgnoringCase(equiv, "x-dns-prefetch-control")) - setDNSPrefetchControl(content); -} - -MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& request, const IntPoint& documentPoint, const PlatformMouseEvent& event) -{ - ASSERT(!renderer() || renderer()->isRenderView()); - - if (!renderer()) - return MouseEventWithHitTestResults(event, HitTestResult(IntPoint())); - - HitTestResult result(documentPoint); - renderer()->layer()->hitTest(request, result); - - if (!request.readonly) - updateRendering(); - - return MouseEventWithHitTestResults(event, result); -} - -// DOM Section 1.1.1 -bool Document::childTypeAllowed(NodeType type) -{ - switch (type) { - case ATTRIBUTE_NODE: - case CDATA_SECTION_NODE: - case DOCUMENT_FRAGMENT_NODE: - case DOCUMENT_NODE: - case ENTITY_NODE: - case ENTITY_REFERENCE_NODE: - case NOTATION_NODE: - case TEXT_NODE: - case XPATH_NAMESPACE_NODE: - return false; - case COMMENT_NODE: - case PROCESSING_INSTRUCTION_NODE: - return true; - case DOCUMENT_TYPE_NODE: - case ELEMENT_NODE: - // Documents may contain no more than one of each of these. - // (One Element and one DocumentType.) - for (Node* c = firstChild(); c; c = c->nextSibling()) - if (c->nodeType() == type) - return false; - return true; - } - return false; -} - -bool Document::canReplaceChild(Node* newChild, Node* oldChild) -{ - if (!oldChild) - // ContainerNode::replaceChild will raise a NOT_FOUND_ERR. - return true; - - if (oldChild->nodeType() == newChild->nodeType()) - return true; - - int numDoctypes = 0; - int numElements = 0; - - // First, check how many doctypes and elements we have, not counting - // the child we're about to remove. - for (Node* c = firstChild(); c; c = c->nextSibling()) { - if (c == oldChild) - continue; - - switch (c->nodeType()) { - case DOCUMENT_TYPE_NODE: - numDoctypes++; - break; - case ELEMENT_NODE: - numElements++; - break; - default: - break; - } - } - - // Then, see how many doctypes and elements might be added by the new child. - if (newChild->nodeType() == DOCUMENT_FRAGMENT_NODE) { - for (Node* c = firstChild(); c; c = c->nextSibling()) { - switch (c->nodeType()) { - case ATTRIBUTE_NODE: - case CDATA_SECTION_NODE: - case DOCUMENT_FRAGMENT_NODE: - case DOCUMENT_NODE: - case ENTITY_NODE: - case ENTITY_REFERENCE_NODE: - case NOTATION_NODE: - case TEXT_NODE: - case XPATH_NAMESPACE_NODE: - return false; - case COMMENT_NODE: - case PROCESSING_INSTRUCTION_NODE: - break; - case DOCUMENT_TYPE_NODE: - numDoctypes++; - break; - case ELEMENT_NODE: - numElements++; - break; - } - } - } else { - switch (newChild->nodeType()) { - case ATTRIBUTE_NODE: - case CDATA_SECTION_NODE: - case DOCUMENT_FRAGMENT_NODE: - case DOCUMENT_NODE: - case ENTITY_NODE: - case ENTITY_REFERENCE_NODE: - case NOTATION_NODE: - case TEXT_NODE: - case XPATH_NAMESPACE_NODE: - return false; - case COMMENT_NODE: - case PROCESSING_INSTRUCTION_NODE: - return true; - case DOCUMENT_TYPE_NODE: - numDoctypes++; - break; - case ELEMENT_NODE: - numElements++; - break; - } - } - - if (numElements > 1 || numDoctypes > 1) - return false; - - return true; -} - -PassRefPtr<Node> Document::cloneNode(bool /*deep*/) -{ - // Spec says cloning Document nodes is "implementation dependent" - // so we do not support it... - return 0; -} - -StyleSheetList* Document::styleSheets() -{ - return m_styleSheets.get(); -} - -String Document::preferredStylesheetSet() const -{ - return m_preferredStylesheetSet; -} - -String Document::selectedStylesheetSet() const -{ - return m_selectedStylesheetSet; -} - -void Document::setSelectedStylesheetSet(const String& aString) -{ - m_selectedStylesheetSet = aString; - updateStyleSelector(); - if (renderer()) - renderer()->repaint(); -} - -// This method is called whenever a top-level stylesheet has finished loading. -void Document::removePendingSheet() -{ - // Make sure we knew this sheet was pending, and that our count isn't out of sync. - ASSERT(m_pendingStylesheets > 0); - - m_pendingStylesheets--; - -#ifdef INSTRUMENT_LAYOUT_SCHEDULING - if (!ownerElement()) - printf("Stylesheet loaded at time %d. %d stylesheets still remain.\n", elapsedTime(), m_pendingStylesheets); -#endif - - updateStyleSelector(); - - if (!m_pendingStylesheets && m_tokenizer) - m_tokenizer->executeScriptsWaitingForStylesheets(); - - if (!m_pendingStylesheets && m_gotoAnchorNeededAfterStylesheetsLoad && m_frame) - m_frame->loader()->gotoAnchor(); -} - -void Document::updateStyleSelector() -{ - // Don't bother updating, since we haven't loaded all our style info yet - // and haven't calculated the style selector for the first time. - if (!m_didCalculateStyleSelector && !haveStylesheetsLoaded()) - return; - - if (didLayoutWithPendingStylesheets() && m_pendingStylesheets <= 0) { - m_pendingSheetLayout = IgnoreLayoutWithPendingSheets; - if (renderer()) - renderer()->repaint(); - } - -#ifdef INSTRUMENT_LAYOUT_SCHEDULING - if (!ownerElement()) - printf("Beginning update of style selector at time %d.\n", elapsedTime()); -#endif - - recalcStyleSelector(); - recalcStyle(Force); - -#ifdef INSTRUMENT_LAYOUT_SCHEDULING - if (!ownerElement()) - printf("Finished update of style selector at time %d\n", elapsedTime()); -#endif - - if (renderer()) { - renderer()->setNeedsLayoutAndPrefWidthsRecalc(); - if (view()) - view()->scheduleRelayout(); - } -} - -void Document::addStyleSheetCandidateNode(Node* node, bool createdByParser) -{ - // Until the <body> exists, we have no choice but to compare document positions, - // since styles outside of the body and head continue to be shunted into the head - // (and thus can shift to end up before dynamically added DOM content that is also - // outside the body). - if ((createdByParser && body()) || m_styleSheetCandidateNodes.isEmpty()) { - m_styleSheetCandidateNodes.add(node); - return; - } - - // Determine an appropriate insertion point. - ListHashSet<Node*>::iterator begin = m_styleSheetCandidateNodes.begin(); - ListHashSet<Node*>::iterator end = m_styleSheetCandidateNodes.end(); - ListHashSet<Node*>::iterator it = end; - Node* followingNode = 0; - do { - --it; - Node* n = *it; - unsigned short position = n->compareDocumentPosition(node); - if (position == DOCUMENT_POSITION_FOLLOWING) { - m_styleSheetCandidateNodes.insertBefore(followingNode, node); - return; - } - followingNode = n; - } while (it != begin); - - m_styleSheetCandidateNodes.insertBefore(followingNode, node); -} - -void Document::removeStyleSheetCandidateNode(Node* node) -{ - m_styleSheetCandidateNodes.remove(node); -} - -void Document::recalcStyleSelector() -{ - if (!renderer() || !attached()) - return; - - StyleSheetVector sheets; - - bool matchAuthorAndUserStyles = true; - if (Settings* settings = this->settings()) - matchAuthorAndUserStyles = settings->authorAndUserStylesEnabled(); - - ListHashSet<Node*>::iterator begin = m_styleSheetCandidateNodes.begin(); - ListHashSet<Node*>::iterator end = m_styleSheetCandidateNodes.end(); - if (!matchAuthorAndUserStyles) - end = begin; - for (ListHashSet<Node*>::iterator it = begin; it != end; ++it) { - Node* n = *it; - - StyleSheet* sheet = 0; - - if (n->nodeType() == PROCESSING_INSTRUCTION_NODE) { - // Processing instruction (XML documents only) - ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(n); - sheet = pi->sheet(); -#if ENABLE(XSLT) - // Don't apply XSL transforms to already transformed documents -- <rdar://problem/4132806> - if (pi->isXSL() && !transformSourceDocument()) { - // Don't apply XSL transforms until loading is finished. - if (!parsing()) - applyXSLTransform(pi); - return; - } -#endif - if (!sheet && !pi->localHref().isEmpty()) { - // Processing instruction with reference to an element in this document - e.g. - // <?xml-stylesheet href="#mystyle">, with the element - // <foo id="mystyle">heading { color: red; }</foo> at some location in - // the document - Element* elem = getElementById(pi->localHref().impl()); - if (elem) { - String sheetText(""); - for (Node* c = elem->firstChild(); c; c = c->nextSibling()) { - if (c->nodeType() == TEXT_NODE || c->nodeType() == CDATA_SECTION_NODE) - sheetText += c->nodeValue(); - } - - RefPtr<CSSStyleSheet> cssSheet = CSSStyleSheet::create(this); - cssSheet->parseString(sheetText); - pi->setCSSStyleSheet(cssSheet); - sheet = cssSheet.get(); - } - } - } else if (n->isHTMLElement() && (n->hasTagName(linkTag) || n->hasTagName(styleTag)) -#if ENABLE(SVG) - || (n->isSVGElement() && n->hasTagName(SVGNames::styleTag)) -#endif - ) { - Element* e = static_cast<Element*>(n); - AtomicString title = e->getAttribute(titleAttr); - bool enabledViaScript = false; - if (e->hasLocalName(linkTag)) { - // <LINK> element - HTMLLinkElement* l = static_cast<HTMLLinkElement*>(n); - if (l->isDisabled()) - continue; - enabledViaScript = l->isEnabledViaScript(); - if (l->isLoading()) { - // it is loading but we should still decide which style sheet set to use - if (!enabledViaScript && !title.isEmpty() && m_preferredStylesheetSet.isEmpty()) { - const AtomicString& rel = e->getAttribute(relAttr); - if (!rel.contains("alternate")) { - m_preferredStylesheetSet = title; - m_selectedStylesheetSet = title; - } - } - continue; - } - if (!l->sheet()) - title = nullAtom; - } - - // Get the current preferred styleset. This is the - // set of sheets that will be enabled. -#if ENABLE(SVG) - if (n->isSVGElement() && n->hasTagName(SVGNames::styleTag)) - sheet = static_cast<SVGStyleElement*>(n)->sheet(); - else -#endif - if (e->hasLocalName(linkTag)) - sheet = static_cast<HTMLLinkElement*>(n)->sheet(); - else - // <STYLE> element - sheet = static_cast<HTMLStyleElement*>(n)->sheet(); - - // Check to see if this sheet belongs to a styleset - // (thus making it PREFERRED or ALTERNATE rather than - // PERSISTENT). - if (!enabledViaScript && !title.isEmpty()) { - // Yes, we have a title. - if (m_preferredStylesheetSet.isEmpty()) { - // No preferred set has been established. If - // we are NOT an alternate sheet, then establish - // us as the preferred set. Otherwise, just ignore - // this sheet. - AtomicString rel = e->getAttribute(relAttr); - if (e->hasLocalName(styleTag) || !rel.contains("alternate")) - m_preferredStylesheetSet = m_selectedStylesheetSet = title; - } - - if (title != m_preferredStylesheetSet) - sheet = 0; - } - } - - if (sheet) - sheets.append(sheet); - } - - m_styleSheets->swap(sheets); - - // Create a new style selector - delete m_styleSelector; - m_styleSelector = new CSSStyleSelector(this, userStyleSheet(), m_styleSheets.get(), m_mappedElementSheet.get(), !inCompatMode(), matchAuthorAndUserStyles); - m_didCalculateStyleSelector = true; -} - -void Document::setHoverNode(PassRefPtr<Node> newHoverNode) -{ - m_hoverNode = newHoverNode; -} - -void Document::setActiveNode(PassRefPtr<Node> newActiveNode) -{ - m_activeNode = newActiveNode; -} - -void Document::focusedNodeRemoved() -{ - setFocusedNode(0); -} - -void Document::removeFocusedNodeOfSubtree(Node* node, bool amongChildrenOnly) -{ - if (!m_focusedNode || this->inPageCache()) // If the document is in the page cache, then we don't need to clear out the focused node. - return; - - bool nodeInSubtree = false; - if (amongChildrenOnly) - nodeInSubtree = m_focusedNode->isDescendantOf(node); - else - nodeInSubtree = (m_focusedNode == node) || m_focusedNode->isDescendantOf(node); - - if (nodeInSubtree) - document()->focusedNodeRemoved(); -} - -void Document::hoveredNodeDetached(Node* node) -{ - if (!m_hoverNode || (node != m_hoverNode && (!m_hoverNode->isTextNode() || node != m_hoverNode->parent()))) - return; - - m_hoverNode = node->parent(); - while (m_hoverNode && !m_hoverNode->renderer()) - m_hoverNode = m_hoverNode->parent(); - if (frame()) - frame()->eventHandler()->scheduleHoverStateUpdate(); -} - -void Document::activeChainNodeDetached(Node* node) -{ - if (!m_activeNode || (node != m_activeNode && (!m_activeNode->isTextNode() || node != m_activeNode->parent()))) - return; - - m_activeNode = node->parent(); - while (m_activeNode && !m_activeNode->renderer()) - m_activeNode = m_activeNode->parent(); -} - -#if ENABLE(DASHBOARD_SUPPORT) -const Vector<DashboardRegionValue>& Document::dashboardRegions() const -{ - return m_dashboardRegions; -} - -void Document::setDashboardRegions(const Vector<DashboardRegionValue>& regions) -{ - m_dashboardRegions = regions; - setDashboardRegionsDirty(false); -} -#endif - -bool Document::setFocusedNode(PassRefPtr<Node> newFocusedNode) -{ - // Make sure newFocusedNode is actually in this document - if (newFocusedNode && (newFocusedNode->document() != this)) - return true; - - if (m_focusedNode == newFocusedNode) - return true; - - if (m_inPageCache) - return false; - - bool focusChangeBlocked = false; - RefPtr<Node> oldFocusedNode = m_focusedNode; - m_focusedNode = 0; - - // Remove focus from the existing focus node (if any) - if (oldFocusedNode && !oldFocusedNode->m_inDetach) { - if (oldFocusedNode->active()) - oldFocusedNode->setActive(false); - - oldFocusedNode->setFocus(false); - - // Dispatch a change event for text fields or textareas that have been edited - RenderObject *r = static_cast<RenderObject*>(oldFocusedNode.get()->renderer()); - if (r && (r->isTextArea() || r->isTextField()) && r->isEdited()) { - EventTargetNodeCast(oldFocusedNode.get())->dispatchHTMLEvent(changeEvent, true, false); - if ((r = static_cast<RenderObject*>(oldFocusedNode.get()->renderer()))) - r->setEdited(false); - } - - // Dispatch the blur event and let the node do any other blur related activities (important for text fields) - EventTargetNodeCast(oldFocusedNode.get())->dispatchBlurEvent(); - - if (m_focusedNode) { - // handler shifted focus - focusChangeBlocked = true; - newFocusedNode = 0; - } - EventTargetNodeCast(oldFocusedNode.get())->dispatchUIEvent(DOMFocusOutEvent); - if (m_focusedNode) { - // handler shifted focus - focusChangeBlocked = true; - newFocusedNode = 0; - } - if ((oldFocusedNode.get() == this) && oldFocusedNode->hasOneRef()) - return true; - - if (oldFocusedNode.get() == oldFocusedNode->rootEditableElement()) - frame()->editor()->didEndEditing(); - } - - if (newFocusedNode) { - if (newFocusedNode == newFocusedNode->rootEditableElement() && !acceptsEditingFocus(newFocusedNode.get())) { - // delegate blocks focus change - focusChangeBlocked = true; - goto SetFocusedNodeDone; - } - // Set focus on the new node - m_focusedNode = newFocusedNode.get(); - - // Dispatch the focus event and let the node do any other focus related activities (important for text fields) - EventTargetNodeCast(m_focusedNode.get())->dispatchFocusEvent(); - - if (m_focusedNode != newFocusedNode) { - // handler shifted focus - focusChangeBlocked = true; - goto SetFocusedNodeDone; - } - EventTargetNodeCast(m_focusedNode.get())->dispatchUIEvent(DOMFocusInEvent); - if (m_focusedNode != newFocusedNode) { - // handler shifted focus - focusChangeBlocked = true; - goto SetFocusedNodeDone; - } - m_focusedNode->setFocus(); - - if (m_focusedNode.get() == m_focusedNode->rootEditableElement()) - frame()->editor()->didBeginEditing(); - - // eww, I suck. set the qt focus correctly - // ### find a better place in the code for this - if (view()) { - Widget *focusWidget = widgetForNode(m_focusedNode.get()); - if (focusWidget) { - // Make sure a widget has the right size before giving it focus. - // Otherwise, we are testing edge cases of the Widget code. - // Specifically, in WebCore this does not work well for text fields. - updateLayout(); - // Re-get the widget in case updating the layout changed things. - focusWidget = widgetForNode(m_focusedNode.get()); - } - if (focusWidget) - focusWidget->setFocus(); - else - view()->setFocus(); - } - } - -#if PLATFORM(MAC) && !PLATFORM(CHROMIUM) - if (!focusChangeBlocked && m_focusedNode && AXObjectCache::accessibilityEnabled()) - axObjectCache()->handleFocusedUIElementChanged(); -#endif - -SetFocusedNodeDone: - updateRendering(); - return !focusChangeBlocked; - } - -void Document::setCSSTarget(Node* n) -{ - if (m_cssTarget) - m_cssTarget->setChanged(); - m_cssTarget = n; - if (n) - n->setChanged(); -} - -Node* Document::getCSSTarget() const -{ - return m_cssTarget; -} - -void Document::attachNodeIterator(NodeIterator *ni) -{ - m_nodeIterators.add(ni); -} - -void Document::detachNodeIterator(NodeIterator *ni) -{ - m_nodeIterators.remove(ni); -} - -void Document::nodeChildrenChanged(ContainerNode* container) -{ - if (!page() || !page()->settings()->rangeMutationDisabledForOldAppleMail()) { - HashSet<Range*>::const_iterator end = m_ranges.end(); - for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) - (*it)->nodeChildrenChanged(container); - } -} - -void Document::nodeWillBeRemoved(Node* n) -{ - HashSet<NodeIterator*>::const_iterator nodeIteratorsEnd = m_nodeIterators.end(); - for (HashSet<NodeIterator*>::const_iterator it = m_nodeIterators.begin(); it != nodeIteratorsEnd; ++it) - (*it)->nodeWillBeRemoved(n); - - if (!page() || !page()->settings()->rangeMutationDisabledForOldAppleMail()) { - HashSet<Range*>::const_iterator rangesEnd = m_ranges.end(); - for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != rangesEnd; ++it) - (*it)->nodeWillBeRemoved(n); - } - - if (Frame* frame = this->frame()) { - frame->selection()->nodeWillBeRemoved(n); - frame->dragCaretController()->nodeWillBeRemoved(n); - } -} - -void Document::textInserted(Node* text, unsigned offset, unsigned length) -{ - if (!page() || !page()->settings()->rangeMutationDisabledForOldAppleMail()) { - HashSet<Range*>::const_iterator end = m_ranges.end(); - for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) - (*it)->textInserted(text, offset, length); - } - - // Update the markers for spelling and grammar checking. - shiftMarkers(text, offset, length); -} - -void Document::textRemoved(Node* text, unsigned offset, unsigned length) -{ - if (!page() || !page()->settings()->rangeMutationDisabledForOldAppleMail()) { - HashSet<Range*>::const_iterator end = m_ranges.end(); - for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) - (*it)->textRemoved(text, offset, length); - } - - // Update the markers for spelling and grammar checking. - removeMarkers(text, offset, length); - shiftMarkers(text, offset + length, 0 - length); -} - -void Document::textNodesMerged(Text* oldNode, unsigned offset) -{ - if (!page() || !page()->settings()->rangeMutationDisabledForOldAppleMail()) { - NodeWithIndex oldNodeWithIndex(oldNode); - HashSet<Range*>::const_iterator end = m_ranges.end(); - for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) - (*it)->textNodesMerged(oldNodeWithIndex, offset); - } - - // FIXME: This should update markers for spelling and grammar checking. -} - -void Document::textNodeSplit(Text* oldNode) -{ - if (!page() || !page()->settings()->rangeMutationDisabledForOldAppleMail()) { - HashSet<Range*>::const_iterator end = m_ranges.end(); - for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it) - (*it)->textNodeSplit(oldNode); - } - - // FIXME: This should update markers for spelling and grammar checking. -} - -// FIXME: eventually, this should return a DOMWindow stored in the document. -DOMWindow* Document::domWindow() const -{ - if (!frame()) - return 0; - return frame()->domWindow(); -} - -PassRefPtr<Event> Document::createEvent(const String& eventType, ExceptionCode& ec) -{ - if (eventType == "UIEvents" || eventType == "UIEvent") - return UIEvent::create(); - if (eventType == "MouseEvents" || eventType == "MouseEvent") - return MouseEvent::create(); - if (eventType == "MutationEvents" || eventType == "MutationEvent") - return MutationEvent::create(); - if (eventType == "KeyboardEvents" || eventType == "KeyboardEvent") - return KeyboardEvent::create(); - if (eventType == "HTMLEvents" || eventType == "Event" || eventType == "Events") - return Event::create(); - if (eventType == "ProgressEvent") - return ProgressEvent::create(); - if (eventType == "TextEvent") - return TextEvent::create(); - if (eventType == "OverflowEvent") - return OverflowEvent::create(); - if (eventType == "WheelEvent") - return WheelEvent::create(); -#if ENABLE(SVG) - if (eventType == "SVGEvents") - return Event::create(); - if (eventType == "SVGZoomEvents") - return SVGZoomEvent::create(); -#endif - if (eventType == "MessageEvent") - return MessageEvent::create(); - ec = NOT_SUPPORTED_ERR; - return 0; -} - -CSSStyleDeclaration* Document::getOverrideStyle(Element*, const String&) -{ - return 0; -} - -void Document::handleWindowEvent(Event *evt, bool useCapture) -{ - if (m_windowEventListeners.isEmpty()) - return; - - // if any html event listeners are registered on the window, then dispatch them here - RegisteredEventListenerList listenersCopy = m_windowEventListeners; - RegisteredEventListenerList::iterator it = listenersCopy.begin(); - - for (; it != listenersCopy.end(); ++it) - if ((*it)->eventType() == evt->type() && (*it)->useCapture() == useCapture && !(*it)->removed()) - (*it)->listener()->handleEvent(evt, true); -} - -void Document::setHTMLWindowEventListener(const AtomicString &eventType, PassRefPtr<EventListener> listener) -{ - // If we already have it we don't want removeWindowEventListener to delete it - removeHTMLWindowEventListener(eventType); - if (listener) - addWindowEventListener(eventType, listener, false); -} - -EventListener *Document::getHTMLWindowEventListener(const AtomicString& eventType) -{ - RegisteredEventListenerList::iterator it = m_windowEventListeners.begin(); - for (; it != m_windowEventListeners.end(); ++it) { - if ((*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener()) - return (*it)->listener(); - } - return 0; -} - -void Document::removeHTMLWindowEventListener(const AtomicString& eventType) -{ - RegisteredEventListenerList::iterator it = m_windowEventListeners.begin(); - for (; it != m_windowEventListeners.end(); ++it) { - if ((*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener()) { - if (eventType == unloadEvent) - removePendingFrameUnloadEventCount(); - else if (eventType == beforeunloadEvent) - removePendingFrameBeforeUnloadEventCount(); - m_windowEventListeners.remove(it); - return; - } - } -} - -void Document::addWindowEventListener(const AtomicString &eventType, PassRefPtr<EventListener> listener, bool useCapture) -{ - if (eventType == unloadEvent) - addPendingFrameUnloadEventCount(); - else if (eventType == beforeunloadEvent) - addPendingFrameBeforeUnloadEventCount(); - // Remove existing identical listener set with identical arguments. - // The DOM 2 spec says that "duplicate instances are discarded" in this case. - removeWindowEventListener(eventType, listener.get(), useCapture); - m_windowEventListeners.append(RegisteredEventListener::create(eventType, listener, useCapture)); -} - -void Document::removeWindowEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture) -{ - RegisteredEventListenerList::iterator it = m_windowEventListeners.begin(); - for (; it != m_windowEventListeners.end(); ++it) { - RegisteredEventListener& r = **it; - if (r.eventType() == eventType && r.listener() == listener && r.useCapture() == useCapture) { - if (eventType == unloadEvent) - removePendingFrameUnloadEventCount(); - else if (eventType == beforeunloadEvent) - removePendingFrameBeforeUnloadEventCount(); - m_windowEventListeners.remove(it); - return; - } - } -} - -bool Document::hasWindowEventListener(const AtomicString &eventType) -{ - RegisteredEventListenerList::iterator it = m_windowEventListeners.begin(); - for (; it != m_windowEventListeners.end(); ++it) - if ((*it)->eventType() == eventType) { - return true; - } - return false; -} - -void Document::addPendingFrameUnloadEventCount() -{ - if (m_frame) - m_frame->eventHandler()->addPendingFrameUnloadEventCount(); -} - -void Document::removePendingFrameUnloadEventCount() -{ - if (m_frame) - m_frame->eventHandler()->removePendingFrameUnloadEventCount(); -} - -void Document::addPendingFrameBeforeUnloadEventCount() -{ - if (m_frame) - m_frame->eventHandler()->addPendingFrameBeforeUnloadEventCount(); -} - - void Document::removePendingFrameBeforeUnloadEventCount() -{ - if (m_frame) - m_frame->eventHandler()->removePendingFrameBeforeUnloadEventCount(); -} - -bool Document::hasUnloadEventListener() -{ - return (hasWindowEventListener(unloadEvent) || - hasWindowEventListener(beforeunloadEvent)); -} - -PassRefPtr<EventListener> Document::createHTMLEventListener(const String& functionName, const String& code, Node *node) -{ - if (Frame* frm = frame()) - if (frm->script()->isEnabled()) - return frm->script()->createHTMLEventHandler(functionName, code, node); - return 0; -} - -void Document::setHTMLWindowEventListener(const AtomicString& eventType, Attribute* attr) -{ - setHTMLWindowEventListener(eventType, - createHTMLEventListener(attr->localName().string(), attr->value(), 0)); -} - -void Document::dispatchImageLoadEventSoon(HTMLImageLoader *image) -{ - m_imageLoadEventDispatchSoonList.append(image); - if (!m_imageLoadEventTimer.isActive()) - m_imageLoadEventTimer.startOneShot(0); -} - -void Document::removeImage(HTMLImageLoader* image) -{ - // Remove instances of this image from both lists. - // Use loops because we allow multiple instances to get into the lists. - while (m_imageLoadEventDispatchSoonList.removeRef(image)) { } - while (m_imageLoadEventDispatchingList.removeRef(image)) { } - if (m_imageLoadEventDispatchSoonList.isEmpty()) - m_imageLoadEventTimer.stop(); -} - -void Document::dispatchImageLoadEventsNow() -{ - // need to avoid re-entering this function; if new dispatches are - // scheduled before the parent finishes processing the list, they - // will set a timer and eventually be processed - if (!m_imageLoadEventDispatchingList.isEmpty()) { - return; - } - - m_imageLoadEventTimer.stop(); - - m_imageLoadEventDispatchingList = m_imageLoadEventDispatchSoonList; - m_imageLoadEventDispatchSoonList.clear(); - for (DeprecatedPtrListIterator<HTMLImageLoader> it(m_imageLoadEventDispatchingList); it.current();) { - HTMLImageLoader* image = it.current(); - // Must advance iterator *before* dispatching call. - // Otherwise, it might be advanced automatically if dispatching the call had a side effect - // of destroying the current HTMLImageLoader, and then we would advance past the *next* item, - // missing one altogether. - ++it; - image->dispatchLoadEvent(); - } - m_imageLoadEventDispatchingList.clear(); -} - -void Document::imageLoadEventTimerFired(Timer<Document>*) -{ - dispatchImageLoadEventsNow(); -} - -Element* Document::ownerElement() const -{ - if (!frame()) - return 0; - return frame()->ownerElement(); -} - -String Document::cookie() const -{ - return cookies(this, cookieURL()); -} - -void Document::setCookie(const String& value) -{ - setCookies(this, cookieURL(), policyBaseURL(), value); -} - -String Document::referrer() const -{ - if (frame()) - return frame()->loader()->referrer(); - return String(); -} - -String Document::domain() const -{ - return m_securityOrigin->domain(); -} - -void Document::setDomain(const String& newDomain) -{ - // Both NS and IE specify that changing the domain is only allowed when - // the new domain is a suffix of the old domain. - - // FIXME: We should add logging indicating why a domain was not allowed. - - // If the new domain is the same as the old domain, still call - // m_securityOrigin.setDomainForDOM. This will change the - // security check behavior. For example, if a page loaded on port 8000 - // assigns its current domain using document.domain, the page will - // allow other pages loaded on different ports in the same domain that - // have also assigned to access this page. - if (equalIgnoringCase(domain(), newDomain)) { - m_securityOrigin->setDomainFromDOM(newDomain); - return; - } - - int oldLength = domain().length(); - int newLength = newDomain.length(); - // e.g. newDomain = webkit.org (10) and domain() = www.webkit.org (14) - if (newLength >= oldLength) - return; - - String test = domain(); - // Check that it's a subdomain, not e.g. "ebkit.org" - if (test[oldLength - newLength - 1] != '.') - return; - - // Now test is "webkit.org" from domain() - // and we check that it's the same thing as newDomain - test.remove(0, oldLength - newLength); - if (test != newDomain) - return; - - m_securityOrigin->setDomainFromDOM(newDomain); -} - -String Document::lastModified() const -{ - Frame* f = frame(); - if (!f) - return String(); - DocumentLoader* loader = f->loader()->documentLoader(); - if (!loader) - return String(); - return loader->response().httpHeaderField("Last-Modified"); -} - -static bool isValidNameNonASCII(const UChar* characters, unsigned length) -{ - unsigned i = 0; - - UChar32 c; - U16_NEXT(characters, i, length, c) - if (!isValidNameStart(c)) - return false; - - while (i < length) { - U16_NEXT(characters, i, length, c) - if (!isValidNamePart(c)) - return false; - } - - return true; -} - -static inline bool isValidNameASCII(const UChar* characters, unsigned length) -{ - UChar c = characters[0]; - if (!(isASCIIAlpha(c) || c == ':' || c == '_')) - return false; - - for (unsigned i = 1; i < length; ++i) { - c = characters[i]; - if (!(isASCIIAlphanumeric(c) || c == ':' || c == '_' || c == '-' || c == '.')) - return false; - } - - return true; -} - -bool Document::isValidName(const String& name) -{ - unsigned length = name.length(); - if (!length) - return false; - - const UChar* characters = name.characters(); - return isValidNameASCII(characters, length) || isValidNameNonASCII(characters, length); -} - -bool Document::parseQualifiedName(const String& qualifiedName, String& prefix, String& localName, ExceptionCode& ec) -{ - unsigned length = qualifiedName.length(); - - if (length == 0) { - ec = INVALID_CHARACTER_ERR; - return false; - } - - bool nameStart = true; - bool sawColon = false; - int colonPos = 0; - - const UChar* s = qualifiedName.characters(); - for (unsigned i = 0; i < length;) { - UChar32 c; - U16_NEXT(s, i, length, c) - if (c == ':') { - if (sawColon) { - ec = NAMESPACE_ERR; - return false; // multiple colons: not allowed - } - nameStart = true; - sawColon = true; - colonPos = i - 1; - } else if (nameStart) { - if (!isValidNameStart(c)) { - ec = INVALID_CHARACTER_ERR; - return false; - } - nameStart = false; - } else { - if (!isValidNamePart(c)) { - ec = INVALID_CHARACTER_ERR; - return false; - } - } - } - - if (!sawColon) { - prefix = String(); - localName = qualifiedName; - } else { - prefix = qualifiedName.substring(0, colonPos); - if (prefix.isEmpty()) { - ec = NAMESPACE_ERR; - return false; - } - localName = qualifiedName.substring(colonPos + 1); - } - - if (localName.isEmpty()) { - ec = NAMESPACE_ERR; - return false; - } - - return true; -} - -void Document::addImageMap(HTMLMapElement* imageMap) -{ - const AtomicString& name = imageMap->getName(); - if (!name.impl()) - return; - - // Add the image map, unless there's already another with that name. - // "First map wins" is the rule other browsers seem to implement. - m_imageMapsByName.add(name.impl(), imageMap); -} - -void Document::removeImageMap(HTMLMapElement* imageMap) -{ - // Remove the image map by name. - // But don't remove some other image map that just happens to have the same name. - // FIXME: Use a HashCountedSet as we do for IDs to find the first remaining map - // once a map has been removed. - const AtomicString& name = imageMap->getName(); - if (!name.impl()) - return; - - ImageMapsByName::iterator it = m_imageMapsByName.find(name.impl()); - if (it != m_imageMapsByName.end() && it->second == imageMap) - m_imageMapsByName.remove(it); -} - -HTMLMapElement *Document::getImageMap(const String& url) const -{ - if (url.isNull()) - return 0; - int hashPos = url.find('#'); - String name = (hashPos < 0 ? url : url.substring(hashPos + 1)).impl(); - AtomicString mapName = isHTMLDocument() ? name.lower() : name; - return m_imageMapsByName.get(mapName.impl()); -} - -void Document::setDecoder(PassRefPtr<TextResourceDecoder> decoder) -{ - m_decoder = decoder; -} - -UChar Document::backslashAsCurrencySymbol() const -{ - if (!m_decoder) - return '\\'; - return m_decoder->encoding().backslashAsCurrencySymbol(); -} - -KURL Document::completeURL(const String& url) const -{ - // Always return a null URL when passed a null string. - // FIXME: Should we change the KURL constructor to have this behavior? - if (url.isNull()) - return KURL(); - if (!m_decoder) - return KURL(m_baseURL, url); - return KURL(m_baseURL, url, m_decoder->encoding()); -} - -bool Document::inPageCache() -{ - return m_inPageCache; -} - -void Document::setInPageCache(bool flag) -{ - if (m_inPageCache == flag) - return; - - m_inPageCache = flag; - if (flag) { - ASSERT(m_savedRenderer == 0); - m_savedRenderer = renderer(); - if (FrameView* v = view()) - v->resetScrollbars(); - } else { - ASSERT(renderer() == 0 || renderer() == m_savedRenderer); - ASSERT(m_renderArena); - setRenderer(m_savedRenderer); - m_savedRenderer = 0; - } -} - -void Document::willSaveToCache() -{ - HashSet<Element*>::iterator end = m_pageCacheCallbackElements.end(); - for (HashSet<Element*>::iterator i = m_pageCacheCallbackElements.begin(); i != end; ++i) - (*i)->willSaveToCache(); -} - -void Document::didRestoreFromCache() -{ - HashSet<Element*>::iterator end = m_pageCacheCallbackElements.end(); - for (HashSet<Element*>::iterator i = m_pageCacheCallbackElements.begin(); i != end; ++i) - (*i)->didRestoreFromCache(); -} - -void Document::registerForCacheCallbacks(Element* e) -{ - m_pageCacheCallbackElements.add(e); -} - -void Document::unregisterForCacheCallbacks(Element* e) -{ - m_pageCacheCallbackElements.remove(e); -} - -void Document::setShouldCreateRenderers(bool f) -{ - m_createRenderers = f; -} - -bool Document::shouldCreateRenderers() -{ - return m_createRenderers; -} - -// Support for Javascript execCommand, and related methods - -static Editor::Command command(Document* document, const String& commandName, bool userInterface = false) -{ - Frame* frame = document->frame(); - if (!frame || frame->document() != document) - return Editor::Command(); - return frame->editor()->command(commandName, - userInterface ? CommandFromDOMWithUserInterface : CommandFromDOM); -} - -bool Document::execCommand(const String& commandName, bool userInterface, const String& value) -{ - return command(this, commandName, userInterface).execute(value); -} - -bool Document::queryCommandEnabled(const String& commandName) -{ - return command(this, commandName).isEnabled(); -} - -bool Document::queryCommandIndeterm(const String& commandName) -{ - return command(this, commandName).state() == MixedTriState; -} - -bool Document::queryCommandState(const String& commandName) -{ - return command(this, commandName).state() != FalseTriState; -} - -bool Document::queryCommandSupported(const String& commandName) -{ - return command(this, commandName).isSupported(); -} - -String Document::queryCommandValue(const String& commandName) -{ - return command(this, commandName).value(); -} - -static IntRect placeholderRectForMarker() -{ - return IntRect(-1, -1, -1, -1); -} - -void Document::addMarker(Range *range, DocumentMarker::MarkerType type, String description) -{ - // Use a TextIterator to visit the potentially multiple nodes the range covers. - for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) { - RefPtr<Range> textPiece = markedText.range(); - int exception = 0; - DocumentMarker marker = {type, textPiece->startOffset(exception), textPiece->endOffset(exception), description}; - addMarker(textPiece->startContainer(exception), marker); - } -} - -void Document::removeMarkers(Range* range, DocumentMarker::MarkerType markerType) -{ - if (m_markers.isEmpty()) - return; - - ExceptionCode ec = 0; - Node* startContainer = range->startContainer(ec); - Node* endContainer = range->endContainer(ec); - - Node* pastLastNode = range->pastLastNode(); - for (Node* node = range->firstNode(); node != pastLastNode; node = node->traverseNextNode()) { - int startOffset = node == startContainer ? range->startOffset(ec) : 0; - int endOffset = node == endContainer ? range->endOffset(ec) : INT_MAX; - int length = endOffset - startOffset; - removeMarkers(node, startOffset, length, markerType); - } -} - -// Markers are stored in order sorted by their start offset. -// Markers of the same type do not overlap each other. - -void Document::addMarker(Node* node, DocumentMarker newMarker) -{ - ASSERT(newMarker.endOffset >= newMarker.startOffset); - if (newMarker.endOffset == newMarker.startOffset) - return; - - MarkerMapVectorPair* vectorPair = m_markers.get(node); - - if (!vectorPair) { - vectorPair = new MarkerMapVectorPair; - vectorPair->first.append(newMarker); - vectorPair->second.append(placeholderRectForMarker()); - m_markers.set(node, vectorPair); - } else { - Vector<DocumentMarker>& markers = vectorPair->first; - Vector<IntRect>& rects = vectorPair->second; - size_t numMarkers = markers.size(); - ASSERT(numMarkers == rects.size()); - size_t i; - // Iterate over all markers whose start offset is less than or equal to the new marker's. - // If one of them is of the same type as the new marker and touches it or intersects with it - // (there is at most one), remove it and adjust the new marker's start offset to encompass it. - for (i = 0; i < numMarkers; ++i) { - DocumentMarker marker = markers[i]; - if (marker.startOffset > newMarker.startOffset) - break; - if (marker.type == newMarker.type && marker.endOffset >= newMarker.startOffset) { - newMarker.startOffset = marker.startOffset; - markers.remove(i); - rects.remove(i); - numMarkers--; - break; - } - } - size_t j = i; - // Iterate over all markers whose end offset is less than or equal to the new marker's, - // removing markers of the same type as the new marker which touch it or intersect with it, - // adjusting the new marker's end offset to cover them if necessary. - while (j < numMarkers) { - DocumentMarker marker = markers[j]; - if (marker.startOffset > newMarker.endOffset) - break; - if (marker.type == newMarker.type) { - markers.remove(j); - rects.remove(j); - if (newMarker.endOffset <= marker.endOffset) { - newMarker.endOffset = marker.endOffset; - break; - } - numMarkers--; - } else - j++; - } - // At this point i points to the node before which we want to insert. - markers.insert(i, newMarker); - rects.insert(i, placeholderRectForMarker()); - } - - // repaint the affected node - if (node->renderer()) - node->renderer()->repaint(); -} - -// copies markers from srcNode to dstNode, applying the specified shift delta to the copies. The shift is -// useful if, e.g., the caller has created the dstNode from a non-prefix substring of the srcNode. -void Document::copyMarkers(Node *srcNode, unsigned startOffset, int length, Node *dstNode, int delta, DocumentMarker::MarkerType markerType) -{ - if (length <= 0) - return; - - MarkerMapVectorPair* vectorPair = m_markers.get(srcNode); - if (!vectorPair) - return; - - ASSERT(vectorPair->first.size() == vectorPair->second.size()); - - bool docDirty = false; - unsigned endOffset = startOffset + length - 1; - Vector<DocumentMarker>& markers = vectorPair->first; - for (size_t i = 0; i != markers.size(); ++i) { - DocumentMarker marker = markers[i]; - - // stop if we are now past the specified range - if (marker.startOffset > endOffset) - break; - - // skip marker that is before the specified range or is the wrong type - if (marker.endOffset < startOffset || (marker.type != markerType && markerType != DocumentMarker::AllMarkers)) - continue; - - // pin the marker to the specified range and apply the shift delta - docDirty = true; - if (marker.startOffset < startOffset) - marker.startOffset = startOffset; - if (marker.endOffset > endOffset) - marker.endOffset = endOffset; - marker.startOffset += delta; - marker.endOffset += delta; - - addMarker(dstNode, marker); - } - - // repaint the affected node - if (docDirty && dstNode->renderer()) - dstNode->renderer()->repaint(); -} - -void Document::removeMarkers(Node* node, unsigned startOffset, int length, DocumentMarker::MarkerType markerType) -{ - if (length <= 0) - return; - - MarkerMapVectorPair* vectorPair = m_markers.get(node); - if (!vectorPair) - return; - - Vector<DocumentMarker>& markers = vectorPair->first; - Vector<IntRect>& rects = vectorPair->second; - ASSERT(markers.size() == rects.size()); - bool docDirty = false; - unsigned endOffset = startOffset + length; - for (size_t i = 0; i < markers.size();) { - DocumentMarker marker = markers[i]; - - // markers are returned in order, so stop if we are now past the specified range - if (marker.startOffset >= endOffset) - break; - - // skip marker that is wrong type or before target - if (marker.endOffset < startOffset || (marker.type != markerType && markerType != DocumentMarker::AllMarkers)) { - i++; - continue; - } - - // at this point we know that marker and target intersect in some way - docDirty = true; - - // pitch the old marker and any associated rect - markers.remove(i); - rects.remove(i); - - // add either of the resulting slices that are left after removing target - if (startOffset > marker.startOffset) { - DocumentMarker newLeft = marker; - newLeft.endOffset = startOffset; - markers.insert(i, newLeft); - rects.insert(i, placeholderRectForMarker()); - // i now points to the newly-inserted node, but we want to skip that one - i++; - } - if (marker.endOffset > endOffset) { - DocumentMarker newRight = marker; - newRight.startOffset = endOffset; - markers.insert(i, newRight); - rects.insert(i, placeholderRectForMarker()); - // i now points to the newly-inserted node, but we want to skip that one - i++; - } - } - - if (markers.isEmpty()) { - ASSERT(rects.isEmpty()); - m_markers.remove(node); - delete vectorPair; - } - - // repaint the affected node - if (docDirty && node->renderer()) - node->renderer()->repaint(); -} - -DocumentMarker* Document::markerContainingPoint(const IntPoint& point, DocumentMarker::MarkerType markerType) -{ - // outer loop: process each node that contains any markers - MarkerMap::iterator end = m_markers.end(); - for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) { - // inner loop; process each marker in this node - MarkerMapVectorPair* vectorPair = nodeIterator->second; - Vector<DocumentMarker>& markers = vectorPair->first; - Vector<IntRect>& rects = vectorPair->second; - ASSERT(markers.size() == rects.size()); - unsigned markerCount = markers.size(); - for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) { - DocumentMarker& marker = markers[markerIndex]; - - // skip marker that is wrong type - if (marker.type != markerType && markerType != DocumentMarker::AllMarkers) - continue; - - IntRect& r = rects[markerIndex]; - - // skip placeholder rects - if (r == placeholderRectForMarker()) - continue; - - if (r.contains(point)) - return ▮ - } - } - - return 0; -} - -Vector<DocumentMarker> Document::markersForNode(Node* node) -{ - MarkerMapVectorPair* vectorPair = m_markers.get(node); - if (vectorPair) - return vectorPair->first; - return Vector<DocumentMarker>(); -} - -Vector<IntRect> Document::renderedRectsForMarkers(DocumentMarker::MarkerType markerType) -{ - Vector<IntRect> result; - - // outer loop: process each node - MarkerMap::iterator end = m_markers.end(); - for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) { - // inner loop; process each marker in this node - MarkerMapVectorPair* vectorPair = nodeIterator->second; - Vector<DocumentMarker>& markers = vectorPair->first; - Vector<IntRect>& rects = vectorPair->second; - ASSERT(markers.size() == rects.size()); - unsigned markerCount = markers.size(); - for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) { - DocumentMarker marker = markers[markerIndex]; - - // skip marker that is wrong type - if (marker.type != markerType && markerType != DocumentMarker::AllMarkers) - continue; - - IntRect r = rects[markerIndex]; - // skip placeholder rects - if (r == placeholderRectForMarker()) - continue; - - result.append(r); - } - } - - return result; -} - -void Document::removeMarkers(Node* node) -{ - MarkerMap::iterator i = m_markers.find(node); - if (i != m_markers.end()) { - delete i->second; - m_markers.remove(i); - if (RenderObject* renderer = node->renderer()) - renderer->repaint(); - } -} - -void Document::removeMarkers(DocumentMarker::MarkerType markerType) -{ - // outer loop: process each markered node in the document - MarkerMap markerMapCopy = m_markers; - MarkerMap::iterator end = markerMapCopy.end(); - for (MarkerMap::iterator i = markerMapCopy.begin(); i != end; ++i) { - Node* node = i->first.get(); - bool nodeNeedsRepaint = false; - - // inner loop: process each marker in the current node - MarkerMapVectorPair* vectorPair = i->second; - Vector<DocumentMarker>& markers = vectorPair->first; - Vector<IntRect>& rects = vectorPair->second; - ASSERT(markers.size() == rects.size()); - for (size_t i = 0; i != markers.size();) { - DocumentMarker marker = markers[i]; - - // skip nodes that are not of the specified type - if (marker.type != markerType && markerType != DocumentMarker::AllMarkers) { - ++i; - continue; - } - - // pitch the old marker - markers.remove(i); - rects.remove(i); - nodeNeedsRepaint = true; - // markerIterator now points to the next node - } - - // Redraw the node if it changed. Do this before the node is removed from m_markers, since - // m_markers might contain the last reference to the node. - if (nodeNeedsRepaint) { - RenderObject* renderer = node->renderer(); - if (renderer) - renderer->repaint(); - } - - // delete the node's list if it is now empty - if (markers.isEmpty()) { - ASSERT(rects.isEmpty()); - m_markers.remove(node); - delete vectorPair; - } - } -} - -void Document::repaintMarkers(DocumentMarker::MarkerType markerType) -{ - // outer loop: process each markered node in the document - MarkerMap::iterator end = m_markers.end(); - for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) { - Node* node = i->first.get(); - - // inner loop: process each marker in the current node - MarkerMapVectorPair* vectorPair = i->second; - Vector<DocumentMarker>& markers = vectorPair->first; - bool nodeNeedsRepaint = false; - for (size_t i = 0; i != markers.size(); ++i) { - DocumentMarker marker = markers[i]; - - // skip nodes that are not of the specified type - if (marker.type == markerType || markerType == DocumentMarker::AllMarkers) { - nodeNeedsRepaint = true; - break; - } - } - - if (!nodeNeedsRepaint) - continue; - - // cause the node to be redrawn - if (RenderObject* renderer = node->renderer()) - renderer->repaint(); - } -} - -void Document::setRenderedRectForMarker(Node* node, DocumentMarker marker, const IntRect& r) -{ - MarkerMapVectorPair* vectorPair = m_markers.get(node); - if (!vectorPair) { - ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about - return; - } - - Vector<DocumentMarker>& markers = vectorPair->first; - ASSERT(markers.size() == vectorPair->second.size()); - unsigned markerCount = markers.size(); - for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) { - DocumentMarker m = markers[markerIndex]; - if (m == marker) { - vectorPair->second[markerIndex] = r; - return; - } - } - - ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about -} - -void Document::invalidateRenderedRectsForMarkersInRect(const IntRect& r) -{ - // outer loop: process each markered node in the document - MarkerMap::iterator end = m_markers.end(); - for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) { - - // inner loop: process each rect in the current node - MarkerMapVectorPair* vectorPair = i->second; - Vector<IntRect>& rects = vectorPair->second; - - unsigned rectCount = rects.size(); - for (unsigned rectIndex = 0; rectIndex < rectCount; ++rectIndex) - if (rects[rectIndex].intersects(r)) - rects[rectIndex] = placeholderRectForMarker(); - } -} - -void Document::shiftMarkers(Node *node, unsigned startOffset, int delta, DocumentMarker::MarkerType markerType) -{ - MarkerMapVectorPair* vectorPair = m_markers.get(node); - if (!vectorPair) - return; - - Vector<DocumentMarker>& markers = vectorPair->first; - Vector<IntRect>& rects = vectorPair->second; - ASSERT(markers.size() == rects.size()); - - bool docDirty = false; - for (size_t i = 0; i != markers.size(); ++i) { - DocumentMarker &marker = markers[i]; - if (marker.startOffset >= startOffset && (markerType == DocumentMarker::AllMarkers || marker.type == markerType)) { - ASSERT((int)marker.startOffset + delta >= 0); - marker.startOffset += delta; - marker.endOffset += delta; - docDirty = true; - - // Marker moved, so previously-computed rendered rectangle is now invalid - rects[i] = placeholderRectForMarker(); - } - } - - // repaint the affected node - if (docDirty && node->renderer()) - node->renderer()->repaint(); -} - -#if ENABLE(XSLT) - -void Document::applyXSLTransform(ProcessingInstruction* pi) -{ - RefPtr<XSLTProcessor> processor = XSLTProcessor::create(); - processor->setXSLStyleSheet(static_cast<XSLStyleSheet*>(pi->sheet())); - String resultMIMEType; - String newSource; - String resultEncoding; - if (!processor->transformToString(this, resultMIMEType, newSource, resultEncoding)) - return; - // FIXME: If the transform failed we should probably report an error (like Mozilla does). - processor->createDocumentFromSource(newSource, resultEncoding, resultMIMEType, this, frame()); -} - -void Document::setTransformSource(void* doc) -{ - if (doc == m_transformSource) - return; - - xmlFreeDoc((xmlDocPtr)m_transformSource); - m_transformSource = doc; -} - -#endif - -void Document::setDesignMode(InheritedBool value) -{ - m_designMode = value; -} - -Document::InheritedBool Document::getDesignMode() const -{ - return m_designMode; -} - -bool Document::inDesignMode() const -{ - for (const Document* d = this; d; d = d->parentDocument()) { - if (d->m_designMode != inherit) - return d->m_designMode; - } - return false; -} - -Document *Document::parentDocument() const -{ - Frame *childPart = frame(); - if (!childPart) - return 0; - Frame *parent = childPart->tree()->parent(); - if (!parent) - return 0; - return parent->document(); -} - -Document *Document::topDocument() const -{ - Document *doc = const_cast<Document *>(this); - Element *element; - while ((element = doc->ownerElement())) - doc = element->document(); - - return doc; -} - -PassRefPtr<Attr> Document::createAttributeNS(const String& namespaceURI, const String& qualifiedName, ExceptionCode& ec, bool shouldIgnoreNamespaceChecks) -{ - String prefix, localName; - if (!parseQualifiedName(qualifiedName, prefix, localName, ec)) - return 0; - - QualifiedName qName(prefix, localName, namespaceURI); - if (!shouldIgnoreNamespaceChecks && hasPrefixNamespaceMismatch(qName)) { - ec = NAMESPACE_ERR; - return 0; - } - - // Spec: DOM Level 2 Core: http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-DocCrAttrNS - if (!shouldIgnoreNamespaceChecks && qName.localName() == "xmlns" && qName.namespaceURI() != "http://www.w3.org/2000/xmlns/") { - ec = NAMESPACE_ERR; - return 0; - } - - // FIXME: Assume this is a mapped attribute, since createAttribute isn't namespace-aware. There's no harm to XML - // documents if we're wrong. - return new Attr(0, this, MappedAttribute::create(qName, StringImpl::empty())); -} - -#if ENABLE(SVG) -const SVGDocumentExtensions* Document::svgExtensions() -{ - return m_svgExtensions; -} - -SVGDocumentExtensions* Document::accessSVGExtensions() -{ - if (!m_svgExtensions) - m_svgExtensions = new SVGDocumentExtensions(this); - return m_svgExtensions; -} -#endif - -PassRefPtr<HTMLCollection> Document::images() -{ - return HTMLCollection::create(this, HTMLCollection::DocImages); -} - -PassRefPtr<HTMLCollection> Document::applets() -{ - return HTMLCollection::create(this, HTMLCollection::DocApplets); -} - -PassRefPtr<HTMLCollection> Document::embeds() -{ - return HTMLCollection::create(this, HTMLCollection::DocEmbeds); -} - -PassRefPtr<HTMLCollection> Document::plugins() -{ - // This is an alias for embeds() required for the JS DOM bindings. - return HTMLCollection::create(this, HTMLCollection::DocEmbeds); -} - -PassRefPtr<HTMLCollection> Document::objects() -{ - return HTMLCollection::create(this, HTMLCollection::DocObjects); -} - -PassRefPtr<HTMLCollection> Document::scripts() -{ - return HTMLCollection::create(this, HTMLCollection::DocScripts); -} - -PassRefPtr<HTMLCollection> Document::links() -{ - return HTMLCollection::create(this, HTMLCollection::DocLinks); -} - -PassRefPtr<HTMLCollection> Document::forms() -{ - return HTMLCollection::create(this, HTMLCollection::DocForms); -} - -PassRefPtr<HTMLCollection> Document::anchors() -{ - return HTMLCollection::create(this, HTMLCollection::DocAnchors); -} - -PassRefPtr<HTMLCollection> Document::all() -{ - return HTMLCollection::create(this, HTMLCollection::DocAll); -} - -PassRefPtr<HTMLCollection> Document::windowNamedItems(const String &name) -{ - return HTMLNameCollection::create(this, HTMLCollection::WindowNamedItems, name); -} - -PassRefPtr<HTMLCollection> Document::documentNamedItems(const String &name) -{ - return HTMLNameCollection::create(this, HTMLCollection::DocumentNamedItems, name); -} - -HTMLCollection::CollectionInfo* Document::nameCollectionInfo(HTMLCollection::Type type, const AtomicString& name) -{ - ASSERT(type >= HTMLCollection::FirstNamedDocumentCachedType); - unsigned index = type - HTMLCollection::FirstNamedDocumentCachedType; - ASSERT(index < HTMLCollection::NumNamedDocumentCachedTypes); - - NamedCollectionMap& map = m_nameCollectionInfo[index]; - NamedCollectionMap::iterator iter = map.find(name.impl()); - if (iter == map.end()) - iter = map.add(name.impl(), new HTMLCollection::CollectionInfo).first; - return iter->second; -} - -void Document::finishedParsing() -{ - setParsing(false); - - ExceptionCode ec = 0; - dispatchEvent(Event::create(DOMContentLoadedEvent, true, false), ec); - - if (Frame* f = frame()) - f->loader()->finishedParsing(); -} - -Vector<String> Document::formElementsState() const -{ - Vector<String> stateVector; - stateVector.reserveCapacity(m_formElementsWithState.size() * 3); - typedef ListHashSet<HTMLFormControlElementWithState*>::const_iterator Iterator; - Iterator end = m_formElementsWithState.end(); - for (Iterator it = m_formElementsWithState.begin(); it != end; ++it) { - HTMLFormControlElementWithState* e = *it; - String value; - if (e->saveState(value)) { - stateVector.append(e->name().string()); - stateVector.append(e->type().string()); - stateVector.append(value); - } - } - return stateVector; -} - -#if ENABLE(XPATH) - -PassRefPtr<XPathExpression> Document::createExpression(const String& expression, - XPathNSResolver* resolver, - ExceptionCode& ec) -{ - if (!m_xpathEvaluator) - m_xpathEvaluator = XPathEvaluator::create(); - return m_xpathEvaluator->createExpression(expression, resolver, ec); -} - -PassRefPtr<XPathNSResolver> Document::createNSResolver(Node* nodeResolver) -{ - if (!m_xpathEvaluator) - m_xpathEvaluator = XPathEvaluator::create(); - return m_xpathEvaluator->createNSResolver(nodeResolver); -} - -PassRefPtr<XPathResult> Document::evaluate(const String& expression, - Node* contextNode, - XPathNSResolver* resolver, - unsigned short type, - XPathResult* result, - ExceptionCode& ec) -{ - if (!m_xpathEvaluator) - m_xpathEvaluator = XPathEvaluator::create(); - return m_xpathEvaluator->evaluate(expression, contextNode, resolver, type, result, ec); -} - -#endif // ENABLE(XPATH) - -void Document::setStateForNewFormElements(const Vector<String>& stateVector) -{ - // Walk the state vector backwards so that the value to use for each - // name/type pair first is the one at the end of each individual vector - // in the FormElementStateMap. We're using them like stacks. - typedef FormElementStateMap::iterator Iterator; - m_formElementsWithState.clear(); - for (size_t i = stateVector.size() / 3 * 3; i; i -= 3) { - AtomicString a = stateVector[i - 3]; - AtomicString b = stateVector[i - 2]; - const String& c = stateVector[i - 1]; - FormElementKey key(a.impl(), b.impl()); - Iterator it = m_stateForNewFormElements.find(key); - if (it != m_stateForNewFormElements.end()) - it->second.append(c); - else { - Vector<String> v(1); - v[0] = c; - m_stateForNewFormElements.set(key, v); - } - } -} - -bool Document::hasStateForNewFormElements() const -{ - return !m_stateForNewFormElements.isEmpty(); -} - -bool Document::takeStateForFormElement(AtomicStringImpl* name, AtomicStringImpl* type, String& state) -{ - typedef FormElementStateMap::iterator Iterator; - Iterator it = m_stateForNewFormElements.find(FormElementKey(name, type)); - if (it == m_stateForNewFormElements.end()) - return false; - ASSERT(it->second.size()); - state = it->second.last(); - if (it->second.size() > 1) - it->second.removeLast(); - else - m_stateForNewFormElements.remove(it); - return true; -} - -FormElementKey::FormElementKey(AtomicStringImpl* name, AtomicStringImpl* type) - : m_name(name), m_type(type) -{ - ref(); -} - -FormElementKey::~FormElementKey() -{ - deref(); -} - -FormElementKey::FormElementKey(const FormElementKey& other) - : m_name(other.name()), m_type(other.type()) -{ - ref(); -} - -FormElementKey& FormElementKey::operator=(const FormElementKey& other) -{ - other.ref(); - deref(); - m_name = other.name(); - m_type = other.type(); - return *this; -} - -void FormElementKey::ref() const -{ - if (name()) - name()->ref(); - if (type()) - type()->ref(); -} - -void FormElementKey::deref() const -{ - if (name()) - name()->deref(); - if (type()) - type()->deref(); -} - -unsigned FormElementKeyHash::hash(const FormElementKey& k) -{ - ASSERT(sizeof(k) % (sizeof(uint16_t) * 2) == 0); - - unsigned l = sizeof(k) / (sizeof(uint16_t) * 2); - const uint16_t* s = reinterpret_cast<const uint16_t*>(&k); - uint32_t hash = PHI; - - // Main loop - for (; l > 0; l--) { - hash += s[0]; - uint32_t tmp = (s[1] << 11) ^ hash; - hash = (hash << 16) ^ tmp; - s += 2; - hash += hash >> 11; - } - - // Force "avalanching" of final 127 bits - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 2; - hash += hash >> 15; - hash ^= hash << 10; - - // this avoids ever returning a hash code of 0, since that is used to - // signal "hash not computed yet", using a value that is likely to be - // effectively the same as 0 when the low bits are masked - if (hash == 0) - hash = 0x80000000; - - return hash; -} - -void Document::setIconURL(const String& iconURL, const String& type) -{ - // FIXME - <rdar://problem/4727645> - At some point in the future, we might actually honor the "type" - if (m_iconURL.isEmpty()) - m_iconURL = iconURL; - else if (!type.isEmpty()) - m_iconURL = iconURL; -} - -void Document::setUseSecureKeyboardEntryWhenActive(bool usesSecureKeyboard) -{ - if (m_useSecureKeyboardEntryWhenActive == usesSecureKeyboard) - return; - - m_useSecureKeyboardEntryWhenActive = usesSecureKeyboard; - m_frame->updateSecureKeyboardEntryIfActive(); -} - -bool Document::useSecureKeyboardEntryWhenActive() const -{ - return m_useSecureKeyboardEntryWhenActive; -} - -void Document::initSecurityContext() -{ - if (m_securityOrigin && !m_securityOrigin->isEmpty()) - return; // m_securityOrigin has already been initialized. - - if (!m_frame) { - // No source for a security context. - // This can occur via document.implementation.createDocument(). - m_cookieURL = KURL(""); - m_securityOrigin = SecurityOrigin::createEmpty(); - return; - } - - // In the common case, create the security context from the currently - // loading URL. - const KURL& url = m_frame->loader()->url(); - m_cookieURL = url; - m_securityOrigin = SecurityOrigin::create(url); - - if (FrameLoader::allowSubstituteDataAccessToLocal()) { - // If this document was loaded with substituteData, then the document can - // load local resources. See https://bugs.webkit.org/show_bug.cgi?id=16756 - // and https://bugs.webkit.org/show_bug.cgi?id=19760 for further - // discussion. - DocumentLoader* documentLoader = m_frame->loader()->documentLoader(); - if (documentLoader && documentLoader->substituteData().isValid()) - m_securityOrigin->grantLoadLocalResources(); - } - - if (!m_securityOrigin->isEmpty()) - return; - - // If we do not obtain a meaningful origin from the URL, then we try to - // find one via the frame hierarchy. - - Frame* ownerFrame = m_frame->tree()->parent(); - if (!ownerFrame) - ownerFrame = m_frame->loader()->opener(); - - if (ownerFrame && ownerFrame->document()) { - m_cookieURL = ownerFrame->document()->cookieURL(); - // We alias the SecurityOrigins to match Firefox, see Bug 15313 - // https://bugs.webkit.org/show_bug.cgi?id=15313 - m_securityOrigin = ownerFrame->document()->securityOrigin(); - } -} - -void Document::setSecurityOrigin(SecurityOrigin* securityOrigin) -{ - m_securityOrigin = securityOrigin; - initDNSPrefetchEnabled(); -} - -void Document::updateFocusAppearanceSoon() -{ - if (!m_updateFocusAppearanceTimer.isActive()) - m_updateFocusAppearanceTimer.startOneShot(0); -} - -void Document::cancelFocusAppearanceUpdate() -{ - m_updateFocusAppearanceTimer.stop(); -} - -void Document::updateFocusAppearanceTimerFired(Timer<Document>*) -{ - Node* node = focusedNode(); - if (!node) - return; - if (!node->isElementNode()) - return; - - updateLayout(); - - Element* element = static_cast<Element*>(node); - if (element->isFocusable()) - element->updateFocusAppearance(false); -} - -// FF method for accessing the selection added for compatability. -DOMSelection* Document::getSelection() const -{ - return frame() ? frame()->domWindow()->getSelection() : 0; -} - -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; -} - -unsigned Document::visitedLinkHash(const AtomicString& attributeURL) const -{ - 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 AlreadyHashed::avoidDeletedValue(attributeURL.string().impl()->hash()); - - 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 AlreadyHashed::avoidDeletedValue(StringImpl::computeHash(buffer.data(), buffer.size())); - } - - switch (characters[0]) { - case '/': - buffer.append(m_baseURL.string().characters(), m_baseURL.pathStart()); - break; - case '#': - buffer.append(m_baseURL.string().characters(), m_baseURL.pathEnd()); - break; - default: - buffer.append(m_baseURL.string().characters(), m_baseURL.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 AlreadyHashed::avoidDeletedValue(StringImpl::computeHash(buffer.data(), buffer.size())); -} - -#if ENABLE(DATABASE) - -void Document::addOpenDatabase(Database* database) -{ - if (!m_openDatabaseSet) - m_openDatabaseSet.set(new DatabaseSet); - - ASSERT(!m_openDatabaseSet->contains(database)); - m_openDatabaseSet->add(database); -} - -void Document::removeOpenDatabase(Database* database) -{ - ASSERT(m_openDatabaseSet && m_openDatabaseSet->contains(database)); - if (!m_openDatabaseSet) - return; - - m_openDatabaseSet->remove(database); -} - -DatabaseThread* Document::databaseThread() -{ - if (!m_databaseThread && !m_hasOpenDatabases) { - // Create the database thread on first request - but not if at least one database was already opened, - // because in that case we already had a database thread and terminated it and should not create another. - m_databaseThread = DatabaseThread::create(this); - if (!m_databaseThread->start()) - m_databaseThread = 0; - } - - return m_databaseThread.get(); -} - -void Document::stopDatabases() -{ - if (m_openDatabaseSet) { - DatabaseSet::iterator i = m_openDatabaseSet->begin(); - DatabaseSet::iterator end = m_openDatabaseSet->end(); - for (; i != end; ++i) { - (*i)->stop(); - if (m_databaseThread) - m_databaseThread->unscheduleDatabaseTasks(*i); - } - } - - if (m_databaseThread) - m_databaseThread->requestTermination(); -} - -#endif - -void Document::attachRange(Range* range) -{ - ASSERT(!m_ranges.contains(range)); - m_ranges.add(range); -} - -void Document::detachRange(Range* range) -{ - ASSERT(m_ranges.contains(range)); - m_ranges.remove(range); -} - -CanvasRenderingContext2D* Document::getCSSCanvasContext(const String& type, const String& name, int width, int height) -{ - HTMLCanvasElement* result = getCSSCanvasElement(name); - if (!result) - return 0; - result->setSize(IntSize(width, height)); - return result->getContext(type); -} - -HTMLCanvasElement* Document::getCSSCanvasElement(const String& name) -{ - RefPtr<HTMLCanvasElement> result = m_cssCanvasElements.get(name).get(); - if (!result) { - result = new HTMLCanvasElement(this); - m_cssCanvasElements.set(name, result); - } - return result.get(); -} - -void Document::initDNSPrefetchEnabled() -{ - m_haveExplicitlyDisabledDNSPrefetch = false; - m_isDNSPrefetchEnabled = (securityOrigin()->protocol() == "http"); - - // Inherit DNS prefetch opt-out from parent frame - if (Document* parent = parentDocument()) - if (!parent->isDNSPrefetchEnabled()) - m_isDNSPrefetchEnabled = false; -} - -void Document::setDNSPrefetchControl(const String& dnsPrefetchControl) -{ - if (equalIgnoringCase(dnsPrefetchControl, "on") && - !m_haveExplicitlyDisabledDNSPrefetch) { - m_isDNSPrefetchEnabled = true; - return; - } - - m_isDNSPrefetchEnabled = false; - m_haveExplicitlyDisabledDNSPrefetch = true; -} - -} // namespace WebCore diff --git a/webkit/pending/Document.h b/webkit/pending/Document.h deleted file mode 100644 index 90a1fc4..0000000 --- a/webkit/pending/Document.h +++ /dev/null @@ -1,1090 +0,0 @@ -/* - * 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. - * - */ - -#ifndef Document_h -#define Document_h - -#include "Attr.h" -#include "Color.h" -#include "DeprecatedPtrList.h" -#include "DocumentMarker.h" -#include "HTMLCollection.h" -#include "HTMLFormElement.h" -#include "KURL.h" -#include "StringHash.h" -#include "Timer.h" -#include "unicode/uscript.h" -#include <wtf/HashCountedSet.h> -#include <wtf/ListHashSet.h> - -// FIXME: We should move Mac off of the old Frame-based user stylesheet loading -// code and onto the new code in Page. We can't do that until the code in Page -// supports non-file: URLs, however. -#if PLATFORM(MAC) || PLATFORM(QT) -#define FRAME_LOADS_USER_STYLESHEET 1 -#else -#define FRAME_LOADS_USER_STYLESHEET 0 -#endif - -namespace WebCore { - - class AXObjectCache; - class Attr; - class Attribute; - class CDATASection; - class CachedCSSStyleSheet; - class CanvasRenderingContext2D; - class CharacterData; - class CSSStyleDeclaration; - class CSSStyleSelector; - class CSSStyleSheet; - class Comment; - class Database; - class DOMImplementation; - class DOMSelection; - class DOMWindow; - class DatabaseThread; - class DocLoader; - class DocumentFragment; - class DocumentType; - class EditingText; - class Element; - class EntityReference; - class Event; - class EventListener; - class Frame; - class FrameView; - class HTMLCanvasElement; - class HTMLDocument; - class HTMLElement; - class HTMLFormControlElementWithState; - class HTMLFormElement; - class HTMLHeadElement; - class HTMLImageLoader; - class HTMLInputElement; - class HTMLMapElement; - class IntPoint; - class JSNode; - class MouseEventWithHitTestResults; - class NodeFilter; - class NodeIterator; - class Page; - class PlatformMouseEvent; - class ProcessingInstruction; - class Range; - class RegisteredEventListener; - class RenderArena; - class SecurityOrigin; - class Settings; - class StyleSheet; - class StyleSheetList; - class Text; - class TextResourceDecoder; - class Tokenizer; - class TreeWalker; - -#if ENABLE(SVG) - class SVGDocumentExtensions; -#endif - -#if ENABLE(XBL) - class XBLBindingManager; -#endif - -#if ENABLE(XPATH) - class XPathEvaluator; - class XPathExpression; - class XPathNSResolver; - class XPathResult; -#endif - -#if ENABLE(DASHBOARD_SUPPORT) - struct DashboardRegionValue; -#endif - struct HitTestRequest; - - typedef int ExceptionCode; - -class FormElementKey { -public: - FormElementKey(AtomicStringImpl* = 0, AtomicStringImpl* = 0); - ~FormElementKey(); - FormElementKey(const FormElementKey&); - FormElementKey& operator=(const FormElementKey&); - - AtomicStringImpl* name() const { return m_name; } - AtomicStringImpl* type() const { return m_type; } - - // Hash table deleted values, which are only constructed and never copied or destroyed. - FormElementKey(WTF::HashTableDeletedValueType) : m_name(hashTableDeletedValue()) { } - bool isHashTableDeletedValue() const { return m_name == hashTableDeletedValue(); } - -private: - void ref() const; - void deref() const; - - static AtomicStringImpl* hashTableDeletedValue() { return reinterpret_cast<AtomicStringImpl*>(-1); } - - AtomicStringImpl* m_name; - AtomicStringImpl* m_type; -}; - -inline bool operator==(const FormElementKey& a, const FormElementKey& b) -{ - return a.name() == b.name() && a.type() == b.type(); -} - -struct FormElementKeyHash { - static unsigned hash(const FormElementKey&); - static bool equal(const FormElementKey& a, const FormElementKey& b) { return a == b; } - static const bool safeToCompareToEmptyOrDeleted = true; -}; - -struct FormElementKeyHashTraits : WTF::GenericHashTraits<FormElementKey> { - static void constructDeletedValue(FormElementKey& slot) { new (&slot) FormElementKey(WTF::HashTableDeletedValue); } - static bool isDeletedValue(const FormElementKey& value) { return value.isHashTableDeletedValue(); } -}; - -class Document : public ContainerNode { -public: - static PassRefPtr<Document> create(Frame* frame) - { - return new Document(frame, false); - } - static PassRefPtr<Document> createXHTML(Frame* frame) - { - return new Document(frame, true); - } - virtual ~Document(); - - virtual void removedLastRef(); - - // Nodes belonging to this document hold "self-only" references - - // these are enough to keep the document from being destroyed, but - // not enough to keep it from removing its children. This allows a - // node that outlives its document to still have a valid document - // pointer without introducing reference cycles - - void selfOnlyRef() - { - ASSERT(!m_deletionHasBegun); - ++m_selfOnlyRefCount; - } - void selfOnlyDeref() - { - ASSERT(!m_deletionHasBegun); - --m_selfOnlyRefCount; - if (!m_selfOnlyRefCount && !refCount()) { -#ifndef NDEBUG - m_deletionHasBegun = true; -#endif - delete this; - } - } - - // DOM methods & attributes for Document - - DocumentType* doctype() const { return m_docType.get(); } - - DOMImplementation* implementation() const; - virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); - Element* documentElement() const; - virtual PassRefPtr<Element> createElement(const AtomicString& tagName, ExceptionCode&); - PassRefPtr<DocumentFragment> createDocumentFragment (); - PassRefPtr<Text> createTextNode(const String& data); - PassRefPtr<Comment> createComment(const String& data); - PassRefPtr<CDATASection> createCDATASection(const String& data, ExceptionCode&); - PassRefPtr<ProcessingInstruction> createProcessingInstruction(const String& target, const String& data, ExceptionCode&); - PassRefPtr<Attr> createAttribute(const String& name, ExceptionCode& ec) { return createAttributeNS(String(), name, ec, true); } - PassRefPtr<Attr> createAttributeNS(const String& namespaceURI, const String& qualifiedName, ExceptionCode&, bool shouldIgnoreNamespaceChecks = false); - PassRefPtr<EntityReference> createEntityReference(const String& name, ExceptionCode&); - PassRefPtr<Node> importNode(Node* importedNode, bool deep, ExceptionCode&); - virtual PassRefPtr<Element> createElementNS(const String& namespaceURI, const String& qualifiedName, ExceptionCode&); - PassRefPtr<Element> createElement(const QualifiedName&, bool createdByParser, ExceptionCode& ec); - Element* getElementById(const AtomicString&) const; - bool hasElementWithId(AtomicStringImpl* id) const; - bool containsMultipleElementsWithId(const AtomicString& elementId) { return m_duplicateIds.contains(elementId.impl()); } - - Element* elementFromPoint(int x, int y) const; - String readyState() const; - String inputEncoding() const; - String defaultCharset() const; - - String charset() const { return inputEncoding(); } - String characterSet() const { return inputEncoding(); } - - void setCharset(const String&); - UScriptCode dominantScript() const; - - String contentLanguage() const { return m_contentLanguage; } - void setContentLanguage(const String& lang) { m_contentLanguage = lang; } - - String xmlEncoding() const { return m_xmlEncoding; } - String xmlVersion() const { return m_xmlVersion; } - bool xmlStandalone() const { return m_xmlStandalone; } - - void setXMLEncoding(const String& encoding) { m_xmlEncoding = encoding; } // read-only property, only to be set from XMLTokenizer - void setXMLVersion(const String&, ExceptionCode&); - void setXMLStandalone(bool, ExceptionCode&); - - String documentURI() const { return m_documentURI; } - void setDocumentURI(const String&); - - virtual KURL baseURI() const; - - PassRefPtr<Node> adoptNode(PassRefPtr<Node> source, ExceptionCode&); - - PassRefPtr<HTMLCollection> images(); - PassRefPtr<HTMLCollection> embeds(); - PassRefPtr<HTMLCollection> plugins(); // an alias for embeds() required for the JS DOM bindings. - PassRefPtr<HTMLCollection> applets(); - PassRefPtr<HTMLCollection> links(); - PassRefPtr<HTMLCollection> forms(); - PassRefPtr<HTMLCollection> anchors(); - PassRefPtr<HTMLCollection> all(); - PassRefPtr<HTMLCollection> objects(); - PassRefPtr<HTMLCollection> scripts(); - PassRefPtr<HTMLCollection> windowNamedItems(const String& name); - PassRefPtr<HTMLCollection> documentNamedItems(const String& name); - - HTMLCollection::CollectionInfo* collectionInfo(HTMLCollection::Type type) - { - ASSERT(type >= HTMLCollection::FirstUnnamedDocumentCachedType); - unsigned index = type - HTMLCollection::FirstUnnamedDocumentCachedType; - ASSERT(index < HTMLCollection::NumUnnamedDocumentCachedTypes); - return &m_collectionInfo[index]; - } - - HTMLCollection::CollectionInfo* nameCollectionInfo(HTMLCollection::Type, const AtomicString& name); - - // DOM methods overridden from parent classes - - virtual String nodeName() const; - virtual NodeType nodeType() const; - - // Other methods (not part of DOM) - virtual bool isDocumentNode() const { return true; } - virtual bool isHTMLDocument() const { return false; } - virtual bool isImageDocument() const { return false; } -#if ENABLE(SVG) - virtual bool isSVGDocument() const { return false; } -#endif - virtual bool isPluginDocument() const { return false; } - virtual bool isMediaDocument() const { return false; } - - CSSStyleSelector* styleSelector() const { return m_styleSelector; } - - Element* getElementByAccessKey(const String& key) const; - - /** - * Updates the pending sheet count and then calls updateStyleSelector. - */ - void removePendingSheet(); - - /** - * This method returns true if all top-level stylesheets have loaded (including - * any @imports that they may be loading). - */ - bool haveStylesheetsLoaded() const - { - return m_pendingStylesheets <= 0 || m_ignorePendingStylesheets -#if USE(LOW_BANDWIDTH_DISPLAY) - || m_inLowBandwidthDisplay -#endif - ; - } - - /** - * Increments the number of pending sheets. The <link> elements - * invoke this to add themselves to the loading list. - */ - void addPendingSheet() { m_pendingStylesheets++; } - - void addStyleSheetCandidateNode(Node*, bool createdByParser); - void removeStyleSheetCandidateNode(Node*); - - bool gotoAnchorNeededAfterStylesheetsLoad() { return m_gotoAnchorNeededAfterStylesheetsLoad; } - void setGotoAnchorNeededAfterStylesheetsLoad(bool b) { m_gotoAnchorNeededAfterStylesheetsLoad = b; } - - /** - * Called when one or more stylesheets in the document may have been added, removed or changed. - * - * Creates a new style selector and assign it to this document. This is done by iterating through all nodes in - * document (or those before <BODY> in a HTML document), searching for stylesheets. Stylesheets can be contained in - * <LINK>, <STYLE> or <BODY> elements, as well as processing instructions (XML documents only). A list is - * constructed from these which is used to create the a new style selector which collates all of the stylesheets - * found and is used to calculate the derived styles for all rendering objects. - */ - void updateStyleSelector(); - - void recalcStyleSelector(); - - bool usesDescendantRules() const { return m_usesDescendantRules; } - void setUsesDescendantRules(bool b) { m_usesDescendantRules = b; } - bool usesSiblingRules() const { return m_usesSiblingRules; } - void setUsesSiblingRules(bool b) { m_usesSiblingRules = b; } - bool usesFirstLineRules() const { return m_usesFirstLineRules; } - void setUsesFirstLineRules(bool b) { m_usesFirstLineRules = b; } - bool usesFirstLetterRules() const { return m_usesFirstLetterRules; } - void setUsesFirstLetterRules(bool b) { m_usesFirstLetterRules = b; } - - // Machinery for saving and restoring state when you leave and then go back to a page. - void registerFormElementWithState(HTMLFormControlElementWithState* e) { m_formElementsWithState.add(e); } - void unregisterFormElementWithState(HTMLFormControlElementWithState* e) { m_formElementsWithState.remove(e); } - Vector<String> formElementsState() const; - void setStateForNewFormElements(const Vector<String>&); - bool hasStateForNewFormElements() const; - bool takeStateForFormElement(AtomicStringImpl* name, AtomicStringImpl* type, String& state); - - FrameView* view() const; // can be NULL - Frame* frame() const { return m_frame; } // can be NULL - Page* page() const; // can be NULL - Settings* settings() const; // can be NULL - - PassRefPtr<Range> createRange(); - - PassRefPtr<NodeIterator> createNodeIterator(Node* root, unsigned whatToShow, - PassRefPtr<NodeFilter>, bool expandEntityReferences, ExceptionCode&); - - PassRefPtr<TreeWalker> createTreeWalker(Node* root, unsigned whatToShow, - PassRefPtr<NodeFilter>, bool expandEntityReferences, ExceptionCode&); - - // Special support for editing - PassRefPtr<CSSStyleDeclaration> createCSSStyleDeclaration(); - PassRefPtr<EditingText> createEditingTextNode(const String&); - - virtual void recalcStyle( StyleChange = NoChange ); - virtual void updateRendering(); - void updateLayout(); - void updateLayoutIgnorePendingStylesheets(); - static void updateDocumentsRendering(); - DocLoader* docLoader() { return m_docLoader; } - - virtual void attach(); - virtual void detach(); - - void clearFramePointer(); - - RenderArena* renderArena() { return m_renderArena; } - - void clearAXObjectCache(); - AXObjectCache* axObjectCache() const; - - // to get visually ordered hebrew and arabic pages right - void setVisuallyOrdered(); - - void open(Document* ownerDocument = 0); - void implicitOpen(); - void close(); - void implicitClose(); - void cancelParsing(); - - void write(const String& text, Document* ownerDocument = 0); - void writeln(const String& text, Document* ownerDocument = 0); - void finishParsing(); - void clear(); - - bool wellFormed() const { return m_wellFormed; } - - const KURL& url() const { return m_url; } - void setURL(const KURL&); - - const KURL& baseURL() const { return m_baseURL; } - // Setting the BaseElementURL will change the baseURL. - void setBaseElementURL(const KURL&); - - const String& baseTarget() const { return m_baseTarget; } - // Setting the BaseElementTarget will change the baseTarget. - void setBaseElementTarget(const String& baseTarget) { m_baseTarget = baseTarget; } - - KURL completeURL(const String&) const; - - unsigned visitedLinkHash(const AtomicString& attributeURL) const; - - // from cachedObjectClient - virtual void setCSSStyleSheet(const String& url, const String& charset, const CachedCSSStyleSheet*); - -#if FRAME_LOADS_USER_STYLESHEET - void setUserStyleSheet(const String& sheet); -#endif - - String userStyleSheet() const; - - CSSStyleSheet* elementSheet(); - CSSStyleSheet* mappedElementSheet(); - virtual Tokenizer* createTokenizer(); - Tokenizer* tokenizer() { return m_tokenizer; } - - bool printing() const { return m_printing; } - void setPrinting(bool p) { m_printing = p; } - - enum ParseMode { Compat, AlmostStrict, Strict }; - - // Used by Chromium to know if it can just SIGKILL a renderer when navigating - bool hasUnloadEventListener(); - -private: - virtual void determineParseMode() {} - -public: - void setParseMode(ParseMode m) { m_parseMode = m; } - ParseMode parseMode() const { return m_parseMode; } - - bool inCompatMode() const { return m_parseMode == Compat; } - bool inAlmostStrictMode() const { return m_parseMode == AlmostStrict; } - bool inStrictMode() const { return m_parseMode == Strict; } - - void setParsing(bool); - bool parsing() const { return m_bParsing; } - int minimumLayoutDelay(); - bool shouldScheduleLayout(); - int elapsedTime() const; - - void setTextColor(const Color& color) { m_textColor = color; } - Color textColor() const { return m_textColor; } - - const Color& linkColor() const { return m_linkColor; } - const Color& visitedLinkColor() const { return m_visitedLinkColor; } - const Color& activeLinkColor() const { return m_activeLinkColor; } - void setLinkColor(const Color& c) { m_linkColor = c; } - void setVisitedLinkColor(const Color& c) { m_visitedLinkColor = c; } - void setActiveLinkColor(const Color& c) { m_activeLinkColor = c; } - void resetLinkColor(); - void resetVisitedLinkColor(); - void resetActiveLinkColor(); - - MouseEventWithHitTestResults prepareMouseEvent(const HitTestRequest&, const IntPoint&, const PlatformMouseEvent&); - - virtual bool childTypeAllowed(NodeType); - virtual PassRefPtr<Node> cloneNode(bool deep); - - virtual bool canReplaceChild(Node* newChild, Node* oldChild); - - StyleSheetList* styleSheets(); - - /* Newly proposed CSS3 mechanism for selecting alternate - stylesheets using the DOM. May be subject to change as - spec matures. - dwh - */ - String preferredStylesheetSet() const; - String selectedStylesheetSet() const; - void setSelectedStylesheetSet(const String&); - - bool setFocusedNode(PassRefPtr<Node>); - Node* focusedNode() const { return m_focusedNode.get(); } - - // The m_ignoreAutofocus flag specifies whether or not the document has been changed by the user enough - // for WebCore to ignore the autofocus attribute on any form controls - bool ignoreAutofocus() const { return m_ignoreAutofocus; }; - void setIgnoreAutofocus(bool shouldIgnore = true) { m_ignoreAutofocus = shouldIgnore; }; - - void setHoverNode(PassRefPtr<Node>); - Node* hoverNode() const { return m_hoverNode.get(); } - - void setActiveNode(PassRefPtr<Node>); - Node* activeNode() const { return m_activeNode.get(); } - - void focusedNodeRemoved(); - void removeFocusedNodeOfSubtree(Node*, bool amongChildrenOnly = false); - void hoveredNodeDetached(Node*); - void activeChainNodeDetached(Node*); - - // Updates for :target (CSS3 selector). - void setCSSTarget(Node*); - Node* getCSSTarget() const; - - void setDocumentChanged(bool); - - void attachNodeIterator(NodeIterator*); - void detachNodeIterator(NodeIterator*); - - void attachRange(Range*); - void detachRange(Range*); - - void nodeChildrenChanged(ContainerNode*); - void nodeWillBeRemoved(Node*); - - void textInserted(Node*, unsigned offset, unsigned length); - void textRemoved(Node*, unsigned offset, unsigned length); - void textNodesMerged(Text* oldNode, unsigned offset); - void textNodeSplit(Text* oldNode); - - DOMWindow* defaultView() const { return domWindow(); } - DOMWindow* domWindow() const; - - PassRefPtr<Event> createEvent(const String& eventType, ExceptionCode&); - - // keep track of what types of event listeners are registered, so we don't - // dispatch events unnecessarily - enum ListenerType { - DOMSUBTREEMODIFIED_LISTENER = 0x01, - DOMNODEINSERTED_LISTENER = 0x02, - DOMNODEREMOVED_LISTENER = 0x04, - DOMNODEREMOVEDFROMDOCUMENT_LISTENER = 0x08, - DOMNODEINSERTEDINTODOCUMENT_LISTENER = 0x10, - DOMATTRMODIFIED_LISTENER = 0x20, - DOMCHARACTERDATAMODIFIED_LISTENER = 0x40, - OVERFLOWCHANGED_LISTENER = 0x80, - ANIMATIONEND_LISTENER = 0x100, - ANIMATIONSTART_LISTENER = 0x200, - ANIMATIONITERATION_LISTENER = 0x400, - TRANSITIONEND_LISTENER = 0x800 - }; - - bool hasListenerType(ListenerType listenerType) const { return (m_listenerTypes & listenerType); } - void addListenerType(ListenerType listenerType) { m_listenerTypes = m_listenerTypes | listenerType; } - - CSSStyleDeclaration* getOverrideStyle(Element*, const String& pseudoElt); - - void handleWindowEvent(Event*, bool useCapture); - void setHTMLWindowEventListener(const AtomicString &eventType, PassRefPtr<EventListener>); - EventListener* getHTMLWindowEventListener(const AtomicString &eventType); - void removeHTMLWindowEventListener(const AtomicString &eventType); - - void setHTMLWindowEventListener(const AtomicString& eventType, Attribute*); - - void addWindowEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture); - void removeWindowEventListener(const AtomicString& eventType, EventListener*, bool useCapture); - bool hasWindowEventListener(const AtomicString& eventType); - - void addPendingFrameUnloadEventCount(); - void removePendingFrameUnloadEventCount(); - void addPendingFrameBeforeUnloadEventCount(); - void removePendingFrameBeforeUnloadEventCount(); - - PassRefPtr<EventListener> createHTMLEventListener(const String& functionName, const String& code, Node*); - - /** - * Searches through the document, starting from fromNode, for the next selectable element that comes after fromNode. - * The order followed is as specified in section 17.11.1 of the HTML4 spec, which is elements with tab indexes - * first (from lowest to highest), and then elements without tab indexes (in document order). - * - * @param fromNode The node from which to start searching. The node after this will be focused. May be null. - * - * @return The focus node that comes after fromNode - * - * See http://www.w3.org/TR/html4/interact/forms.html#h-17.11.1 - */ - Node* nextFocusableNode(Node* start, KeyboardEvent*); - - /** - * Searches through the document, starting from fromNode, for the previous selectable element (that comes _before_) - * fromNode. The order followed is as specified in section 17.11.1 of the HTML4 spec, which is elements with tab - * indexes first (from lowest to highest), and then elements without tab indexes (in document order). - * - * @param fromNode The node from which to start searching. The node before this will be focused. May be null. - * - * @return The focus node that comes before fromNode - * - * See http://www.w3.org/TR/html4/interact/forms.html#h-17.11.1 - */ - Node* previousFocusableNode(Node* start, KeyboardEvent*); - - int nodeAbsIndex(Node*); - Node* nodeWithAbsIndex(int absIndex); - - /** - * Handles a HTTP header equivalent set by a meta tag using <meta http-equiv="..." content="...">. This is called - * when a meta tag is encountered during document parsing, and also when a script dynamically changes or adds a meta - * tag. This enables scripts to use meta tags to perform refreshes and set expiry dates in addition to them being - * specified in a HTML file. - * - * @param equiv The http header name (value of the meta tag's "equiv" attribute) - * @param content The header value (value of the meta tag's "content" attribute) - */ - void processHttpEquiv(const String& equiv, const String& content); - - void dispatchImageLoadEventSoon(HTMLImageLoader*); - void dispatchImageLoadEventsNow(); - void removeImage(HTMLImageLoader*); - - // Returns the owning element in the parent document. - // Returns 0 if this is the top level document. - Element* ownerElement() const; - - String title() const { return m_title; } - void setTitle(const String&, Element* titleElement = 0); - void removeTitle(Element* titleElement); - - String cookie() const; - void setCookie(const String&); - - String referrer() const; - - String domain() const; - void setDomain(const String& newDomain); - - String lastModified() const; - - const KURL& cookieURL() const { return m_cookieURL; } - - const KURL& policyBaseURL() const { return m_policyBaseURL; } - void setPolicyBaseURL(const KURL& url) { m_policyBaseURL = url; } - - // The following implements the rule from HTML 4 for what valid names are. - // To get this right for all the XML cases, we probably have to improve this or move it - // and make it sensitive to the type of document. - static bool isValidName(const String&); - - // The following breaks a qualified name into a prefix and a local name. - // It also does a validity check, and returns false if the qualified name - // is invalid. It also sets ExceptionCode when name is invalid. - static bool parseQualifiedName(const String& qualifiedName, String& prefix, String& localName, ExceptionCode&); - - // Checks to make sure prefix and namespace do not conflict (per DOM Core 3) - static bool hasPrefixNamespaceMismatch(const QualifiedName&); - - void addElementById(const AtomicString& elementId, Element *element); - void removeElementById(const AtomicString& elementId, Element *element); - - void addImageMap(HTMLMapElement*); - void removeImageMap(HTMLMapElement*); - HTMLMapElement* getImageMap(const String& url) const; - - HTMLElement* body(); - void setBody(PassRefPtr<HTMLElement>, ExceptionCode&); - - HTMLHeadElement* head(); - - bool execCommand(const String& command, bool userInterface = false, const String& value = String()); - bool queryCommandEnabled(const String& command); - bool queryCommandIndeterm(const String& command); - bool queryCommandState(const String& command); - bool queryCommandSupported(const String& command); - String queryCommandValue(const String& command); - - void addMarker(Range*, DocumentMarker::MarkerType, String description = String()); - void addMarker(Node*, DocumentMarker); - void copyMarkers(Node *srcNode, unsigned startOffset, int length, Node *dstNode, int delta, DocumentMarker::MarkerType = DocumentMarker::AllMarkers); - void removeMarkers(Range*, DocumentMarker::MarkerType = DocumentMarker::AllMarkers); - void removeMarkers(Node*, unsigned startOffset, int length, DocumentMarker::MarkerType = DocumentMarker::AllMarkers); - void removeMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers); - void removeMarkers(Node*); - void repaintMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers); - void setRenderedRectForMarker(Node*, DocumentMarker, const IntRect&); - void invalidateRenderedRectsForMarkersInRect(const IntRect&); - void shiftMarkers(Node*, unsigned startOffset, int delta, DocumentMarker::MarkerType = DocumentMarker::AllMarkers); - - DocumentMarker* markerContainingPoint(const IntPoint&, DocumentMarker::MarkerType = DocumentMarker::AllMarkers); - Vector<DocumentMarker> markersForNode(Node*); - Vector<IntRect> renderedRectsForMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers); - - // designMode support - enum InheritedBool { off = false, on = true, inherit }; - void setDesignMode(InheritedBool value); - InheritedBool getDesignMode() const; - bool inDesignMode() const; - - Document* parentDocument() const; - Document* topDocument() const; - - int docID() const { return m_docID; } - -#if ENABLE(XSLT) - void applyXSLTransform(ProcessingInstruction* pi); - void setTransformSource(void* doc); - const void* transformSource() { return m_transformSource; } - PassRefPtr<Document> transformSourceDocument() { return m_transformSourceDocument; } - void setTransformSourceDocument(Document* doc) { m_transformSourceDocument = doc; } -#endif - -#if ENABLE(XBL) - // XBL methods - XBLBindingManager* bindingManager() const { return m_bindingManager; } -#endif - - void incDOMTreeVersion() { ++m_domtree_version; } - unsigned domTreeVersion() const { return m_domtree_version; } - - void setDocType(PassRefPtr<DocumentType>); - - void finishedParsing(); - -#if ENABLE(XPATH) - // XPathEvaluator methods - PassRefPtr<XPathExpression> createExpression(const String& expression, - XPathNSResolver* resolver, - ExceptionCode& ec); - PassRefPtr<XPathNSResolver> createNSResolver(Node *nodeResolver); - PassRefPtr<XPathResult> evaluate(const String& expression, - Node* contextNode, - XPathNSResolver* resolver, - unsigned short type, - XPathResult* result, - ExceptionCode& ec); -#endif // ENABLE(XPATH) - - enum PendingSheetLayout { NoLayoutWithPendingSheets, DidLayoutWithPendingSheets, IgnoreLayoutWithPendingSheets }; - - bool didLayoutWithPendingStylesheets() const { return m_pendingSheetLayout == DidLayoutWithPendingSheets; } - - void setHasNodesWithPlaceholderStyle() { m_hasNodesWithPlaceholderStyle = true; } - - const String& iconURL() const { return m_iconURL; } - void setIconURL(const String& iconURL, const String& type); - - void setUseSecureKeyboardEntryWhenActive(bool); - bool useSecureKeyboardEntryWhenActive() const; - -#if USE(LOW_BANDWIDTH_DISPLAY) - void setDocLoader(DocLoader* loader) { m_docLoader = loader; } - bool inLowBandwidthDisplay() const { return m_inLowBandwidthDisplay; } - void setLowBandwidthDisplay(bool lowBandWidth) { m_inLowBandwidthDisplay = lowBandWidth; } -#endif - - void addNodeListCache() { ++m_numNodeListCaches; } - void removeNodeListCache() { ASSERT(m_numNodeListCaches > 0); --m_numNodeListCaches; } - bool hasNodeListCaches() const { return m_numNodeListCaches; } - - void updateFocusAppearanceSoon(); - void cancelFocusAppearanceUpdate(); - - // FF method for accessing the selection added for compatability. - DOMSelection* getSelection() const; - - // Extension for manipulating canvas drawing contexts for use in CSS - CanvasRenderingContext2D* getCSSCanvasContext(const String& type, const String& name, int width, int height); - HTMLCanvasElement* getCSSCanvasElement(const String& name); - - bool isDNSPrefetchEnabled() const { return m_isDNSPrefetchEnabled; } - void initDNSPrefetchEnabled(); - void setDNSPrefetchControl(const WebCore::String&); - -protected: - Document(Frame*, bool isXHTML); - -private: - CSSStyleSelector* m_styleSelector; - bool m_didCalculateStyleSelector; - - Frame* m_frame; - DocLoader* m_docLoader; - Tokenizer* m_tokenizer; - bool m_wellFormed; - - // Document URLs. - KURL m_url; // Document.URL: The URL from which this document was retrieved. - KURL m_baseURL; // Node.baseURI: The URL to use when resolving relative URLs. - KURL m_baseElementURL; // The URL set by the <base> element. - KURL m_cookieURL; // The URL to use for cookie access. - KURL m_policyBaseURL; // The policy URL for third-party cookie blocking. - - // Document.documentURI: - // Although URL-like, Document.documentURI can actually be set to any - // string by content. Document.documentURI affects m_baseURL unless the - // document contains a <base> element, in which case the <base> element - // takes precedence. - String m_documentURI; - - String m_baseTarget; - - RefPtr<DocumentType> m_docType; - mutable RefPtr<DOMImplementation> m_implementation; - - RefPtr<StyleSheet> m_sheet; -#if FRAME_LOADS_USER_STYLESHEET - String m_usersheet; -#endif - - // Track the number of currently loading top-level stylesheets. Sheets - // loaded using the @import directive are not included in this count. - // We use this count of pending sheets to detect when we can begin attaching - // elements. - int m_pendingStylesheets; - - // But sometimes you need to ignore pending stylesheet count to - // force an immediate layout when requested by JS. - bool m_ignorePendingStylesheets; - - // If we do ignore the pending stylesheet count, then we need to add a boolean - // to track that this happened so that we can do a full repaint when the stylesheets - // do eventually load. - PendingSheetLayout m_pendingSheetLayout; - - bool m_hasNodesWithPlaceholderStyle; - - RefPtr<CSSStyleSheet> m_elemSheet; - RefPtr<CSSStyleSheet> m_mappedElementSheet; - - bool m_printing; - - bool m_ignoreAutofocus; - - ParseMode m_parseMode; - - Color m_textColor; - - RefPtr<Node> m_focusedNode; - RefPtr<Node> m_hoverNode; - RefPtr<Node> m_activeNode; - mutable RefPtr<Element> m_documentElement; - - unsigned m_domtree_version; - - HashSet<NodeIterator*> m_nodeIterators; - HashSet<Range*> m_ranges; - - unsigned short m_listenerTypes; - - RefPtr<StyleSheetList> m_styleSheets; // All of the stylesheets that are currently in effect for our media type and stylesheet set. - ListHashSet<Node*> m_styleSheetCandidateNodes; // All of the nodes that could potentially provide stylesheets to the document (<link>, <style>, <?xml-stylesheet>) - - RegisteredEventListenerList m_windowEventListeners; - - typedef HashMap<FormElementKey, Vector<String>, FormElementKeyHash, FormElementKeyHashTraits> FormElementStateMap; - ListHashSet<HTMLFormControlElementWithState*> m_formElementsWithState; - FormElementStateMap m_stateForNewFormElements; - - Color m_linkColor; - Color m_visitedLinkColor; - Color m_activeLinkColor; - - String m_preferredStylesheetSet; - String m_selectedStylesheetSet; - - bool m_loadingSheet; - bool visuallyOrdered; - bool m_bParsing; - bool m_docChanged; - bool m_inStyleRecalc; - bool m_closeAfterStyleRecalc; - bool m_usesDescendantRules; - bool m_usesSiblingRules; - bool m_usesFirstLineRules; - bool m_usesFirstLetterRules; - bool m_gotoAnchorNeededAfterStylesheetsLoad; - - bool m_isDNSPrefetchEnabled; - bool m_haveExplicitlyDisabledDNSPrefetch; - - String m_title; - bool m_titleSetExplicitly; - RefPtr<Element> m_titleElement; - - RenderArena* m_renderArena; - - typedef std::pair<Vector<DocumentMarker>, Vector<IntRect> > MarkerMapVectorPair; - typedef HashMap<RefPtr<Node>, MarkerMapVectorPair*> MarkerMap; - MarkerMap m_markers; - - mutable AXObjectCache* m_axObjectCache; - - DeprecatedPtrList<HTMLImageLoader> m_imageLoadEventDispatchSoonList; - DeprecatedPtrList<HTMLImageLoader> m_imageLoadEventDispatchingList; - Timer<Document> m_imageLoadEventTimer; - - Timer<Document> m_updateFocusAppearanceTimer; - - Node* m_cssTarget; - - bool m_processingLoadEvent; - double m_startTime; - bool m_overMinimumLayoutThreshold; - -#if ENABLE(XSLT) - void* m_transformSource; - RefPtr<Document> m_transformSourceDocument; -#endif - -#if ENABLE(XBL) - XBLBindingManager* m_bindingManager; // The access point through which documents and elements communicate with XBL. -#endif - - typedef HashMap<AtomicStringImpl*, HTMLMapElement*> ImageMapsByName; - ImageMapsByName m_imageMapsByName; - - HashSet<Node*> m_disconnectedNodesWithEventListeners; - - int m_docID; // A unique document identifier used for things like document-specific mapped attributes. - - String m_xmlEncoding; - String m_xmlVersion; - bool m_xmlStandalone; - - String m_contentLanguage; - - // UScriptCode can be derived from non-Unicode charsets and help us select a fallback - // font. Because it's derived from charset, it's a document-wide constant. - // For instance, it'll be Latin, SimplifiedHan, TraditionalHan, Hiragana, - // Hangul, Arabic and Hebrew for documents in ISO-8859-1, GBK, Big5, Shift_JIS, - // EUC-KR, Windows-1256 and Windows-1255, respectively. In case of Japanese encodings, - // either Hiragana or Katakana should work but Han does not because it does not - // uniquely identify Japanese and as a result does not help the font selection. - // Obviously, this does not work well for Unicode-encoded documents. In the meantime, - // we can resort to the 'dominant' script of the current UI language. - // In the future, we should refer to the value of xml:lang and lang to infer - // this value for invididual text nodes. CSSStyleSelector might be a good place for that. - // Moreover, the value of m_contentLanguage should be utilized as well. - mutable UScriptCode m_dominantScript; - -public: - bool inPageCache(); - void setInPageCache(bool flag); - - // Elements can register themselves for the "willSaveToCache()" and - // "didRestoreFromCache()" callbacks - void registerForCacheCallbacks(Element*); - void unregisterForCacheCallbacks(Element*); - void willSaveToCache(); - void didRestoreFromCache(); - - void setShouldCreateRenderers(bool); - bool shouldCreateRenderers(); - - void setDecoder(PassRefPtr<TextResourceDecoder>); - TextResourceDecoder* decoder() const { return m_decoder.get(); } - - UChar backslashAsCurrencySymbol() const; - -#if ENABLE(DASHBOARD_SUPPORT) - void setDashboardRegionsDirty(bool f) { m_dashboardRegionsDirty = f; } - bool dashboardRegionsDirty() const { return m_dashboardRegionsDirty; } - bool hasDashboardRegions () const { return m_hasDashboardRegions; } - void setHasDashboardRegions (bool f) { m_hasDashboardRegions = f; } - const Vector<DashboardRegionValue>& dashboardRegions() const; - void setDashboardRegions(const Vector<DashboardRegionValue>&); -#endif - - void removeAllEventListenersFromAllNodes(); - - void registerDisconnectedNodeWithEventListeners(Node*); - void unregisterDisconnectedNodeWithEventListeners(Node*); - - HTMLFormElement::CheckedRadioButtons& checkedRadioButtons() { return m_checkedRadioButtons; } - -#if ENABLE(SVG) - const SVGDocumentExtensions* svgExtensions(); - SVGDocumentExtensions* accessSVGExtensions(); -#endif - - void initSecurityContext(); - SecurityOrigin* securityOrigin() const { return m_securityOrigin.get(); } - - // Explicitly override the security origin for this document. - // Note: It is dangerous to change the security origin of a document - // that already contains content. - void setSecurityOrigin(SecurityOrigin*); - - bool processingLoadEvent() const { return m_processingLoadEvent; } - -#if ENABLE(DATABASE) - void addOpenDatabase(Database*); - void removeOpenDatabase(Database*); - DatabaseThread* databaseThread(); // Creates the thread as needed, but not if it has been already terminated. - void setHasOpenDatabases() { m_hasOpenDatabases = true; } - bool hasOpenDatabases() { return m_hasOpenDatabases; } - void stopDatabases(); -#endif -protected: - void clearXMLVersion() { m_xmlVersion = String(); } - -private: - void updateTitle(); - void removeAllDisconnectedNodeEventListeners(); - void imageLoadEventTimerFired(Timer<Document>*); - void updateFocusAppearanceTimerFired(Timer<Document>*); - void updateBaseURL(); - - RefPtr<SecurityOrigin> m_securityOrigin; - - RenderObject* m_savedRenderer; - int m_secureForms; - - RefPtr<TextResourceDecoder> m_decoder; - - // We maintain the invariant that m_duplicateIds is the count of all elements with a given ID - // excluding the one referenced in m_elementsById, if any. This means it one less than the total count - // when the first node with a given ID is cached, otherwise the same as the total count. - mutable HashMap<AtomicStringImpl*, Element*> m_elementsById; - mutable HashCountedSet<AtomicStringImpl*> m_duplicateIds; - - mutable HashMap<StringImpl*, Element*, CaseFoldingHash> m_elementsByAccessKey; - - InheritedBool m_designMode; - - int m_selfOnlyRefCount; - - HTMLFormElement::CheckedRadioButtons m_checkedRadioButtons; - - typedef HashMap<AtomicStringImpl*, HTMLCollection::CollectionInfo*> NamedCollectionMap; - HTMLCollection::CollectionInfo m_collectionInfo[HTMLCollection::NumUnnamedDocumentCachedTypes]; - NamedCollectionMap m_nameCollectionInfo[HTMLCollection::NumNamedDocumentCachedTypes]; - -#if ENABLE(XPATH) - RefPtr<XPathEvaluator> m_xpathEvaluator; -#endif - -#if ENABLE(SVG) - SVGDocumentExtensions* m_svgExtensions; -#endif - -#if ENABLE(DASHBOARD_SUPPORT) - Vector<DashboardRegionValue> m_dashboardRegions; - bool m_hasDashboardRegions; - bool m_dashboardRegionsDirty; -#endif - - HashMap<String, RefPtr<HTMLCanvasElement> > m_cssCanvasElements; - - mutable bool m_accessKeyMapValid; - bool m_createRenderers; - bool m_inPageCache; - String m_iconURL; - - HashSet<Element*> m_pageCacheCallbackElements; - - bool m_useSecureKeyboardEntryWhenActive; - - bool m_isXHTML; - - unsigned m_numNodeListCaches; - -public: - typedef HashMap<WebCore::Node*, JSNode*> JSWrapperCache; - JSWrapperCache& wrapperCache() { return m_wrapperCache; } -private: - JSWrapperCache m_wrapperCache; - -#if ENABLE(DATABASE) - RefPtr<DatabaseThread> m_databaseThread; - bool m_hasOpenDatabases; // This never changes back to false, even as the database thread is closed. - typedef HashSet<Database*> DatabaseSet; - OwnPtr<DatabaseSet> m_openDatabaseSet; -#endif - -#if USE(LOW_BANDWIDTH_DISPLAY) - bool m_inLowBandwidthDisplay; -#endif - -}; - -inline bool Document::hasElementWithId(AtomicStringImpl* id) const -{ - ASSERT(id); - return m_elementsById.contains(id) || m_duplicateIds.contains(id); -} - -} // namespace WebCore - -#endif // Document_h diff --git a/webkit/pending/DragController.cpp b/webkit/pending/DragController.cpp deleted file mode 100644 index f7c18c1..0000000 --- a/webkit/pending/DragController.cpp +++ /dev/null @@ -1,774 +0,0 @@ -/* - * Copyright (C) 2007 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "DragController.h" - -#include "CSSStyleDeclaration.h" -#include "Clipboard.h" -#include "ClipboardAccessPolicy.h" -#include "DocLoader.h" -#include "Document.h" -#include "DocumentFragment.h" -#include "DragActions.h" -#include "DragClient.h" -#include "DragData.h" -#include "Editor.h" -#include "EditorClient.h" -#include "Element.h" -#include "EventHandler.h" -#include "FloatRect.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "FrameView.h" -#include "HTMLAnchorElement.h" -#include "HTMLInputElement.h" -#include "HTMLNames.h" -#include "HitTestResult.h" -#include "Image.h" -#include "MoveSelectionCommand.h" -#include "Node.h" -#include "Page.h" -#include "RenderFileUploadControl.h" -#include "RenderImage.h" -#include "ReplaceSelectionCommand.h" -#include "ResourceRequest.h" -#include "SelectionController.h" -#include "Settings.h" -#include "SystemTime.h" -#include "Text.h" -#include "markup.h" -#include <wtf/RefPtr.h> - -namespace WebCore { - -static PlatformMouseEvent createMouseEvent(DragData* dragData) -{ - // FIXME: We should fake modifier keys here. - return PlatformMouseEvent(dragData->clientPosition(), dragData->globalPosition(), - LeftButton, MouseEventMoved, 0, false, false, false, false, currentTime()); - -} - -DragController::DragController(Page* page, DragClient* client) - : m_page(page) - , m_client(client) - , m_document(0) - , m_dragInitiator(0) - , m_dragDestinationAction(DragDestinationActionNone) - , m_dragSourceAction(DragSourceActionNone) - , m_didInitiateDrag(false) - , m_isHandlingDrag(false) - , m_dragOperation(DragOperationNone) -{ -} - -DragController::~DragController() -{ - m_client->dragControllerDestroyed(); -} - -static PassRefPtr<DocumentFragment> documentFragmentFromDragData(DragData* dragData, RefPtr<Range> context, - bool allowPlainText, bool& chosePlainText) -{ - ASSERT(dragData); - chosePlainText = false; - - Document* document = context->ownerDocument(); - ASSERT(document); - if (document && dragData->containsCompatibleContent()) { - if (PassRefPtr<DocumentFragment> fragment = dragData->asFragment(document)) - return fragment; - - if (dragData->containsURL()) { - String title; - String url = dragData->asURL(&title); - if (!url.isEmpty()) { - ExceptionCode ec; - RefPtr<HTMLAnchorElement> anchor = static_cast<HTMLAnchorElement*>(document->createElement("a", ec).get()); - anchor->setHref(url); - RefPtr<Node> anchorText = document->createTextNode(title); - anchor->appendChild(anchorText, ec); - RefPtr<DocumentFragment> fragment = document->createDocumentFragment(); - fragment->appendChild(anchor, ec); - return fragment.get(); - } - } - } - if (allowPlainText && dragData->containsPlainText()) { - chosePlainText = true; - return createFragmentFromText(context.get(), dragData->asPlainText()).get(); - } - - return 0; -} - -bool DragController::dragIsMove(SelectionController* selection, DragData* dragData) -{ - return m_document == m_dragInitiator - && selection->isContentEditable() - && !isCopyKeyDown(); -} - -void DragController::cancelDrag() -{ - m_page->dragCaretController()->clear(); -} - -void DragController::dragEnded() -{ - m_dragInitiator = 0; - m_didInitiateDrag = false; - m_page->dragCaretController()->clear(); -} - -DragOperation DragController::dragEntered(DragData* dragData) -{ - return dragEnteredOrUpdated(dragData); -} - -void DragController::dragExited(DragData* dragData) -{ - ASSERT(dragData); - Frame* mainFrame = m_page->mainFrame(); - - if (RefPtr<FrameView> v = mainFrame->view()) { - ClipboardAccessPolicy policy = mainFrame->loader()->baseURL().isLocalFile() ? ClipboardReadable : ClipboardTypesReadable; - RefPtr<Clipboard> clipboard = dragData->createClipboard(policy); - clipboard->setSourceOperation(dragData->draggingSourceOperationMask()); - mainFrame->eventHandler()->cancelDragAndDrop(createMouseEvent(dragData), clipboard.get()); - clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security - } - - cancelDrag(); - m_document = 0; -} - -DragOperation DragController::dragUpdated(DragData* dragData) -{ - return dragEnteredOrUpdated(dragData); -} - -bool DragController::performDrag(DragData* dragData) -{ - ASSERT(dragData); - m_document = m_page->mainFrame()->documentAtPoint(dragData->clientPosition()); - if (m_isHandlingDrag) { - ASSERT(m_dragDestinationAction & DragDestinationActionDHTML); - m_client->willPerformDragDestinationAction(DragDestinationActionDHTML, dragData); - RefPtr<Frame> mainFrame = m_page->mainFrame(); - if (mainFrame->view()) { - // Sending an event can result in the destruction of the view and part. - RefPtr<Clipboard> clipboard = dragData->createClipboard(ClipboardReadable); - clipboard->setSourceOperation(dragData->draggingSourceOperationMask()); - mainFrame->eventHandler()->performDragAndDrop(createMouseEvent(dragData), clipboard.get()); - clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security - } - m_document = 0; - return true; - } - - if ((m_dragDestinationAction & DragDestinationActionEdit) && concludeDrag(dragData, m_dragDestinationAction)) { - m_document = 0; - return true; - } - - m_document = 0; - - if (operationForLoad(dragData) == DragOperationNone) - return false; - - m_client->willPerformDragDestinationAction(DragDestinationActionLoad, dragData); - m_page->mainFrame()->loader()->load(ResourceRequest(dragData->asURL())); - return true; -} - -DragOperation DragController::dragEnteredOrUpdated(DragData* dragData) -{ - ASSERT(dragData); - IntPoint windowPoint = dragData->clientPosition(); - - Document* newDraggingDoc = 0; - if (Frame* frame = m_page->mainFrame()) - newDraggingDoc = frame->documentAtPoint(windowPoint); - if (m_document != newDraggingDoc) { - if (m_document) - cancelDrag(); - m_document = newDraggingDoc; - } - - m_dragDestinationAction = m_client->actionMaskForDrag(dragData); - - DragOperation operation = DragOperationNone; - - if (m_dragDestinationAction == DragDestinationActionNone) - cancelDrag(); - else { - operation = tryDocumentDrag(dragData, m_dragDestinationAction); - if (operation == DragOperationNone && (m_dragDestinationAction & DragDestinationActionLoad)) - return operationForLoad(dragData); - } - - return operation; -} - -static HTMLInputElement* asFileInput(Node* node) -{ - ASSERT(node); - - // The button for a FILE input is a sub element with no set input type - // In order to get around this problem we assume any non-FILE input element - // is this internal button, and try querying the shadow parent node. - if (node->hasTagName(HTMLNames::inputTag) && node->isShadowNode() && static_cast<HTMLInputElement*>(node)->inputType() != HTMLInputElement::FILE) - node = node->shadowParentNode(); - - if (!node || !node->hasTagName(HTMLNames::inputTag)) - return 0; - - HTMLInputElement* inputElem = static_cast<HTMLInputElement*>(node); - if (inputElem->inputType() == HTMLInputElement::FILE) - return inputElem; - - return 0; -} - -DragOperation DragController::tryDocumentDrag(DragData* dragData, DragDestinationAction actionMask) -{ - ASSERT(dragData); - - if (!m_document) - return DragOperationNone; - - DragOperation operation = DragOperationNone; - if (actionMask & DragDestinationActionDHTML) - operation = tryDHTMLDrag(dragData); - m_isHandlingDrag = operation != DragOperationNone; - - RefPtr<FrameView> frameView = m_document->view(); - if (!frameView) - return operation; - - if ((actionMask & DragDestinationActionEdit) && !m_isHandlingDrag && canProcessDrag(dragData)) { - if (dragData->containsColor()) - return DragOperationGeneric; - - IntPoint dragPos = dragData->clientPosition(); - IntPoint point = frameView->windowToContents(dragPos); - Element* element = m_document->elementFromPoint(point.x(), point.y()); - ASSERT(element); - Frame* innerFrame = element->document()->frame(); - ASSERT(innerFrame); - if (!asFileInput(element)) { - Selection dragCaret; - if (Frame* frame = m_document->frame()) - dragCaret = frame->visiblePositionForPoint(point); - m_page->dragCaretController()->setSelection(dragCaret); - } - - return dragIsMove(innerFrame->selection(), dragData) ? DragOperationMove : DragOperationCopy; - } - - m_page->dragCaretController()->clear(); - return operation; -} - -DragSourceAction DragController::delegateDragSourceAction(const IntPoint& windowPoint) -{ - m_dragSourceAction = m_client->dragSourceActionMaskForPoint(windowPoint); - return m_dragSourceAction; -} - -DragOperation DragController::operationForLoad(DragData* dragData) -{ - ASSERT(dragData); - Document* doc = 0; - doc = m_page->mainFrame()->documentAtPoint(dragData->clientPosition()); - if (doc && (m_didInitiateDrag || doc->isPluginDocument() || (doc->frame() && doc->frame()->editor()->clientIsEditable()))) - return DragOperationNone; - return dragOperation(dragData); -} - -static bool setSelectionToDragCaret(Frame* frame, Selection& dragCaret, RefPtr<Range>& range, const IntPoint& point) -{ - frame->selection()->setSelection(dragCaret); - if (frame->selection()->isNone()) { - dragCaret = frame->visiblePositionForPoint(point); - frame->selection()->setSelection(dragCaret); - range = dragCaret.toRange(); - } - return !frame->selection()->isNone() && frame->selection()->isContentEditable(); -} - -bool DragController::concludeDrag(DragData* dragData, DragDestinationAction actionMask) -{ - ASSERT(dragData); - ASSERT(!m_isHandlingDrag); - ASSERT(actionMask & DragDestinationActionEdit); - - if (!m_document) - return false; - - IntPoint point = m_document->view()->windowToContents(dragData->clientPosition()); - Element* element = m_document->elementFromPoint(point.x(), point.y()); - ASSERT(element); - Frame* innerFrame = element->ownerDocument()->frame(); - ASSERT(innerFrame); - - if (dragData->containsColor()) { - Color color = dragData->asColor(); - if (!color.isValid()) - return false; - if (!innerFrame) - return false; - RefPtr<Range> innerRange = innerFrame->selection()->toRange(); - RefPtr<CSSStyleDeclaration> style = m_document->createCSSStyleDeclaration(); - ExceptionCode ec; - style->setProperty("color", color.name(), ec); - if (!innerFrame->editor()->shouldApplyStyle(style.get(), innerRange.get())) - return false; - m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData); - innerFrame->editor()->applyStyle(style.get(), EditActionSetColor); - return true; - } - - if (!m_page->dragController()->canProcessDrag(dragData)) { - m_page->dragCaretController()->clear(); - return false; - } - - if (HTMLInputElement* fileInput = asFileInput(element)) { - - if (!fileInput->isEnabled()) - return false; - - if (!dragData->containsFiles()) - return false; - - Vector<String> filenames; - dragData->asFilenames(filenames); - if (filenames.isEmpty()) - return false; - - // Ugly. For security none of the API's available to us to set the input value - // on file inputs. Even forcing a change in HTMLInputElement doesn't work as - // RenderFileUploadControl clears the file when doing updateFromElement() - RenderFileUploadControl* renderer = static_cast<RenderFileUploadControl*>(fileInput->renderer()); - - if (!renderer) - return false; - - // Only take the first filename as <input type="file" /> can only accept one - renderer->receiveDroppedFile(filenames[0]); - return true; - } - - Selection dragCaret(m_page->dragCaretController()->selection()); - m_page->dragCaretController()->clear(); - RefPtr<Range> range = dragCaret.toRange(); - - // For range to be null a WebKit client must have done something bad while - // manually controlling drag behaviour - if (!range) - return false; - DocLoader* loader = range->ownerDocument()->docLoader(); - loader->setAllowStaleResources(true); - if (dragIsMove(innerFrame->selection(), dragData) || dragCaret.isContentRichlyEditable()) { - bool chosePlainText = false; - RefPtr<DocumentFragment> fragment = documentFragmentFromDragData(dragData, range, true, chosePlainText); - if (!fragment || !innerFrame->editor()->shouldInsertFragment(fragment, range, EditorInsertActionDropped)) { - loader->setAllowStaleResources(false); - return false; - } - - m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData); - if (dragIsMove(innerFrame->selection(), dragData)) { - bool smartMove = innerFrame->selectionGranularity() == WordGranularity - && innerFrame->editor()->smartInsertDeleteEnabled() - && dragData->canSmartReplace(); - applyCommand(MoveSelectionCommand::create(fragment, dragCaret.base(), smartMove)); - } else { - if (setSelectionToDragCaret(innerFrame, dragCaret, range, point)) - applyCommand(ReplaceSelectionCommand::create(m_document, fragment, true, dragData->canSmartReplace(), chosePlainText)); - } - } else { - String text = dragData->asPlainText(); - if (text.isEmpty() || !innerFrame->editor()->shouldInsertText(text, range.get(), EditorInsertActionDropped)) { - loader->setAllowStaleResources(false); - return false; - } - - m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData); - if (setSelectionToDragCaret(innerFrame, dragCaret, range, point)) - applyCommand(ReplaceSelectionCommand::create(m_document, createFragmentFromText(range.get(), text), true, false, true)); - } - loader->setAllowStaleResources(false); - - return true; -} - - -bool DragController::canProcessDrag(DragData* dragData) -{ - ASSERT(dragData); - - if (!dragData->containsCompatibleContent()) - return false; - - IntPoint point = m_page->mainFrame()->view()->windowToContents(dragData->clientPosition()); - HitTestResult result = HitTestResult(point); - if (!m_page->mainFrame()->contentRenderer()) - return false; - - result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, true); - - if (!result.innerNonSharedNode()) - return false; - - if (dragData->containsFiles() && asFileInput(result.innerNonSharedNode())) - return true; - - if (!result.innerNonSharedNode()->isContentEditable()) - return false; - - if (m_didInitiateDrag && m_document == m_dragInitiator && result.isSelected()) - return false; - - return true; -} - -DragOperation DragController::tryDHTMLDrag(DragData* dragData) -{ - ASSERT(dragData); - ASSERT(m_document); - DragOperation op = DragOperationNone; - RefPtr<Frame> frame = m_page->mainFrame(); - RefPtr<FrameView> viewProtector = frame->view(); - if (!viewProtector) - return DragOperationNone; - - ClipboardAccessPolicy policy = frame->loader()->baseURL().isLocalFile() ? ClipboardReadable : ClipboardTypesReadable; - RefPtr<Clipboard> clipboard = dragData->createClipboard(policy); - DragOperation srcOp = dragData->draggingSourceOperationMask(); - clipboard->setSourceOperation(srcOp); - - PlatformMouseEvent event = createMouseEvent(dragData); - if (frame->eventHandler()->updateDragAndDrop(event, clipboard.get())) { - // *op unchanged if no source op was set - if (!clipboard->destinationOperation(op)) { - // The element accepted but they didn't pick an operation, so we pick one for them - // (as does WinIE). - if (srcOp & DragOperationCopy) - op = DragOperationCopy; - else if (srcOp & DragOperationMove || srcOp & DragOperationGeneric) - op = DragOperationMove; - else if (srcOp & DragOperationLink) - op = DragOperationLink; - else - op = DragOperationGeneric; - } else if (!(op & srcOp)) { - op = DragOperationNone; - } - - clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security - return op; - } - return op; -} - -bool DragController::mayStartDragAtEventLocation(const Frame* frame, const IntPoint& framePos) -{ - ASSERT(frame); - ASSERT(frame->settings()); - - if (!frame->view() || !frame->contentRenderer()) - return false; - - HitTestResult mouseDownTarget = HitTestResult(framePos); - - mouseDownTarget = frame->eventHandler()->hitTestResultAtPoint(framePos, true); - - if (mouseDownTarget.image() - && !mouseDownTarget.absoluteImageURL().isEmpty() - && frame->settings()->loadsImagesAutomatically() - && m_dragSourceAction & DragSourceActionImage) - return true; - - if (!mouseDownTarget.absoluteLinkURL().isEmpty() - && m_dragSourceAction & DragSourceActionLink - && mouseDownTarget.isLiveLink()) - return true; - - if (mouseDownTarget.isSelected() - && m_dragSourceAction & DragSourceActionSelection) - return true; - - return false; - -} - -static CachedImage* getCachedImage(Element* element) -{ - ASSERT(element); - RenderObject* renderer = element->renderer(); - if (!renderer || !renderer->isImage()) - return 0; - RenderImage* image = static_cast<RenderImage*>(renderer); - return image->cachedImage(); -} - -static Image* getImage(Element* 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()->image(); - return 0; -} - -static void prepareClipboardForImageDrag(Frame* src, Clipboard* clipboard, Element* node, const KURL& linkURL, const KURL& imageURL, const String& label) -{ - RefPtr<Range> range = src->document()->createRange(); - ExceptionCode ec = 0; - range->selectNode(node, ec); - ASSERT(ec == 0); - src->selection()->setSelection(Selection(range.get(), DOWNSTREAM)); - clipboard->declareAndWriteDragImage(node, !linkURL.isEmpty() ? linkURL : imageURL, label, src); -} - -static IntPoint dragLocForDHTMLDrag(const IntPoint& mouseDraggedPoint, const IntPoint& dragOrigin, const IntPoint& dragImageOffset, bool isLinkImage) -{ - // dragImageOffset is the cursor position relative to the lower-left corner of the image. -#if PLATFORM(MAC) - // We add in the Y dimension because we are a flipped view, so adding moves the image down. - const int yOffset = dragImageOffset.y(); -#else - const int yOffset = -dragImageOffset.y(); -#endif - - if (isLinkImage) - return IntPoint(mouseDraggedPoint.x() - dragImageOffset.x(), mouseDraggedPoint.y() + yOffset); - - return IntPoint(dragOrigin.x() - dragImageOffset.x(), dragOrigin.y() + yOffset); -} - -static IntPoint dragLocForSelectionDrag(Frame* src) -{ - IntRect draggingRect = enclosingIntRect(src->selectionRect()); - int xpos = draggingRect.right(); - xpos = draggingRect.x() < xpos ? draggingRect.x() : xpos; - int ypos = draggingRect.bottom(); -#if PLATFORM(MAC) - // Deal with flipped coordinates on Mac - ypos = draggingRect.y() > ypos ? draggingRect.y() : ypos; -#else - ypos = draggingRect.y() < ypos ? draggingRect.y() : ypos; -#endif - return IntPoint(xpos, ypos); -} - -bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin, bool isDHTMLDrag) -{ - ASSERT(src); - ASSERT(clipboard); - - if (!src->view() || !src->contentRenderer()) - return false; - - HitTestResult dragSource = HitTestResult(dragOrigin); - dragSource = src->eventHandler()->hitTestResultAtPoint(dragOrigin, true); - KURL linkURL = dragSource.absoluteLinkURL(); - KURL imageURL = dragSource.absoluteImageURL(); - bool isSelected = dragSource.isSelected(); - - IntPoint mouseDraggedPoint = src->view()->windowToContents(dragEvent.pos()); - - m_draggingImageURL = KURL(); - m_dragOperation = srcOp; - - DragImageRef dragImage = 0; - IntPoint dragLoc(0, 0); - IntPoint dragImageOffset(0, 0); - - if (isDHTMLDrag) - dragImage = clipboard->createDragImage(dragImageOffset); - - // We allow DHTML/JS to set the drag image, even if its a link, image or text we're dragging. - // This is in the spirit of the IE API, which allows overriding of pasteboard data and DragOp. - if (dragImage) { - dragLoc = dragLocForDHTMLDrag(mouseDraggedPoint, dragOrigin, dragImageOffset, !linkURL.isEmpty()); - m_dragOffset = dragImageOffset; - } - - bool startedDrag = true; // optimism - we almost always manage to start the drag - - Node* node = dragSource.innerNonSharedNode(); - - if (!imageURL.isEmpty() && node && node->isElementNode() - && getImage(static_cast<Element*>(node)) - && (m_dragSourceAction & DragSourceActionImage)) { - Element* element = static_cast<Element*>(node); - if (!clipboard->hasData()) { - m_draggingImageURL = imageURL; - prepareClipboardForImageDrag(src, clipboard, element, linkURL, imageURL, dragSource.altDisplayString()); - } - - m_client->willPerformDragSourceAction(DragSourceActionImage, dragOrigin, clipboard); - - if (!dragImage) { - IntRect imageRect = dragSource.imageRect(); - imageRect.setLocation(m_page->mainFrame()->view()->windowToContents(src->view()->contentsToWindow(imageRect.location()))); - doImageDrag(element, dragOrigin, dragSource.imageRect(), clipboard, src, m_dragOffset); - } else - // DHTML defined drag image - doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); - - } else if (!linkURL.isEmpty() && (m_dragSourceAction & DragSourceActionLink)) { - if (!clipboard->hasData()) - // Simplify whitespace so the title put on the clipboard resembles what the user sees - // on the web page. This includes replacing newlines with spaces. - clipboard->writeURL(linkURL, dragSource.textContent().simplifyWhiteSpace(), src); - - m_client->willPerformDragSourceAction(DragSourceActionLink, dragOrigin, clipboard); - if (!dragImage) { - dragImage = m_client->createDragImageForLink(linkURL, dragSource.textContent(), src); - IntSize size = dragImageSize(dragImage); - m_dragOffset = IntPoint(-size.width() / 2, -LinkDragBorderInset); - dragLoc = IntPoint(mouseDraggedPoint.x() + m_dragOffset.x(), mouseDraggedPoint.y() + m_dragOffset.y()); - } - doSystemDrag(dragImage, dragLoc, mouseDraggedPoint, clipboard, src, true); - } else if (isSelected && (m_dragSourceAction & DragSourceActionSelection)) { - RefPtr<Range> selectionRange = src->selection()->toRange(); - ASSERT(selectionRange); - if (!clipboard->hasData()) - clipboard->writeRange(selectionRange.get(), src); - m_client->willPerformDragSourceAction(DragSourceActionSelection, dragOrigin, clipboard); - if (!dragImage) { - dragImage = createDragImageForSelection(src); - dragLoc = dragLocForSelectionDrag(src); - m_dragOffset = IntPoint((int)(dragOrigin.x() - dragLoc.x()), (int)(dragOrigin.y() - dragLoc.y())); - } - doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); - } else if (isDHTMLDrag) { - ASSERT(m_dragSourceAction & DragSourceActionDHTML); - m_client->willPerformDragSourceAction(DragSourceActionDHTML, dragOrigin, clipboard); - doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); - } else { - // Only way I know to get here is if to get here is if the original element clicked on in the mousedown is no longer - // under the mousedown point, so linkURL, imageURL and isSelected are all false/empty. - startedDrag = false; - } - - if (dragImage) - deleteDragImage(dragImage); - return startedDrag; -} - -void DragController::doImageDrag(Element* element, const IntPoint& dragOrigin, const IntRect& rect, Clipboard* clipboard, Frame* frame, IntPoint& dragImageOffset) -{ - IntPoint mouseDownPoint = dragOrigin; - DragImageRef dragImage; - IntPoint origin; - - Image* image = getImage(element); - if (image && image->size().height() * image->size().width() <= MaxOriginalImageArea - && (dragImage = createDragImageFromImage(image))) { - IntSize originalSize = rect.size(); - origin = rect.location(); - - dragImage = fitDragImageToMaxSize(dragImage, rect.size(), maxDragImageSize()); - dragImage = dissolveDragImageToFraction(dragImage, DragImageAlpha); - IntSize newSize = dragImageSize(dragImage); - - // Properly orient the drag image and orient it differently if it's smaller than the original - float scale = newSize.width() / (float)originalSize.width(); - float dx = origin.x() - mouseDownPoint.x(); - dx *= scale; - origin.setX((int)(dx + 0.5)); -#if PLATFORM(MAC) - //Compensate for accursed flipped coordinates in cocoa - origin.setY(origin.y() + originalSize.height()); -#endif - float dy = origin.y() - mouseDownPoint.y(); - dy *= scale; - origin.setY((int)(dy + 0.5)); - } else { - dragImage = createDragImageIconForCachedImage(getCachedImage(element)); - if (dragImage) - origin = IntPoint(DragIconRightInset - dragImageSize(dragImage).width(), DragIconBottomInset); - } - - dragImageOffset.setX(mouseDownPoint.x() + origin.x()); - dragImageOffset.setY(mouseDownPoint.y() + origin.y()); - doSystemDrag(dragImage, dragImageOffset, dragOrigin, clipboard, frame, false); - - deleteDragImage(dragImage); -} - -void DragController::doSystemDrag(DragImageRef image, const IntPoint& dragLoc, const IntPoint& eventPos, Clipboard* clipboard, Frame* frame, bool forLink) -{ - m_didInitiateDrag = true; - m_dragInitiator = frame->document(); - // Protect this frame and view, as a load may occur mid drag and attempt to unload this frame - RefPtr<Frame> frameProtector = m_page->mainFrame(); - RefPtr<FrameView> viewProtector = frameProtector->view(); - m_client->startDrag(image, viewProtector->windowToContents(frame->view()->contentsToWindow(dragLoc)), - viewProtector->windowToContents(frame->view()->contentsToWindow(eventPos)), clipboard, frameProtector.get(), forLink); - - // Drag has ended, dragEnded *should* have been called, however it is possible - // for the UIDelegate to take over the drag, and fail to send the appropriate - // drag termination event. As dragEnded just resets drag variables, we just - // call it anyway to be on the safe side - // Except if drag and drop happens asynchronously, in which case dragging - // has not ended. - //dragEnded(); -} - -// Manual drag caret manipulation -void DragController::placeDragCaret(const IntPoint& windowPoint) -{ - Frame* mainFrame = m_page->mainFrame(); - Document* newDraggingDoc = mainFrame->documentAtPoint(windowPoint); - if (m_document != newDraggingDoc) { - if (m_document) - cancelDrag(); - m_document = newDraggingDoc; - } - if (!m_document) - return; - Frame* frame = m_document->frame(); - ASSERT(frame); - FrameView* frameView = frame->view(); - if (!frameView) - return; - IntPoint framePoint = frameView->windowToContents(windowPoint); - Selection dragCaret(frame->visiblePositionForPoint(framePoint)); - m_page->dragCaretController()->setSelection(dragCaret); -} - -} diff --git a/webkit/pending/EmptyClients.h b/webkit/pending/EmptyClients.h deleted file mode 100644 index ed169dc..0000000 --- a/webkit/pending/EmptyClients.h +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright (C) 2006 Eric Seidel (eric@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 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 EmptyClients_h -#define EmptyClients_h - -#include "ChromeClient.h" -#include "ContextMenuClient.h" -#include "DragClient.h" -#include "DocumentLoader.h" -#include "EditCommand.h" -#include "EditorClient.h" -#include "FocusDirection.h" -#include "FloatRect.h" -#include "FrameLoaderClient.h" -#include "InspectorClient.h" -#include "ResourceError.h" -#include "SharedBuffer.h" - -/* - This file holds empty Client stubs for use by WebCore. - Viewless element needs to create a dummy Page->Frame->FrameView tree for use in parsing or executing JavaScript. - This tree depends heavily on Clients (usually provided by WebKit classes). - - This file was first created for SVGImage as it had no way to access the current Page (nor should it, - since Images are not tied to a page). - See http://bugs.webkit.org/show_bug.cgi?id=5971 for the original discussion about this file. - - Ideally, whenever you change a Client class, you should add a stub here. - Brittle, yes. Unfortunate, yes. Hopefully temporary. -*/ - -namespace WebCore { - -class EmptyChromeClient : public ChromeClient { -public: - virtual ~EmptyChromeClient() { } - virtual void chromeDestroyed() { } - - virtual void setWindowRect(const FloatRect&) { } - virtual FloatRect windowRect() { return FloatRect(); } - - virtual FloatRect pageRect() { return FloatRect(); } - - virtual float scaleFactor() { return 1.f; } - - virtual void focus() { } - virtual void unfocus() { } - - virtual bool canTakeFocus(FocusDirection) { return false; } - virtual void takeFocus(FocusDirection) { } - - virtual Page* createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures&) { return 0; } - virtual void show() { } - - virtual bool canRunModal() { return false; } - virtual void runModal() { } - - virtual void setToolbarsVisible(bool) { } - virtual bool toolbarsVisible() { return false; } - - virtual void setStatusbarVisible(bool) { } - virtual bool statusbarVisible() { return false; } - - virtual void setScrollbarsVisible(bool) { } - virtual bool scrollbarsVisible() { return false; } - - virtual void setMenubarVisible(bool) { } - virtual bool menubarVisible() { return false; } - - virtual void setResizable(bool) { } - - virtual void addMessageToConsole(const String& message, unsigned int lineNumber, const String& sourceID) { } - - virtual bool canRunBeforeUnloadConfirmPanel() { return false; } - virtual bool runBeforeUnloadConfirmPanel(const String& message, Frame* frame) { return true; } - - virtual void closeWindowSoon() { } - - virtual void runJavaScriptAlert(Frame*, const String&) { } - virtual bool runJavaScriptConfirm(Frame*, const String&) { return false; } - virtual bool runJavaScriptPrompt(Frame*, const String& message, const String& defaultValue, String& result) { return false; } - virtual bool shouldInterruptJavaScript() { return false; } - - virtual void setStatusbarText(const String&) { } - - virtual bool tabsToLinks() const { return false; } - - virtual IntRect windowResizerRect() const { return IntRect(); } - virtual void addToDirtyRegion(const IntRect&) { } - virtual void scrollBackingStore(int dx, int dy, const IntRect& scrollViewRect, const IntRect& clipRect) { } - virtual void updateBackingStore() { } - - virtual void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags) { } - - virtual void setToolTip(const String&) { } - - virtual void print(Frame*) { } - - virtual void exceededDatabaseQuota(Frame*, const String&) { } -}; - -class EmptyFrameLoaderClient : public FrameLoaderClient { -public: - virtual ~EmptyFrameLoaderClient() { } - virtual void frameLoaderDestroyed() { } - - virtual bool hasWebView() const { return true; } // mainly for assertions - virtual bool hasFrameView() const { return true; } // ditto - - virtual void makeRepresentation(DocumentLoader*) { } - virtual void forceLayout() { } - virtual void forceLayoutForNonHTML() { } - - virtual void updateHistoryForCommit() { } - - virtual void updateHistoryForBackForwardNavigation() { } - virtual void updateHistoryForReload() { } - virtual void updateHistoryForStandardLoad() { } - virtual void updateHistoryForInternalLoad() { } - - virtual void updateHistoryAfterClientRedirect() { } - - virtual void setCopiesOnScroll() { } - - virtual void detachedFromParent2() { } - virtual void detachedFromParent3() { } - virtual void detachedFromParent4() { } - - virtual void download(ResourceHandle*, const ResourceRequest&, const ResourceRequest&, const ResourceResponse&) { } - - virtual void assignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader*, const ResourceRequest&) { } - virtual void dispatchWillSendRequest(DocumentLoader*, unsigned long identifier, ResourceRequest&, const ResourceResponse& redirectResponse) { } - virtual void dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) { } - virtual void dispatchDidCancelAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) { } - virtual void dispatchDidReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse&) { } - virtual void dispatchDidReceiveContentLength(DocumentLoader*, unsigned long identifier, int lengthReceived) { } - virtual void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier) { } - virtual void dispatchDidFailLoading(DocumentLoader*, unsigned long identifier, const ResourceError&) { } - virtual bool dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int length) { return false; } - - virtual void dispatchDidHandleOnloadEvents() { } - virtual void dispatchDidReceiveServerRedirectForProvisionalLoad() { } - virtual void dispatchDidCancelClientRedirect() { } - virtual void dispatchWillPerformClientRedirect(const KURL&, double interval, double fireDate) { } - virtual void dispatchDidChangeLocationWithinPage() { } - virtual void dispatchWillClose() { } - virtual void dispatchDidReceiveIcon() { } - virtual void dispatchDidStartProvisionalLoad() { } - virtual void dispatchDidReceiveTitle(const String& title) { } - virtual void dispatchDidCommitLoad() { } - virtual void dispatchDidFailProvisionalLoad(const ResourceError&) { } - virtual void dispatchDidFailLoad(const ResourceError&) { } - virtual void dispatchDidFinishDocumentLoad() { } - virtual void dispatchDidFinishLoad() { } - virtual void dispatchDidFirstLayout() { } - - virtual Frame* dispatchCreatePage() { return 0; } - virtual void dispatchShow() { } - - virtual void dispatchDecidePolicyForMIMEType(FramePolicyFunction, const String& MIMEType, const ResourceRequest&) { } - virtual void dispatchDecidePolicyForNewWindowAction(FramePolicyFunction, const NavigationAction&, const ResourceRequest&, PassRefPtr<FormState>, const String& frameName) { } - virtual void dispatchDecidePolicyForNavigationAction(FramePolicyFunction, const NavigationAction&, const ResourceRequest&, PassRefPtr<FormState>) { } - virtual void cancelPolicyCheck() { } - - virtual void dispatchUnableToImplementPolicy(const ResourceError&) { } - - virtual void dispatchWillSubmitForm(FramePolicyFunction, PassRefPtr<FormState>) { } - - virtual void dispatchDidLoadMainResource(DocumentLoader*) { } - virtual void revertToProvisionalState(DocumentLoader*) { } - virtual void setMainDocumentError(DocumentLoader*, const ResourceError&) { } - - virtual void willChangeEstimatedProgress() { } - virtual void didChangeEstimatedProgress() { } - virtual void postProgressStartedNotification() { } - virtual void postProgressEstimateChangedNotification() { } - virtual void postProgressFinishedNotification() { } - - virtual void setMainFrameDocumentReady(bool) { } - - virtual void startDownload(const ResourceRequest&) { } - - virtual void willChangeTitle(DocumentLoader*) { } - virtual void didChangeTitle(DocumentLoader*) { } - - virtual void committedLoad(DocumentLoader*, const char*, int) { } - virtual void finishedLoading(DocumentLoader*) { } - - virtual ResourceError cancelledError(const ResourceRequest&) { return ResourceError(); } - virtual ResourceError blockedError(const ResourceRequest&) { return ResourceError(); } - virtual ResourceError cannotShowURLError(const ResourceRequest&) { return ResourceError(); } - virtual ResourceError interruptForPolicyChangeError(const ResourceRequest&) { return ResourceError(); } - - virtual ResourceError cannotShowMIMETypeError(const ResourceResponse&) { return ResourceError(); } - virtual ResourceError fileDoesNotExistError(const ResourceResponse&) { return ResourceError(); } - virtual ResourceError pluginWillHandleLoadError(const ResourceResponse&) { return ResourceError(); } - - virtual bool shouldFallBack(const ResourceError&) { return false; } - - virtual bool canHandleRequest(const ResourceRequest&) const { return false; } - virtual bool canShowMIMEType(const String& MIMEType) const { return false; } - virtual bool representationExistsForURLScheme(const String& URLScheme) const { return false; } - virtual String generatedMIMETypeForURLScheme(const String& URLScheme) const { return ""; } - - virtual void frameLoadCompleted() { } - virtual void restoreViewState() { } - virtual void provisionalLoadStarted() { } - virtual bool shouldTreatURLAsSameAsCurrent(const KURL&) const { return false; } - virtual void addHistoryItemForFragmentScroll() { } - virtual void didFinishLoad() { } - virtual void prepareForDataSourceReplacement() { } - - virtual PassRefPtr<DocumentLoader> createDocumentLoader(const ResourceRequest& request, const SubstituteData& substituteData) { return DocumentLoader::create(request, substituteData); } - virtual void setTitle(const String& title, const KURL&) { } - - virtual String userAgent(const KURL&) { return ""; } - - virtual void savePlatformDataToCachedPage(CachedPage*) { } - virtual void transitionToCommittedFromCachedPage(CachedPage*) { } - virtual void transitionToCommittedForNewPage() { } - - virtual void updateGlobalHistory(const KURL&) { } - virtual bool shouldGoToHistoryItem(HistoryItem*) const { return false; } - virtual void saveViewStateToItem(HistoryItem*) { } - virtual bool canCachePage() const { return false; } - - virtual PassRefPtr<Frame> createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement, - const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight) { return 0; } - virtual Widget* createPlugin(const IntSize&,Element*, const KURL&, const Vector<String>&, const Vector<String>&, const String&, bool) { return 0; } - virtual Widget* createJavaAppletWidget(const IntSize&, Element*, const KURL&, const Vector<String>&, const Vector<String>&) { return 0; } - - virtual ObjectContentType objectContentType(const KURL& url, const String& mimeType) { return ObjectContentType(); } - virtual String overrideMediaType() const { return String(); } - - virtual void redirectDataToPlugin(Widget*) {} - virtual void windowObjectCleared() {} - virtual void didPerformFirstNavigation() const {} - - virtual void registerForIconNotification(bool listen) {} - - virtual void unloadListenerChanged() {} - -#if PLATFORM(MAC) - virtual NSCachedURLResponse* willCacheResponse(DocumentLoader*, unsigned long identifier, NSCachedURLResponse* response) const { return response; } -#endif - -}; - -class EmptyEditorClient : public EditorClient { -public: - virtual ~EmptyEditorClient() { } - virtual void pageDestroyed() { } - - virtual bool shouldDeleteRange(Range*) { return false; } - virtual bool shouldShowDeleteInterface(HTMLElement*) { return false; } - virtual bool smartInsertDeleteEnabled() { return false; } - virtual bool isContinuousSpellCheckingEnabled() { return false; } - virtual void toggleContinuousSpellChecking() { } - virtual bool isGrammarCheckingEnabled() { return false; } - virtual void toggleGrammarChecking() { } - virtual int spellCheckerDocumentTag() { return -1; } - - virtual bool selectWordBeforeMenuEvent() { return false; } - virtual bool isEditable() { return false; } - - virtual bool shouldBeginEditing(Range*) { return false; } - virtual bool shouldEndEditing(Range*) { return false; } - virtual bool shouldInsertNode(Node*, Range*, EditorInsertAction) { return false; } - // virtual bool shouldInsertNode(Node*, Range* replacingRange, WebViewInsertAction) { return false; } - virtual bool shouldInsertText(const String&, Range*, EditorInsertAction) { return false; } - virtual bool shouldChangeSelectedRange(Range* fromRange, Range* toRange, EAffinity, bool stillSelecting) { return false; } - - virtual bool shouldApplyStyle(CSSStyleDeclaration*, Range*) { return false; } - virtual bool shouldMoveRangeAfterDelete(Range*, Range*) { return false; } - // virtual bool shouldChangeTypingStyle(CSSStyleDeclaration* fromStyle, CSSStyleDeclaration* toStyle) { return false; } - // virtual bool doCommandBySelector(SEL selector) { return false; } - // - virtual void didBeginEditing() { } - virtual void respondToChangedContents() { } - virtual void respondToChangedSelection() { } - virtual void didEndEditing() { } - virtual void didWriteSelectionToPasteboard() { } - virtual void didSetSelectionTypesForPasteboard() { } - // virtual void webViewDidChangeTypingStyle:(NSNotification *)notification { } - // virtual void webViewDidChangeSelection:(NSNotification *)notification { } - // virtual NSUndoManager* undoManagerForWebView:(WebView *)webView { return 0; } - - virtual void registerCommandForUndo(PassRefPtr<EditCommand>) { } - virtual void registerCommandForRedo(PassRefPtr<EditCommand>) { } - virtual void clearUndoRedoOperations() { } - - virtual bool canUndo() const { return false; } - virtual bool canRedo() const { return false; } - - virtual void undo() { } - virtual void redo() { } - - virtual void handleKeyboardEvent(KeyboardEvent*) { } - virtual void handleInputMethodKeydown(KeyboardEvent*) { } - - virtual void textFieldDidBeginEditing(Element*) { } - virtual void textFieldDidEndEditing(Element*) { } - virtual void textDidChangeInTextField(Element*) { } - virtual bool doTextFieldCommandFromEvent(Element*, KeyboardEvent*) { return false; } - virtual void textWillBeDeletedInTextField(Element*) { } - virtual void textDidChangeInTextArea(Element*) { } - -#if PLATFORM(MAC) - virtual void markedTextAbandoned(Frame*) { } - - virtual NSString* userVisibleString(NSURL*) { return 0; } -#ifdef BUILDING_ON_TIGER - virtual NSArray* pasteboardTypesForSelection(Frame*) { return 0; } -#endif -#endif - virtual void ignoreWordInSpellDocument(const String&) { } - virtual void learnWord(const String&) { } - virtual void checkSpellingOfString(const UChar*, int length, int* misspellingLocation, int* misspellingLength) { } - virtual void checkGrammarOfString(const UChar*, int length, Vector<GrammarDetail>&, int* badGrammarLocation, int* badGrammarLength) { } - virtual void updateSpellingUIWithGrammarString(const String&, const GrammarDetail&) { } - virtual void updateSpellingUIWithMisspelledWord(const String&) { } - virtual void showSpellingUI(bool show) { } - virtual bool spellingUIIsShowing() { return false; } - virtual void getGuessesForWord(const String&, Vector<String>& guesses) { } - virtual void setInputMethodState(bool enabled) { } - - -}; - -class EmptyContextMenuClient : public ContextMenuClient { -public: - virtual ~EmptyContextMenuClient() { } - virtual void contextMenuDestroyed() { } - - virtual PlatformMenuDescription getCustomMenuFromDefaultItems(ContextMenu*) { return 0; } - virtual void contextMenuItemSelected(ContextMenuItem*, const ContextMenu*) { } - - virtual void downloadURL(const KURL& url) { } - virtual void copyImageToClipboard(const HitTestResult&) { } - virtual void searchWithGoogle(const Frame*) { } - virtual void lookUpInDictionary(Frame*) { } - virtual void speak(const String&) { } - virtual void stopSpeaking() { } - -#if PLATFORM(MAC) - virtual void searchWithSpotlight() { } -#endif -}; - -class EmptyDragClient : public DragClient { -public: - virtual ~EmptyDragClient() {} - virtual void willPerformDragDestinationAction(DragDestinationAction, DragData*) { } - virtual void willPerformDragSourceAction(DragSourceAction, const IntPoint&, Clipboard*) { } - virtual DragDestinationAction actionMaskForDrag(DragData*) { return DragDestinationActionNone; } - virtual DragSourceAction dragSourceActionMaskForPoint(const IntPoint&) { return DragSourceActionNone; } - virtual void startDrag(DragImageRef, const IntPoint&, const IntPoint&, Clipboard*, Frame*, bool) { } - virtual DragImageRef createDragImageForLink(KURL&, const String& label, Frame*) { return 0; } - virtual void dragControllerDestroyed() { } -}; - -class EmptyInspectorClient : public InspectorClient { -public: - virtual ~EmptyInspectorClient() {} - - virtual void inspectorDestroyed() {}; - - virtual Page* createPage() { return 0; }; - - virtual String localizedStringsURL() { return String(); }; - - virtual void showWindow() {}; - virtual void closeWindow() {}; - - virtual void attachWindow() {}; - virtual void detachWindow() {}; - - virtual void setAttachedWindowHeight(unsigned) {}; - - virtual void highlight(Node*) {}; - virtual void hideHighlight() {}; - virtual void inspectedURLChanged(const String& newURL) {}; -}; - -} - -#endif // EmptyClients_h diff --git a/webkit/pending/EventHandler.cpp b/webkit/pending/EventHandler.cpp deleted file mode 100644 index 4570913..0000000 --- a/webkit/pending/EventHandler.cpp +++ /dev/null @@ -1,2142 +0,0 @@ -/* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2006 Alexey Proskuryakov (ap@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 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 "EventHandler.h" - -#include "AXObjectCache.h" -#include "CachedImage.h" -#include "ChromeClient.h" -#include "Cursor.h" -#include "Document.h" -#include "DragController.h" -#include "Editor.h" -#include "EventNames.h" -#include "FloatPoint.h" -#include "FloatRect.h" -#include "FocusController.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "FrameTree.h" -#include "FrameView.h" -#include "HitTestRequest.h" -#include "HitTestResult.h" -#include "HTMLFrameSetElement.h" -#include "HTMLFrameElementBase.h" -#include "HTMLInputElement.h" -#include "HTMLNames.h" -#include "Image.h" -#include "KeyboardEvent.h" -#include "MouseEvent.h" -#include "MouseEventWithHitTestResults.h" -#include "Page.h" -#include "PlatformKeyboardEvent.h" -#include "PlatformScrollBar.h" -#include "PlatformWheelEvent.h" -#include "RenderFrameSet.h" -#include "RenderWidget.h" -#include "RenderView.h" -#include "SelectionController.h" -#include "Settings.h" -#include "TextEvent.h" - -#if ENABLE(SVG) -#include "SVGDocument.h" -#include "SVGNames.h" -#endif - -namespace WebCore { - -using namespace EventNames; -using namespace HTMLNames; - -// The link drag hysteresis is much larger than the others because there -// needs to be enough space to cancel the link press without starting a link drag, -// and because dragging links is rare. -const int LinkDragHysteresis = 40; -const int ImageDragHysteresis = 5; -const int TextDragHysteresis = 3; -const int GeneralDragHysteresis = 3; - -// Match key code of composition keydown event on windows. -// IE sends VK_PROCESSKEY which has value 229; -const int CompositionEventKeyCode = 229; - -#if ENABLE(SVG) -using namespace SVGNames; -#endif - -// When the autoscroll or the panScroll is triggered when do the scroll every 0.05s to make it smooth -const double autoscrollInterval = 0.05; - -static Frame* subframeForTargetNode(Node* node); - -static inline void scrollAndAcceptEvent(float delta, ScrollDirection positiveDirection, ScrollDirection negativeDirection, bool pageScrollEnabled, PlatformWheelEvent& e, Node* node, float windowHeightOrWidth) -{ - if (!delta) - return; - - float pixelsToScroll = delta > 0 ? delta : -delta; - if (!e.isContinuous() && !pageScrollEnabled) { - if (node->renderer()->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByLine, pixelsToScroll)) - e.accept(); - } else { - if (pageScrollEnabled) - pixelsToScroll = windowHeightOrWidth; - if (node->renderer()->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, pixelsToScroll)) - e.accept(); - } -} - -EventHandler::EventHandler(Frame* frame) - : m_frame(frame) - , m_mousePressed(false) - , m_mouseDownMayStartSelect(false) - , m_mouseDownMayStartDrag(false) - , m_mouseDownWasSingleClickInSelection(false) - , m_beganSelectingText(false) - , m_panScrollInProgress(false) - , m_hoverTimer(this, &EventHandler::hoverTimerFired) - , m_autoscrollTimer(this, &EventHandler::autoscrollTimerFired) - , m_autoscrollRenderer(0) - , m_autoscrollInProgress(false) - , m_mouseDownMayStartAutoscroll(false) - , m_mouseDownWasInSubframe(false) -#if ENABLE(SVG) - , m_svgPan(false) -#endif - , m_resizeLayer(0) - , m_capturingMouseEventsNode(0) - , m_clickCount(0) - , m_mouseDownTimestamp(0) - , m_pendingFrameUnloadEventCount(0) - , m_pendingFrameBeforeUnloadEventCount(0) -#if PLATFORM(MAC) - , m_mouseDownView(nil) - , m_sendingEventToSubview(false) - , m_activationEventNumber(0) -#endif -{ -} - -EventHandler::~EventHandler() -{ -} - -EventHandler::EventHandlerDragState& EventHandler::dragState() -{ - static EventHandlerDragState state; - return state; -} - -void EventHandler::clear() -{ - m_hoverTimer.stop(); - m_resizeLayer = 0; - m_nodeUnderMouse = 0; - m_lastNodeUnderMouse = 0; - m_lastMouseMoveEventSubframe = 0; - m_lastScrollbarUnderMouse = 0; - m_clickCount = 0; - m_clickNode = 0; - m_frameSetBeingResized = 0; - m_dragTarget = 0; - m_currentMousePosition = IntPoint(); - m_mousePressNode = 0; - m_mousePressed = false; - m_capturingMouseEventsNode = 0; -} - -void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result) -{ - Node* innerNode = result.targetNode(); - Selection newSelection; - - if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) { - VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint())); - if (pos.isNotNull()) { - newSelection = Selection(pos); - newSelection.expandUsingGranularity(WordGranularity); - } - - if (newSelection.isRange()) { - m_frame->setSelectionGranularity(WordGranularity); - m_beganSelectingText = true; - } - - if (m_frame->shouldChangeSelection(newSelection)) - m_frame->selection()->setSelection(newSelection); - } -} - -void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result) -{ - if (!result.hitTestResult().isLiveLink()) - return selectClosestWordFromMouseEvent(result); - - Node* innerNode = result.targetNode(); - - if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) { - Selection newSelection; - Element* URLElement = result.hitTestResult().URLElement(); - VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint())); - if (pos.isNotNull() && pos.deepEquivalent().node()->isDescendantOf(URLElement)) - newSelection = Selection::selectionFromContentsOfNode(URLElement); - - if (newSelection.isRange()) { - m_frame->setSelectionGranularity(WordGranularity); - m_beganSelectingText = true; - } - - if (m_frame->shouldChangeSelection(newSelection)) - m_frame->selection()->setSelection(newSelection); - } -} - -bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event) -{ - if (event.event().button() != LeftButton) - return false; - - if (m_frame->selection()->isRange()) - // A double-click when range is already selected - // should not change the selection. So, do not call - // selectClosestWordFromMouseEvent, but do set - // m_beganSelectingText to prevent handleMouseReleaseEvent - // from setting caret selection. - m_beganSelectingText = true; - else - selectClosestWordFromMouseEvent(event); - - return true; -} - -bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event) -{ - if (event.event().button() != LeftButton) - return false; - - Node* innerNode = event.targetNode(); - if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect)) - return false; - - Selection newSelection; - VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint())); - if (pos.isNotNull()) { - newSelection = Selection(pos); - newSelection.expandUsingGranularity(ParagraphGranularity); - } - if (newSelection.isRange()) { - m_frame->setSelectionGranularity(ParagraphGranularity); - m_beganSelectingText = true; - } - - if (m_frame->shouldChangeSelection(newSelection)) - m_frame->selection()->setSelection(newSelection); - - return true; -} - -bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event) -{ - if (event.event().button() != LeftButton) - return false; - - Node* innerNode = event.targetNode(); - if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect)) - return false; - - // Extend the selection if the Shift key is down, unless the click is in a link. - bool extendSelection = event.event().shiftKey() && !event.isOverLink(); - - // Don't restart the selection when the mouse is pressed on an - // existing selection so we can allow for text dragging. - IntPoint vPoint = m_frame->view()->windowToContents(event.event().pos()); - if (!extendSelection && m_frame->selection()->contains(vPoint)) { - m_mouseDownWasSingleClickInSelection = true; - return false; - } - - VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint())); - if (visiblePos.isNull()) - visiblePos = VisiblePosition(innerNode, 0, DOWNSTREAM); - Position pos = visiblePos.deepEquivalent(); - - Selection newSelection = m_frame->selection()->selection(); - if (extendSelection && newSelection.isCaretOrRange()) { - m_frame->selection()->setLastChangeWasHorizontalExtension(false); - - // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection - // was created right-to-left - Position start = newSelection.start(); - Position end = newSelection.end(); - short before = Range::compareBoundaryPoints(pos.node(), pos.offset(), start.node(), start.offset()); - if (before <= 0) - newSelection = Selection(pos, end); - else - newSelection = Selection(start, pos); - - if (m_frame->selectionGranularity() != CharacterGranularity) - newSelection.expandUsingGranularity(m_frame->selectionGranularity()); - m_beganSelectingText = true; - } else { - newSelection = Selection(visiblePos); - m_frame->setSelectionGranularity(CharacterGranularity); - } - - if (m_frame->shouldChangeSelection(newSelection)) - m_frame->selection()->setSelection(newSelection); - - return true; -} - -bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event) -{ - // Reset drag state. - dragState().m_dragSrc = 0; - - bool singleClick = event.event().clickCount() <= 1; - - // If we got the event back, that must mean it wasn't prevented, - // so it's allowed to start a drag or selection. - m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode()); - - // Careful that the drag starting logic stays in sync with eventMayStartDrag() - m_mouseDownMayStartDrag = singleClick; - - m_mouseDownWasSingleClickInSelection = false; - - if (passWidgetMouseDownEventToWidget(event)) - return true; - -#if ENABLE(SVG) - if (m_frame->document()->isSVGDocument() && - static_cast<SVGDocument*>(m_frame->document())->zoomAndPanEnabled()) { - if (event.event().shiftKey() && singleClick) { - m_svgPan = true; - static_cast<SVGDocument*>(m_frame->document())->startPan(event.event().pos()); - return true; - } - } -#endif - - // We don't do this at the start of mouse down handling, - // because we don't want to do it until we know we didn't hit a widget. - if (singleClick) - focusDocumentView(); - - Node* innerNode = event.targetNode(); - - m_mousePressNode = innerNode; - m_dragStartPos = event.event().pos(); - - bool swallowEvent = false; - if (event.event().button() == LeftButton || event.event().button() == MiddleButton) { - m_frame->selection()->setCaretBlinkingSuspended(true); - m_mousePressed = true; - m_beganSelectingText = false; - - if (event.event().clickCount() == 2) - swallowEvent = handleMousePressEventDoubleClick(event); - else if (event.event().clickCount() >= 3) - swallowEvent = handleMousePressEventTripleClick(event); - else - swallowEvent = handleMousePressEventSingleClick(event); - } - - m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect || - (m_mousePressNode && m_mousePressNode->renderer() && m_mousePressNode->renderer()->canBeProgramaticallyScrolled(true)); - - return swallowEvent; -} - -bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event) -{ - if (handleDrag(event)) - return true; - - if (!m_mousePressed) - return false; - - Node* targetNode = event.targetNode(); - if (event.event().button() != LeftButton || !targetNode || !targetNode->renderer()) - return false; - -#if PLATFORM(MAC) // FIXME: Why does this assertion fire on other platforms? - ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll); -#endif - - m_mouseDownMayStartDrag = false; - - if (m_mouseDownMayStartAutoscroll && !m_panScrollInProgress) { - // If the selection is contained in a layer that can scroll, that layer should handle the autoscroll - // Otherwise, let the bridge handle it so the view can scroll itself. - RenderObject* renderer = targetNode->renderer(); - while (renderer && !renderer->canBeProgramaticallyScrolled(false)) { - if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement()) - renderer = renderer->document()->ownerElement()->renderer(); - else - renderer = renderer->parent(); - } - - if (renderer) { - m_autoscrollInProgress = true; - handleAutoscroll(renderer); - } - - m_mouseDownMayStartAutoscroll = false; - } - - updateSelectionForMouseDrag(targetNode, event.localPoint()); - return true; -} - -bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const -{ - // This is a pre-flight check of whether the event might lead to a drag being started. Be careful - // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag - // in handleMousePressEvent - - if (!m_frame->contentRenderer() || !m_frame->contentRenderer()->hasLayer() - || event.button() != LeftButton || event.clickCount() != 1) - return false; - - bool DHTMLFlag; - bool UAFlag; - allowDHTMLDrag(DHTMLFlag, UAFlag); - if (!DHTMLFlag && !UAFlag) - return false; - - HitTestRequest request(true, false); - HitTestResult result(m_frame->view()->windowToContents(event.pos())); - m_frame->contentRenderer()->layer()->hitTest(request, result); - bool srcIsDHTML; - return result.innerNode() && result.innerNode()->renderer()->draggableNode(DHTMLFlag, UAFlag, result.point().x(), result.point().y(), srcIsDHTML); -} - -void EventHandler::updateSelectionForMouseDrag() -{ - FrameView* view = m_frame->view(); - if (!view) - return; - RenderObject* renderer = m_frame->contentRenderer(); - if (!renderer) - return; - RenderLayer* layer = renderer->layer(); - if (!layer) - return; - - HitTestResult result(view->windowToContents(m_currentMousePosition)); - layer->hitTest(HitTestRequest(true, true, true), result); - updateSelectionForMouseDrag(result.innerNode(), result.localPoint()); -} - -void EventHandler::updateSelectionForMouseDrag(Node* targetNode, const IntPoint& localPoint) -{ - if (!m_mouseDownMayStartSelect) - return; - - if (!targetNode) - return; - - RenderObject* targetRenderer = targetNode->renderer(); - if (!targetRenderer) - return; - - if (!canMouseDragExtendSelect(targetNode)) - return; - - VisiblePosition targetPosition(targetRenderer->positionForPoint(localPoint)); - - // Don't modify the selection if we're not on a node. - if (targetPosition.isNull()) - return; - - // Restart the selection if this is the first mouse move. This work is usually - // done in handleMousePressEvent, but not if the mouse press was on an existing selection. - Selection newSelection = m_frame->selection()->selection(); - -#if ENABLE(SVG) - // Special case to limit selection to the containing block for SVG text. - // FIXME: Isn't there a better non-SVG-specific way to do this? - if (Node* selectionBaseNode = newSelection.base().node()) - if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer()) - if (selectionBaseRenderer->isSVGText()) - if (targetNode->renderer()->containingBlock() != selectionBaseRenderer->containingBlock()) - return; -#endif - - if (!m_beganSelectingText) { - m_beganSelectingText = true; - newSelection = Selection(targetPosition); - } - - newSelection.setExtent(targetPosition); - if (m_frame->selectionGranularity() != CharacterGranularity) - newSelection.expandUsingGranularity(m_frame->selectionGranularity()); - - if (m_frame->shouldChangeSelection(newSelection)) { - m_frame->selection()->setLastChangeWasHorizontalExtension(false); - m_frame->selection()->setSelection(newSelection); - } -} - -bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event) -{ - if (eventLoopHandleMouseUp(event)) - return true; - - // If this was the first click in the window, we don't even want to clear the selection. - // This case occurs when the user clicks on a draggable element, since we have to process - // the mouse down and drag events to see if we might start a drag. For other first clicks - // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets - // ignored upstream of this layer. - return eventActivatedView(event.event()); -} - -bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event) -{ - if (m_autoscrollInProgress) - stopAutoscrollTimer(); - - if (handleMouseUp(event)) - return true; - - // Used to prevent mouseMoveEvent from initiating a drag before - // the mouse is pressed again. - m_frame->selection()->setCaretBlinkingSuspended(false); - m_mousePressed = false; - m_mouseDownMayStartDrag = false; - m_mouseDownMayStartSelect = false; - m_mouseDownMayStartAutoscroll = false; - m_mouseDownWasInSubframe = false; - - bool handled = false; - - // Clear the selection if the mouse didn't move after the last mouse press. - // We do this so when clicking on the selection, the selection goes away. - // However, if we are editing, place the caret. - if (m_mouseDownWasSingleClickInSelection && !m_beganSelectingText - && m_dragStartPos == event.event().pos() - && m_frame->selection()->isRange()) { - Selection newSelection; - Node *node = event.targetNode(); - if (node && node->isContentEditable() && node->renderer()) { - VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint()); - newSelection = Selection(pos); - } - if (m_frame->shouldChangeSelection(newSelection)) - m_frame->selection()->setSelection(newSelection); - - handled = true; - } - - m_frame->notifyRendererOfSelectionChange(true); - - m_frame->selection()->selectFrameElementInParentIfFullySelected(); - - return handled; -} - -void EventHandler::handleAutoscroll(RenderObject* renderer) -{ - // We don't want to trigger the autoscroll or the panScroll if it's already active - if (m_autoscrollTimer.isActive()) - return; - - setAutoscrollRenderer(renderer); - -#if PLATFORM(WIN) - if (m_panScrollInProgress) { - m_panScrollStartPos = currentMousePosition(); - m_frame->view()->printPanScrollIcon(m_panScrollStartPos); - // If we're not in the top frame we notify it that we are using the panScroll - if (m_frame != m_frame->page()->mainFrame()) - m_frame->page()->mainFrame()->eventHandler()->setPanScrollInProgress(true); - } -#endif - - startAutoscrollTimer(); -} - -void EventHandler::autoscrollTimerFired(Timer<EventHandler>*) -{ - RenderObject* r = autoscrollRenderer(); - if (!r) { - stopAutoscrollTimer(); - return; - } - - if (m_autoscrollInProgress) { - if (!m_mousePressed) { - stopAutoscrollTimer(); - return; - } - r->autoscroll(); - } else { - // we verify that the main frame hasn't received the order to stop the panScroll - if (!m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress()) { - stopAutoscrollTimer(); - return; - } -#if PLATFORM(WIN) - setPanScrollCursor(); - r->panScroll(m_panScrollStartPos); -#endif - } -} - -void EventHandler::setPanScrollCursor() -{ - // At the original click location we draw a 4 arrowed icon. Over this icon there won't be any scroll - // So we don't want to change the cursor over this area - const int noScrollRadius = 9; - bool east = m_panScrollStartPos.x() < (m_currentMousePosition.x() - noScrollRadius); - bool west = m_panScrollStartPos.x() > (m_currentMousePosition.x() + noScrollRadius); - bool north = m_panScrollStartPos.y() > (m_currentMousePosition.y() + noScrollRadius); - bool south = m_panScrollStartPos.y() < (m_currentMousePosition.y() - noScrollRadius); - - if (north) { - if (east) - m_frame->view()->setCursor(northEastPanningCursor()); - else if (west) - m_frame->view()->setCursor(northWestPanningCursor()); - else - m_frame->view()->setCursor(northPanningCursor()); - } else if (south) { - if (east) - m_frame->view()->setCursor(southEastPanningCursor()); - else if (west) - m_frame->view()->setCursor(southWestPanningCursor()); - else - m_frame->view()->setCursor(southPanningCursor()); - } else if (east) - m_frame->view()->setCursor(eastPanningCursor()); - else if (west) - m_frame->view()->setCursor(westPanningCursor()); - else - m_frame->view()->setCursor(middlePanningCursor()); -} - -RenderObject* EventHandler::autoscrollRenderer() const -{ - return m_autoscrollRenderer; -} - -void EventHandler::updateAutoscrollRenderer() -{ - if (!m_autoscrollRenderer) - return; - - HitTestResult hitTest = hitTestResultAtPoint(m_panScrollStartPos, true); - - if (Node* nodeAtPoint = hitTest.innerNode()) - m_autoscrollRenderer = nodeAtPoint->renderer(); - - while (m_autoscrollRenderer && !m_autoscrollRenderer->canBeProgramaticallyScrolled(false)) - m_autoscrollRenderer = m_autoscrollRenderer->parent(); -} - -void EventHandler::setAutoscrollRenderer(RenderObject* renderer) -{ - m_autoscrollRenderer = renderer; -} - -void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const -{ - if (!m_frame || !m_frame->document()) { - flagDHTML = false; - flagUA = false; - } - - unsigned mask = m_frame->page()->dragController()->delegateDragSourceAction(m_frame->view()->contentsToWindow(m_mouseDownPos)); - flagDHTML = (mask & DragSourceActionDHTML) != DragSourceActionNone; - flagUA = ((mask & DragSourceActionImage) || (mask & DragSourceActionLink) || (mask & DragSourceActionSelection)); -} - -HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool allowShadowContent) -{ - HitTestResult result(point); - if (!m_frame->contentRenderer()) - return result; - m_frame->contentRenderer()->layer()->hitTest(HitTestRequest(true, true), result); - - while (true) { - Node* n = result.innerNode(); - if (!n || !n->renderer() || !n->renderer()->isWidget()) - break; - Widget* widget = static_cast<RenderWidget*>(n->renderer())->widget(); - if (!widget || !widget->isFrameView()) - break; - Frame* frame = static_cast<HTMLFrameElementBase*>(n)->contentFrame(); - if (!frame || !frame->contentRenderer()) - break; - FrameView* view = static_cast<FrameView*>(widget); - IntPoint widgetPoint(result.localPoint().x() + view->contentsX() - n->renderer()->borderLeft() - n->renderer()->paddingLeft(), - result.localPoint().y() + view->contentsY() - n->renderer()->borderTop() - n->renderer()->paddingTop()); - HitTestResult widgetHitTestResult(widgetPoint); - frame->contentRenderer()->layer()->hitTest(HitTestRequest(true, true), widgetHitTestResult); - result = widgetHitTestResult; - } - - if (!allowShadowContent) - result.setToNonShadowAncestor(); - - return result; -} - - -void EventHandler::startAutoscrollTimer() -{ - m_autoscrollTimer.startRepeating(autoscrollInterval); -} - -void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed) -{ - if (m_autoscrollInProgress) { - if (m_mouseDownWasInSubframe) { - if (Frame* subframe = subframeForTargetNode(m_mousePressNode.get())) - subframe->eventHandler()->stopAutoscrollTimer(rendererIsBeingDestroyed); - return; - } - } - - if (autoscrollRenderer()) { - if (!rendererIsBeingDestroyed && (m_autoscrollInProgress || m_panScrollInProgress)) - autoscrollRenderer()->stopAutoscroll(); -#if PLATFORM(WIN) - if (m_panScrollInProgress) { - m_frame->view()->removePanScrollIcon(); - } -#endif - - setAutoscrollRenderer(0); - } - - m_autoscrollTimer.stop(); - - m_panScrollInProgress = false; - // If we're not in the top frame we notify it that we are not using the panScroll anymore - if (m_frame->page() && m_frame != m_frame->page()->mainFrame()) - m_frame->page()->mainFrame()->eventHandler()->setPanScrollInProgress(false); - m_autoscrollInProgress = false; -} - -Node* EventHandler::mousePressNode() const -{ - return m_mousePressNode.get(); -} - -void EventHandler::setMousePressNode(PassRefPtr<Node> node) -{ - m_mousePressNode = node; -} - -bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity) -{ - if (!m_frame->document()) - return false; - - Node* node = m_frame->document()->focusedNode(); - if (!node) - node = m_mousePressNode.get(); - - if (node) { - RenderObject *r = node->renderer(); - if (r && !r->isListBox()) - return r->scroll(direction, granularity); - } - - return false; -} - -IntPoint EventHandler::currentMousePosition() const -{ - return m_currentMousePosition; -} - -Frame* subframeForTargetNode(Node* node) -{ - if (!node) - return 0; - - RenderObject* renderer = node->renderer(); - if (!renderer || !renderer->isWidget()) - return 0; - - Widget* widget = static_cast<RenderWidget*>(renderer)->widget(); - if (!widget || !widget->isFrameView()) - return 0; - - return static_cast<FrameView*>(widget)->frame(); -} - -static bool isSubmitImage(Node* node) -{ - return node && node->hasTagName(inputTag) - && static_cast<HTMLInputElement*>(node)->inputType() == HTMLInputElement::IMAGE; -} - -// Returns true if the node's editable block is not current focused for editing -static bool nodeIsNotBeingEdited(Node* node, Frame* frame) -{ - return frame->selection()->rootEditableElement() != node->rootEditableElement(); -} - -Cursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, PlatformScrollbar* scrollbar) -{ - // During selection, use an I-beam no matter what we're over. - // If you're capturing mouse events for a particular node, don't treat this as a selection. - if (m_mousePressed && m_mouseDownMayStartSelect && m_frame->selection()->isCaretOrRange() && !m_capturingMouseEventsNode) - return iBeamCursor(); - - Node* node = event.targetNode(); - RenderObject* renderer = node ? node->renderer() : 0; - RenderStyle* style = renderer ? renderer->style() : 0; - - if (renderer && renderer->isFrameSet()) { - RenderFrameSet* fs = static_cast<RenderFrameSet*>(renderer); - if (fs->canResizeRow(event.localPoint())) - return rowResizeCursor(); - if (fs->canResizeColumn(event.localPoint())) - return columnResizeCursor(); - } - - if (style && style->cursors()) { - const CursorList* cursors = style->cursors(); - for (unsigned i = 0; i < cursors->size(); ++i) { - CachedImage* cimage = (*cursors)[i].cursorImage; - IntPoint hotSpot = (*cursors)[i].hotSpot; - if (!cimage) - continue; - // Limit the size of cursors so that they cannot be used to cover UI elements in chrome. - IntSize size = cimage->image()->size(); - if (size.width() > 128 || size.height() > 128) - continue; - // Do not let the hotspot be outside the bounds of the image. - if (hotSpot.x() < 0 || hotSpot.y() < 0 || hotSpot.x() > size.width() || hotSpot.y() > size.height()) - continue; - if (cimage->image()->isNull()) - break; - if (!cimage->errorOccurred()) - return Cursor(cimage->image(), hotSpot); - } - } - - switch (style ? style->cursor() : CURSOR_AUTO) { - case CURSOR_AUTO: { - bool editable = (node && node->isContentEditable()); - bool editableLinkEnabled = false; - - // If the link is editable, then we need to check the settings to see whether or not the link should be followed - if (editable) { - ASSERT(m_frame->settings()); - switch(m_frame->settings()->editableLinkBehavior()) { - default: - case EditableLinkDefaultBehavior: - case EditableLinkAlwaysLive: - editableLinkEnabled = true; - break; - - case EditableLinkNeverLive: - editableLinkEnabled = false; - break; - - case EditableLinkLiveWhenNotFocused: - editableLinkEnabled = nodeIsNotBeingEdited(node, m_frame) || event.event().shiftKey(); - break; - - case EditableLinkOnlyLiveWithShiftKey: - editableLinkEnabled = event.event().shiftKey(); - break; - } - } - - if ((event.isOverLink() || isSubmitImage(node)) && (!editable || editableLinkEnabled)) - return handCursor(); - RenderLayer* layer = renderer ? renderer->enclosingLayer() : 0; - bool inResizer = false; - if (m_frame->view() && layer && layer->isPointInResizeControl(m_frame->view()->windowToContents(event.event().pos()))) - inResizer = true; - if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !scrollbar) - return iBeamCursor(); - return pointerCursor(); - } - case CURSOR_CROSS: - return crossCursor(); - case CURSOR_POINTER: - return handCursor(); - case CURSOR_MOVE: - return moveCursor(); - case CURSOR_ALL_SCROLL: - return moveCursor(); - case CURSOR_E_RESIZE: - return eastResizeCursor(); - case CURSOR_W_RESIZE: - return westResizeCursor(); - case CURSOR_N_RESIZE: - return northResizeCursor(); - case CURSOR_S_RESIZE: - return southResizeCursor(); - case CURSOR_NE_RESIZE: - return northEastResizeCursor(); - case CURSOR_SW_RESIZE: - return southWestResizeCursor(); - case CURSOR_NW_RESIZE: - return northWestResizeCursor(); - case CURSOR_SE_RESIZE: - return southEastResizeCursor(); - case CURSOR_NS_RESIZE: - return northSouthResizeCursor(); - case CURSOR_EW_RESIZE: - return eastWestResizeCursor(); - case CURSOR_NESW_RESIZE: - return northEastSouthWestResizeCursor(); - case CURSOR_NWSE_RESIZE: - return northWestSouthEastResizeCursor(); - case CURSOR_COL_RESIZE: - return columnResizeCursor(); - case CURSOR_ROW_RESIZE: - return rowResizeCursor(); - case CURSOR_TEXT: - return iBeamCursor(); - case CURSOR_WAIT: - return waitCursor(); - case CURSOR_HELP: - return helpCursor(); - case CURSOR_VERTICAL_TEXT: - return verticalTextCursor(); - case CURSOR_CELL: - return cellCursor(); - case CURSOR_CONTEXT_MENU: - return contextMenuCursor(); - case CURSOR_PROGRESS: - return progressCursor(); - case CURSOR_NO_DROP: - return noDropCursor(); - case CURSOR_ALIAS: - return aliasCursor(); - case CURSOR_COPY: - return copyCursor(); - case CURSOR_NONE: - return noneCursor(); - case CURSOR_NOT_ALLOWED: - return notAllowedCursor(); - case CURSOR_DEFAULT: - return pointerCursor(); - case CURSOR_WEBKIT_ZOOM_IN: - return zoomInCursor(); - case CURSOR_WEBKIT_ZOOM_OUT: - return zoomOutCursor(); - } - return pointerCursor(); -} - -bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent) -{ - if (!m_frame->document()) - return false; - - RefPtr<FrameView> protector(m_frame->view()); - - m_mousePressed = true; - m_currentMousePosition = mouseEvent.pos(); - m_mouseDownTimestamp = mouseEvent.timestamp(); - m_mouseDownMayStartDrag = false; - m_mouseDownMayStartSelect = false; - m_mouseDownMayStartAutoscroll = false; - m_mouseDownPos = m_frame->view()->windowToContents(mouseEvent.pos()); - m_mouseDownWasInSubframe = false; - - MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(false, true), mouseEvent); - - if (!mev.targetNode()) { - invalidateClick(); - return false; - } - - m_mousePressNode = mev.targetNode(); - - Frame* subframe = subframeForTargetNode(mev.targetNode()); - if (subframe && passMousePressEventToSubframe(mev, subframe)) { - // Start capturing future events for this frame. We only do this if we didn't clear - // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop. - if (m_mousePressed) - m_capturingMouseEventsNode = mev.targetNode(); - invalidateClick(); - return true; - } - -#if PLATFORM(WIN) - if (m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress() || m_autoscrollInProgress) { - stopAutoscrollTimer(); - invalidateClick(); - return true; - } - - if (mouseEvent.button() == MiddleButton && !mev.isOverLink()) { - RenderObject* renderer = mev.targetNode()->renderer(); - - while (renderer && !renderer->canBeProgramaticallyScrolled(false)) { - if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement()) - renderer = renderer->document()->ownerElement()->renderer(); - else - renderer = renderer->parent(); - } - - if (renderer) { - m_panScrollInProgress = true; - handleAutoscroll(renderer); - invalidateClick(); - return true; - } - } -#endif - - m_clickCount = mouseEvent.clickCount(); - m_clickNode = mev.targetNode(); - - RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0; - IntPoint p = m_frame->view()->windowToContents(mouseEvent.pos()); - if (layer && layer->isPointInResizeControl(p)) { - layer->setInResizeMode(true); - m_resizeLayer = layer; - m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p); - invalidateClick(); - return true; - } - - bool swallowEvent = dispatchMouseEvent(mousedownEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true); - - // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults - // in case the scrollbar widget was destroyed when the mouse event was handled. - if (mev.scrollbar()) { - const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get(); - mev = prepareMouseEvent(HitTestRequest(true, true), mouseEvent); - - if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get()) - m_lastScrollbarUnderMouse = 0; - } - - if (swallowEvent) { - // scrollbars should get events anyway, even disabled controls might be scrollable - PlatformScrollbar* scrollbar = mev.scrollbar(); - if (!scrollbar) - scrollbar = m_frame->view()->scrollbarUnderMouse(mouseEvent); - if (scrollbar) - passMousePressEventToScrollbar(mev, scrollbar); - } else { - // Refetch the event target node if it currently is the shadow node inside an <input> element. - // If a mouse event handler changes the input element type to one that has a widget associated, - // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the - // event target node can't still be the shadow node. - if (mev.targetNode()->isShadowNode() && mev.targetNode()->shadowParentNode()->hasTagName(inputTag)) - mev = prepareMouseEvent(HitTestRequest(true, true), mouseEvent); - - PlatformScrollbar* scrollbar = m_frame->view()->scrollbarUnderMouse(mouseEvent); - if (!scrollbar) - scrollbar = mev.scrollbar(); - if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar)) - swallowEvent = true; - else - swallowEvent = handleMousePressEvent(mev); - } - - return swallowEvent; -} - -// This method only exists for platforms that don't know how to deliver -bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent) -{ - if (!m_frame->document()) - return false; - - RefPtr<FrameView> protector(m_frame->view()); - - // We get this instead of a second mouse-up - m_mousePressed = false; - m_currentMousePosition = mouseEvent.pos(); - - MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(false, true), mouseEvent); - Frame* subframe = subframeForTargetNode(mev.targetNode()); - if (subframe && passMousePressEventToSubframe(mev, subframe)) { - m_capturingMouseEventsNode = 0; - return true; - } - - m_clickCount = mouseEvent.clickCount(); - bool swallowMouseUpEvent = dispatchMouseEvent(mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false); - - bool swallowClickEvent = false; - // Don't ever dispatch click events for right clicks - if (mouseEvent.button() != RightButton && mev.targetNode() == m_clickNode) - swallowClickEvent = dispatchMouseEvent(clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true); - - bool swallowMouseReleaseEvent = false; - if (!swallowMouseUpEvent) - swallowMouseReleaseEvent = handleMouseReleaseEvent(mev); - - invalidateClick(); - - return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent; -} - -bool EventHandler::mouseMoved(const PlatformMouseEvent& event) -{ - HitTestResult hoveredNode = HitTestResult(IntPoint()); - bool result = handleMouseMoveEvent(event, &hoveredNode); - - Page* page = m_frame->page(); - if (!page) - return result; - - hoveredNode.setToNonShadowAncestor(); - page->chrome()->mouseDidMoveOverElement(hoveredNode, event.modifierFlags()); - page->chrome()->setToolTip(hoveredNode); - return result; -} - -bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode) -{ - // in Radar 3703768 we saw frequent crashes apparently due to the - // part being null here, which seems impossible, so check for nil - // but also assert so that we can try to figure this out in debug - // builds, if it happens. - ASSERT(m_frame); - if (!m_frame || !m_frame->document()) - return false; - - RefPtr<FrameView> protector(m_frame->view()); - m_currentMousePosition = mouseEvent.pos(); - - if (m_hoverTimer.isActive()) - m_hoverTimer.stop(); - -#if ENABLE(SVG) - if (m_svgPan) { - static_cast<SVGDocument*>(m_frame->document())->updatePan(m_currentMousePosition); - return true; - } -#endif - - if (m_frameSetBeingResized) - return dispatchMouseEvent(mousemoveEvent, m_frameSetBeingResized.get(), false, 0, mouseEvent, false); - - // Send events right to a scrollbar if the mouse is pressed. - if (m_lastScrollbarUnderMouse && m_mousePressed) - return m_lastScrollbarUnderMouse->handleMouseMoveEvent(mouseEvent); - - // Treat mouse move events while the mouse is pressed as "read-only" in prepareMouseEvent - // if we are allowed to select. - // This means that :hover and :active freeze in the state they were in when the mouse - // was pressed, rather than updating for nodes the mouse moves over as you hold the mouse down. - HitTestRequest request(m_mousePressed && m_mouseDownMayStartSelect, m_mousePressed, true); - MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent); - if (hoveredNode) - *hoveredNode = mev.hitTestResult(); - - PlatformScrollbar* scrollbar = 0; - - if (m_resizeLayer && m_resizeLayer->inResizeMode()) - m_resizeLayer->resize(mouseEvent, m_offsetFromResizeCorner); - else { - if (m_frame->view()) - scrollbar = m_frame->view()->scrollbarUnderMouse(mouseEvent); - - if (!scrollbar) - scrollbar = mev.scrollbar(); - - if (m_lastScrollbarUnderMouse != scrollbar) { - // Send mouse exited to the old scrollbar. - if (m_lastScrollbarUnderMouse) - m_lastScrollbarUnderMouse->handleMouseOutEvent(mouseEvent); - m_lastScrollbarUnderMouse = m_mousePressed ? 0 : scrollbar; - } - } - - bool swallowEvent = false; - Node* targetNode = m_capturingMouseEventsNode ? m_capturingMouseEventsNode.get() : mev.targetNode(); - RefPtr<Frame> newSubframe = subframeForTargetNode(targetNode); - - // We want mouseouts to happen first, from the inside out. First send a move event to the last subframe so that it will fire mouseouts. - if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree()->isDescendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe) - passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get()); - - if (newSubframe) { - // Update over/out state before passing the event to the subframe. - updateMouseEventTargetNode(mev.targetNode(), mouseEvent, true); - - // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target - // node to be detached from its FrameView, in which case the event should not be passed. - - // Manually merge changes from webkit trunk to fix the crash for - // http://www.coolpc.com.tw/evaluate.php - // See http://trac.webkit.org/changeset/31788. - if (newSubframe->view()) - swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode); - } else { - if (scrollbar && !m_mousePressed) - scrollbar->handleMouseMoveEvent(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering. - if ((!m_resizeLayer || !m_resizeLayer->inResizeMode()) && !m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress() && m_frame->view()) - m_frame->view()->setCursor(selectCursor(mev, scrollbar)); - } - - m_lastMouseMoveEventSubframe = newSubframe; - - if (swallowEvent) - return true; - - swallowEvent = dispatchMouseEvent(mousemoveEvent, mev.targetNode(), false, 0, mouseEvent, true); - if (!swallowEvent) - swallowEvent = handleMouseDraggedEvent(mev); - - return swallowEvent; -} - -void EventHandler::invalidateClick() -{ - m_clickCount = 0; - m_clickNode = 0; -} - -bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent) -{ - if (!m_frame->document()) - return false; - - RefPtr<FrameView> protector(m_frame->view()); - - m_mousePressed = false; - m_currentMousePosition = mouseEvent.pos(); - -#if ENABLE(SVG) - if (m_svgPan) { - m_svgPan = false; - static_cast<SVGDocument*>(m_frame->document())->updatePan(m_currentMousePosition); - return true; - } -#endif - - if (m_frameSetBeingResized) - return dispatchMouseEvent(mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, mouseEvent, false); - - if (m_lastScrollbarUnderMouse) { - invalidateClick(); - return m_lastScrollbarUnderMouse->handleMouseReleaseEvent(mouseEvent); - } - - MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(false, false, false, true), mouseEvent); - Node* targetNode = m_capturingMouseEventsNode.get() ? m_capturingMouseEventsNode.get() : mev.targetNode(); - Frame* subframe = subframeForTargetNode(targetNode); - if (subframe && passMouseReleaseEventToSubframe(mev, subframe)) { - m_capturingMouseEventsNode = 0; - return true; - } - - bool swallowMouseUpEvent = dispatchMouseEvent(mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false); - - // Don't ever dispatch click events for right clicks - bool swallowClickEvent = false; - if (m_clickCount > 0 && mouseEvent.button() != RightButton && mev.targetNode() == m_clickNode) - swallowClickEvent = dispatchMouseEvent(clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true); - - if (m_resizeLayer) { - m_resizeLayer->setInResizeMode(false); - m_resizeLayer = 0; - } - - bool swallowMouseReleaseEvent = false; - if (!swallowMouseUpEvent) - swallowMouseReleaseEvent = handleMouseReleaseEvent(mev); - - invalidateClick(); - - return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent; -} - -bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard) -{ - IntPoint contentsPos = m_frame->view()->windowToContents(event.pos()); - - RefPtr<MouseEvent> me = MouseEvent::create(eventType, - true, true, m_frame->document()->defaultView(), - 0, event.globalX(), event.globalY(), contentsPos.x(), contentsPos.y(), - event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(), - 0, 0, clipboard); - - ExceptionCode ec = 0; - EventTargetNodeCast(dragTarget)->dispatchEvent(me.get(), ec, true); - return me->defaultPrevented(); -} - -bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard) -{ - bool accept = false; - - if (!m_frame->document()) - return false; - - if (!m_frame->view()) - return false; - - MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(true, false), event); - - // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch) - Node* newTarget = mev.targetNode(); - if (newTarget && newTarget->isTextNode()) - newTarget = newTarget->parentNode(); - if (newTarget) - newTarget = newTarget->shadowAncestorNode(); - - if (m_dragTarget != newTarget) { - // FIXME: this ordering was explicitly chosen to match WinIE. However, - // it is sometimes incorrect when dragging within subframes, as seen with - // LayoutTests/fast/events/drag-in-frames.html. - if (newTarget) - if (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeTag)) - accept = static_cast<HTMLFrameElementBase*>(newTarget)->contentFrame()->eventHandler()->updateDragAndDrop(event, clipboard); - else - accept = dispatchDragEvent(dragenterEvent, newTarget, event, clipboard); - - if (m_dragTarget) { - Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag)) - ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())->contentFrame() : 0; - if (frame) - accept = frame->eventHandler()->updateDragAndDrop(event, clipboard); - else - dispatchDragEvent(dragleaveEvent, m_dragTarget.get(), event, clipboard); - } - } else { - if (newTarget) - if (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeTag)) - accept = static_cast<HTMLFrameElementBase*>(newTarget)->contentFrame()->eventHandler()->updateDragAndDrop(event, clipboard); - else - accept = dispatchDragEvent(dragoverEvent, newTarget, event, clipboard); - } - m_dragTarget = newTarget; - - return accept; -} - -void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard) -{ - if (m_dragTarget) { - Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag)) - ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())->contentFrame() : 0; - if (frame) - frame->eventHandler()->cancelDragAndDrop(event, clipboard); - else - dispatchDragEvent(dragleaveEvent, m_dragTarget.get(), event, clipboard); - } - clearDragState(); -} - -bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard) -{ - bool accept = false; - if (m_dragTarget) { - Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag)) - ? static_cast<HTMLFrameElementBase*>(m_dragTarget.get())->contentFrame() : 0; - if (frame) - accept = frame->eventHandler()->performDragAndDrop(event, clipboard); - else - accept = dispatchDragEvent(dropEvent, m_dragTarget.get(), event, clipboard); - } - clearDragState(); - return accept; -} - -void EventHandler::clearDragState() -{ - m_dragTarget = 0; - m_capturingMouseEventsNode = 0; -#if PLATFORM(MAC) - m_sendingEventToSubview = false; -#endif -} - -Node* EventHandler::nodeUnderMouse() const -{ - return m_nodeUnderMouse.get(); -} - -void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n) -{ - m_capturingMouseEventsNode = n; -} - -MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev) -{ - ASSERT(m_frame); - ASSERT(m_frame->document()); - - IntPoint documentPoint = m_frame->view()->windowToContents(mev.pos()); - return m_frame->document()->prepareMouseEvent(request, documentPoint, mev); -} - -void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut) -{ - Node* result = targetNode; - - // If we're capturing, we always go right to that node. - if (m_capturingMouseEventsNode) - result = m_capturingMouseEventsNode.get(); - else { - // If the target node is a text node, dispatch on the parent node - rdar://4196646 - if (result && result->isTextNode()) - result = result->parentNode(); - if (result) - result = result->shadowAncestorNode(); - } - m_nodeUnderMouse = result; - - // Fire mouseout/mouseover if the mouse has shifted to a different node. - if (fireMouseOverOut) { - if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame->document()) { - m_lastNodeUnderMouse = 0; - m_lastScrollbarUnderMouse = 0; - } - - if (m_lastNodeUnderMouse != m_nodeUnderMouse) { - // send mouseout event to the old node - if (m_lastNodeUnderMouse) - EventTargetNodeCast(m_lastNodeUnderMouse.get())->dispatchMouseEvent(mouseEvent, mouseoutEvent, 0, m_nodeUnderMouse.get()); - // send mouseover event to the new node - if (m_nodeUnderMouse) - EventTargetNodeCast(m_nodeUnderMouse.get())->dispatchMouseEvent(mouseEvent, mouseoverEvent, 0, m_lastNodeUnderMouse.get()); - } - m_lastNodeUnderMouse = m_nodeUnderMouse; - } -} - -bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool cancelable, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder) -{ - updateMouseEventTargetNode(targetNode, mouseEvent, setUnder); - - bool swallowEvent = false; - - if (m_nodeUnderMouse) - swallowEvent = EventTargetNodeCast(m_nodeUnderMouse.get())->dispatchMouseEvent(mouseEvent, eventType, clickCount); - - if (!swallowEvent && eventType == mousedownEvent) { - // Blur current focus node when a link/button is clicked; this - // is expected by some sites that rely on onChange handlers running - // from form fields before the button click is processed. - Node* node = m_nodeUnderMouse.get(); - RenderObject* renderer = node ? node->renderer() : 0; - - // Walk up the render tree to search for a node to focus. - // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields. - while (renderer) { - node = renderer->element(); - if (node && node->isFocusable()) { - // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus a - // node on mouse down if it's selected and inside a focused node. It will be - // focused if the user does a mouseup over it, however, because the mouseup - // will set a selection inside it, which will call setFocuseNodeIfNeeded. - ExceptionCode ec = 0; - Node* n = node->isShadowNode() ? node->shadowParentNode() : node; - if (m_frame->selection()->isRange() && - m_frame->selection()->toRange()->compareNode(n, ec) == Range::NODE_INSIDE && - n->isDescendantOf(m_frame->document()->focusedNode())) - return false; - - break; - } - - renderer = renderer->parent(); - } - // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent - // if the page already set it (e.g., by canceling default behavior). - if (node && node->isMouseFocusable()) { - if (!m_frame->page()->focusController()->setFocusedNode(node, m_frame)) - swallowEvent = true; - } else if (!node || !node->focused()) { - if (!m_frame->page()->focusController()->setFocusedNode(0, m_frame)) - swallowEvent = true; - } - } - - return swallowEvent; -} - -bool EventHandler::handleWheelEvent(PlatformWheelEvent& e) -{ - Document* doc = m_frame->document(); - if (!doc) - return false; - - RenderObject* docRenderer = doc->renderer(); - if (!docRenderer) - return false; - - IntPoint vPoint = m_frame->view()->windowToContents(e.pos()); - - HitTestRequest request(true, false); - HitTestResult result(vPoint); - doc->renderer()->layer()->hitTest(request, result); - Node* node = result.innerNode(); - - if (node) { - // Figure out which view to send the event to. - RenderObject* target = node->renderer(); - - if (target && target->isWidget()) { - Widget* widget = static_cast<RenderWidget*>(target)->widget(); - - if (widget && passWheelEventToWidget(e, widget)) { - e.accept(); - return true; - } - } - - node = node->shadowAncestorNode(); - EventTargetNodeCast(node)->dispatchWheelEvent(e); - if (e.isAccepted()) - return true; - - if (node->renderer()) { - // Just break up into two scrolls if we need to. Diagonal movement on - // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set). - float deltaX = e.isContinuous() ? e.continuousDeltaX() : e.deltaX(); - float deltaY = e.isContinuous() ? e.continuousDeltaY() : e.deltaY(); - - scrollAndAcceptEvent(deltaX, ScrollLeft, ScrollRight, e.isPageXScrollModeEnabled(), e, node, m_frame->page()->chrome()->windowRect().width()); - scrollAndAcceptEvent(deltaY, ScrollUp, ScrollDown, e.isPageYScrollModeEnabled(), e, node, m_frame->page()->chrome()->windowRect().height()); - } - } - - if (!e.isAccepted()) - m_frame->view()->wheelEvent(e); - - return e.isAccepted(); -} - -bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event) -{ - Document* doc = m_frame->document(); - FrameView* v = m_frame->view(); - if (!doc || !v) - return false; - - bool swallowEvent; - IntPoint viewportPos = v->windowToContents(event.pos()); - MouseEventWithHitTestResults mev = doc->prepareMouseEvent(HitTestRequest(false, true), viewportPos, event); - -#if 0 - // The following commented out code tries to select the word below the - // mouse cursor on right click. This used to be behavior that could be - // changed by webkit embedders, but in change 24499, that functionality was - // removed. - // https://bugs.webkit.org/show_bug.cgi?id=15279 - - if (!m_frame->selection()->contains(viewportPos) && - // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse. - // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items - // available for text selections. But only if we're above text. - (m_frame->selection()->isContentEditable() || mev.targetNode() && mev.targetNode()->isTextNode())) { - m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection - selectClosestWordOrLinkFromMouseEvent(mev); - } -#endif - swallowEvent = dispatchMouseEvent(contextmenuEvent, mev.targetNode(), true, 0, event, true); - - return swallowEvent; -} - -void EventHandler::scheduleHoverStateUpdate() -{ - if (!m_hoverTimer.isActive()) - m_hoverTimer.startOneShot(0); -} - -// Whether or not a mouse down can begin the creation of a selection. Fires the selectStart event. -bool EventHandler::canMouseDownStartSelect(Node* node) -{ - if (!node || !node->renderer()) - return true; - - // Some controls and images can't start a select on a mouse down. - if (!node->canStartSelection()) - return false; - - for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) - if (Node* node = curr->element()) - return EventTargetNodeCast(node)->dispatchHTMLEvent(selectstartEvent, true, true); - - return true; -} - -bool EventHandler::canMouseDragExtendSelect(Node* node) -{ - if (!node || !node->renderer()) - return true; - - for (RenderObject* curr = node->renderer(); curr; curr = curr->parent()) - if (Node* node = curr->element()) - return EventTargetNodeCast(node)->dispatchHTMLEvent(selectstartEvent, true, true); - - return true; -} - -void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet) -{ - m_frameSetBeingResized = frameSet; -} - -void EventHandler::resizeLayerDestroyed() -{ - ASSERT(m_resizeLayer); - m_resizeLayer = 0; -} - -void EventHandler::hoverTimerFired(Timer<EventHandler>*) -{ - m_hoverTimer.stop(); - - ASSERT(m_frame); - ASSERT(m_frame->document()); - - if (RenderObject* renderer = m_frame->contentRenderer()) { - HitTestResult result(m_frame->view()->windowToContents(m_currentMousePosition)); - renderer->layer()->hitTest(HitTestRequest(false, false, true), result); - m_frame->document()->updateRendering(); - } -} - -static EventTargetNode* eventTargetNodeForDocument(Document* doc) -{ - if (!doc) - return 0; - Node* node = doc->focusedNode(); - if (!node) { - if (doc->isHTMLDocument()) - node = doc->body(); - else - node = doc->documentElement(); - if (!node) - return 0; - } - return EventTargetNodeCast(node); -} - -bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt) -{ - if ((evt.modifiers() & s_accessKeyModifiers) != s_accessKeyModifiers) - return false; - String key = evt.unmodifiedText(); - Element* elem = m_frame->document()->getElementByAccessKey(key.lower()); - if (!elem) - return false; - elem->accessKeyAction(false); - return true; -} - -#if !PLATFORM(MAC) -bool EventHandler::needsKeyboardEventDisambiguationQuirks() const -{ - return false; -} -#endif - -bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent) -{ -#if PLATFORM(WIN) || (PLATFORM(WX) && PLATFORM(WIN_OS)) - String escKeyId = "U+001B"; - // If a key is pressed while the autoscroll/panScroll is in progress then we want to stop - if (initialKeyEvent.keyIdentifier() == escKeyId && m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress() || m_autoscrollInProgress) - stopAutoscrollTimer(); -#endif - - // Check for cases where we are too early for events -- possible unmatched key up - // from pressing return in the location bar. - RefPtr<EventTargetNode> node = eventTargetNodeForDocument(m_frame->document()); - if (!node) - return false; - - // FIXME: what is this doing here, in keyboard event handler? - m_frame->loader()->resetMultipleFormSubmissionProtection(); - - // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match. - // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict - // with access keys. Then we dispatch keydown, but suppress its default handling. - // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages. - // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events. - bool matchedAnAccessKey = false; - if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyDown) - matchedAnAccessKey = handleAccessKey(initialKeyEvent); - - // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch. - if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyUp || initialKeyEvent.type() == PlatformKeyboardEvent::Char) - return !node->dispatchKeyEvent(initialKeyEvent); - - bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks(); - - ExceptionCode ec; - PlatformKeyboardEvent keyDownEvent = initialKeyEvent; - if (keyDownEvent.type() != PlatformKeyboardEvent::RawKeyDown) - keyDownEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown, backwardCompatibilityMode); - RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView()); - if (matchedAnAccessKey) - keydown->setDefaultPrevented(true); - keydown->setTarget(node); - - if (initialKeyEvent.type() == PlatformKeyboardEvent::RawKeyDown) { - node->dispatchEvent(keydown, ec, true); - return keydown->defaultHandled() || keydown->defaultPrevented(); - } - - // Run input method in advance of DOM event handling. This may result in the IM - // modifying the page prior the keydown event, but this behaviour is necessary - // in order to match IE: - // 1. preventing default handling of keydown and keypress events has no effect on IM input; - // 2. if an input method handles the event, its keyCode is set to 229 in keydown event. - m_frame->editor()->handleInputMethodKeydown(keydown.get()); - - bool handledByInputMethod = keydown->defaultHandled(); - - if (handledByInputMethod) { - keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode); - keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView()); - keydown->setTarget(node); - keydown->setDefaultHandled(); - } - - node->dispatchEvent(keydown, ec, true); - bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented(); - if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode)) - return keydownResult; - - // Focus may have changed during keydown handling, so refetch node. - // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node. - if (!keydownResult) { - node = eventTargetNodeForDocument(m_frame->document()); - if (!node) - return false; - } - - PlatformKeyboardEvent keyPressEvent = initialKeyEvent; - keyPressEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::Char, backwardCompatibilityMode); - if (keyPressEvent.text().isEmpty()) - return keydownResult; - RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->defaultView()); - keypress->setTarget(node); - if (keydownResult) - keypress->setDefaultPrevented(true); -#if PLATFORM(MAC) - keypress->keypressCommands() = keydown->keypressCommands(); -#endif - node->dispatchEvent(keypress, ec, true); - - return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled(); -} - -void EventHandler::handleKeyboardSelectionMovement(KeyboardEvent* event) -{ - if (!event) - return; - - String key = event->keyIdentifier(); - bool isShifted = event->getModifierState("Shift"); - bool isOptioned = event->getModifierState("Alt"); - - if (key == "Up") { - m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::BACKWARD, LineGranularity, true); - event->setDefaultHandled(); - } - else if (key == "Down") { - m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::FORWARD, LineGranularity, true); - event->setDefaultHandled(); - } - else if (key == "Left") { - m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::LEFT, (isOptioned) ? WordGranularity : CharacterGranularity, true); - event->setDefaultHandled(); - } - else if (key == "Right") { - m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::RIGHT, (isOptioned) ? WordGranularity : CharacterGranularity, true); - event->setDefaultHandled(); - } -} - -void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event) -{ - if (event->type() == keydownEvent) { - m_frame->editor()->handleKeyboardEvent(event); - if (event->defaultHandled()) - return; - if (event->keyIdentifier() == "U+0009") - defaultTabEventHandler(event); - - // provides KB navigation and selection for enhanced accessibility users - if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled()) - handleKeyboardSelectionMovement(event); - } - if (event->type() == keypressEvent) { - m_frame->editor()->handleKeyboardEvent(event); - if (event->defaultHandled()) - return; - } -} - -bool EventHandler::dragHysteresisExceeded(const FloatPoint& floatDragViewportLocation) const -{ - IntPoint dragViewportLocation((int)floatDragViewportLocation.x(), (int)floatDragViewportLocation.y()); - return dragHysteresisExceeded(dragViewportLocation); -} - -bool EventHandler::dragHysteresisExceeded(const IntPoint& dragViewportLocation) const -{ - IntPoint dragLocation = m_frame->view()->windowToContents(dragViewportLocation); - IntSize delta = dragLocation - m_mouseDownPos; - - int threshold = GeneralDragHysteresis; - if (dragState().m_dragSrcIsImage) - threshold = ImageDragHysteresis; - else if (dragState().m_dragSrcIsLink) - threshold = LinkDragHysteresis; - else if (dragState().m_dragSrcInSelection) - threshold = TextDragHysteresis; - - return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold; -} - -void EventHandler::freeClipboard() -{ - if (dragState().m_dragClipboard) - dragState().m_dragClipboard->setAccessPolicy(ClipboardNumb); -} - -bool EventHandler::shouldDragAutoNode(Node* node, const IntPoint& point) const -{ - ASSERT(node); - if (node->hasChildNodes() || !m_frame->view()) - return false; - return m_frame->page() && m_frame->page()->dragController()->mayStartDragAtEventLocation(m_frame, point); -} - -void EventHandler::dragSourceMovedTo(const PlatformMouseEvent& event) -{ - if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) - // for now we don't care if event handler cancels default behavior, since there is none - dispatchDragSrcEvent(dragEvent, event); -} - -void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation) -{ - if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) { - dragState().m_dragClipboard->setDestinationOperation(operation); - // for now we don't care if event handler cancels default behavior, since there is none - dispatchDragSrcEvent(dragendEvent, event); - } - freeClipboard(); - dragState().m_dragSrc = 0; -} - -// returns if we should continue "default processing", i.e., whether eventhandler canceled -bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event) -{ - return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dragState().m_dragClipboard.get()); -} - -bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event) -{ - if (event.event().button() != LeftButton || event.event().eventType() != MouseEventMoved) { - // If we allowed the other side of the bridge to handle a drag - // last time, then m_mousePressed might still be set. So we - // clear it now to make sure the next move after a drag - // doesn't look like a drag. - m_mousePressed = false; - return false; - } - - if (eventLoopHandleMouseDragged(event)) - return true; - - // Careful that the drag starting logic stays in sync with eventMayStartDrag() - - if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) { - allowDHTMLDrag(dragState().m_dragSrcMayBeDHTML, dragState().m_dragSrcMayBeUA); - if (!dragState().m_dragSrcMayBeDHTML && !dragState().m_dragSrcMayBeUA) - m_mouseDownMayStartDrag = false; // no element is draggable - } - - if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) { - // try to find an element that wants to be dragged - HitTestRequest request(true, false); - HitTestResult result(m_mouseDownPos); - m_frame->contentRenderer()->layer()->hitTest(request, result); - Node* node = result.innerNode(); - if (node && node->renderer()) - dragState().m_dragSrc = node->renderer()->draggableNode(dragState().m_dragSrcMayBeDHTML, dragState().m_dragSrcMayBeUA, - m_mouseDownPos.x(), m_mouseDownPos.y(), dragState().m_dragSrcIsDHTML); - else - dragState().m_dragSrc = 0; - - if (!dragState().m_dragSrc) - m_mouseDownMayStartDrag = false; // no element is draggable - else { - // remember some facts about this source, while we have a HitTestResult handy - node = result.URLElement(); - dragState().m_dragSrcIsLink = node && node->isLink(); - - node = result.innerNonSharedNode(); - dragState().m_dragSrcIsImage = node && node->renderer() && node->renderer()->isImage(); - - dragState().m_dragSrcInSelection = m_frame->selection()->contains(m_mouseDownPos); - } - } - - // For drags starting in the selection, the user must wait between the mousedown and mousedrag, - // or else we bail on the dragging stuff and allow selection to occur - if (m_mouseDownMayStartDrag && !dragState().m_dragSrcIsImage && dragState().m_dragSrcInSelection && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) { - m_mouseDownMayStartDrag = false; - dragState().m_dragSrc = 0; - // ...but if this was the first click in the window, we don't even want to start selection - if (eventActivatedView(event.event())) - m_mouseDownMayStartSelect = false; - } - - if (!m_mouseDownMayStartDrag) - return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll; - - // We are starting a text/image/url drag, so the cursor should be an arrow - m_frame->view()->setCursor(pointerCursor()); - - if (!dragHysteresisExceeded(event.event().pos())) - return true; - - // Once we're past the hysteresis point, we don't want to treat this gesture as a click - invalidateClick(); - - DragOperation srcOp = DragOperationNone; - - freeClipboard(); // would only happen if we missed a dragEnd. Do it anyway, just - // to make sure it gets numbified - dragState().m_dragClipboard = createDraggingClipboard(); - - if (dragState().m_dragSrcMayBeDHTML) { - // Check to see if the is a DOM based drag, if it is get the DOM specified drag - // image and offset - if (dragState().m_dragSrcIsDHTML) { - int srcX, srcY; - if (RenderObject* renderer = dragState().m_dragSrc->renderer()) { - renderer->absolutePosition(srcX, srcY); - IntSize delta = m_mouseDownPos - IntPoint(srcX, srcY); - dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), IntPoint() + delta); - } else { - // The renderer has disappeared, this can happen if the onStartDrag handler has hidden - // the element in some way. In this case we just kill the drag. - m_mouseDownMayStartDrag = false; - goto cleanupDrag; - } - } - - m_mouseDownMayStartDrag = dispatchDragSrcEvent(dragstartEvent, m_mouseDown) - && !m_frame->selection()->isInPasswordField(); - - // Invalidate clipboard here against anymore pasteboard writing for security. The drag - // image can still be changed as we drag, but not the pasteboard data. - dragState().m_dragClipboard->setAccessPolicy(ClipboardImageWritable); - - if (m_mouseDownMayStartDrag) { - // gather values from DHTML element, if it set any - dragState().m_dragClipboard->sourceOperation(srcOp); - - // Yuck, dragSourceMovedTo() can be called as a result of kicking off the drag with - // dragImage! Because of that dumb reentrancy, we may think we've not started the - // drag when that happens. So we have to assume it's started before we kick it off. - dragState().m_dragClipboard->setDragHasStarted(); - } - } - - if (m_mouseDownMayStartDrag) { - DragController* dragController = m_frame->page() ? m_frame->page()->dragController() : 0; - bool startedDrag = dragController && dragController->startDrag(m_frame, dragState().m_dragClipboard.get(), srcOp, event.event(), m_mouseDownPos, dragState().m_dragSrcIsDHTML); - if (!startedDrag && dragState().m_dragSrcMayBeDHTML) { - // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event - dispatchDragSrcEvent(dragendEvent, event.event()); - m_mouseDownMayStartDrag = false; - } - } - -cleanupDrag: - if (!m_mouseDownMayStartDrag) { - // something failed to start the drag, cleanup - freeClipboard(); - dragState().m_dragSrc = 0; - } - - // No more default handling (like selection), whether we're past the hysteresis bounds or not - return true; -} - -bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, - bool isLineBreak, bool isBackTab) -{ - if (!m_frame) - return false; -#ifndef NDEBUG - // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline), - // and avoid dispatching text input events from keydown default handlers. - if (underlyingEvent && underlyingEvent->isKeyboardEvent()) - ASSERT(static_cast<KeyboardEvent*>(underlyingEvent)->type() == keypressEvent); -#endif - EventTarget* target; - if (underlyingEvent) - target = underlyingEvent->target(); - else - target = eventTargetNodeForDocument(m_frame->document()); - if (!target) - return false; - RefPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text); - event->setUnderlyingEvent(underlyingEvent); - event->setIsLineBreak(isLineBreak); - event->setIsBackTab(isBackTab); - ExceptionCode ec; - return target->dispatchEvent(event.release(), ec, true); -} - - -#if !PLATFORM(MAC) && !PLATFORM(QT) -bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent*) const -{ - return false; -} -#endif - -bool EventHandler::tabsToLinks(KeyboardEvent* event) const -{ - Page* page = m_frame->page(); - if (!page) - return false; - - if (page->chrome()->client()->tabsToLinks()) - return !invertSenseOfTabsToLinks(event); - - return invertSenseOfTabsToLinks(event); -} - -void EventHandler::defaultTextInputEventHandler(TextEvent* event) -{ - String data = event->data(); - if (data == "\n") { - if (event->isLineBreak()) { - if (m_frame->editor()->insertLineBreak()) - event->setDefaultHandled(); - } else { - if (m_frame->editor()->insertParagraphSeparator()) - event->setDefaultHandled(); - } - } else { - if (m_frame->editor()->insertTextWithoutSendingTextEvent(data, false, event)) - event->setDefaultHandled(); - } -} - -void EventHandler::defaultTabEventHandler(KeyboardEvent* event) -{ - // We should only advance focus on tabs if no special modifier keys are held down. - if (event->ctrlKey() || event->metaKey() || event->altGraphKey()) - return; - - Page* page = m_frame->page(); - if (!page) - return; - if (!page->tabKeyCyclesThroughElements()) - return; - - FocusDirection focusDirection = event->shiftKey() ? FocusDirectionBackward : FocusDirectionForward; - - // Tabs can be used in design mode editing. - if (m_frame->document()->inDesignMode()) - return; - - if (page->focusController()->advanceFocus(focusDirection, event)) - event->setDefaultHandled(); -} - -void EventHandler::capsLockStateMayHaveChanged() -{ - if (Document* d = m_frame->document()) - if (Node* node = d->focusedNode()) - if (RenderObject* r = node->renderer()) - r->capsLockStateMayHaveChanged(); -} - -unsigned EventHandler::pendingFrameUnloadEventCount() -{ - return m_pendingFrameUnloadEventCount; -} - -void EventHandler::addPendingFrameUnloadEventCount() -{ - m_pendingFrameUnloadEventCount += 1; - m_frame->page()->changePendingUnloadEventCount(1); - return; -} - -void EventHandler::removePendingFrameUnloadEventCount() -{ - ASSERT( (-1 + (int)m_pendingFrameUnloadEventCount) >= 0 ); - m_pendingFrameUnloadEventCount -= 1; - m_frame->page()->changePendingUnloadEventCount(-1); - return; -} - -void EventHandler::clearPendingFrameUnloadEventCount() -{ - m_frame->page()->changePendingUnloadEventCount(-((int)m_pendingFrameUnloadEventCount)); - m_pendingFrameUnloadEventCount = 0; - return; -} - -unsigned EventHandler::pendingFrameBeforeUnloadEventCount() -{ - return m_pendingFrameBeforeUnloadEventCount; -} - -void EventHandler::addPendingFrameBeforeUnloadEventCount() -{ - m_pendingFrameBeforeUnloadEventCount += 1; - m_frame->page()->changePendingBeforeUnloadEventCount(1); - return; -} - -void EventHandler::removePendingFrameBeforeUnloadEventCount() -{ - ASSERT( (-1 + (int)m_pendingFrameBeforeUnloadEventCount) >= 0 ); - m_pendingFrameBeforeUnloadEventCount -= 1; - m_frame->page()->changePendingBeforeUnloadEventCount(-1); - return; -} - - void EventHandler::clearPendingFrameBeforeUnloadEventCount() -{ - m_frame->page()->changePendingBeforeUnloadEventCount(-((int)m_pendingFrameBeforeUnloadEventCount)); - m_pendingFrameBeforeUnloadEventCount = 0; - return; -} -} diff --git a/webkit/pending/FileSystem.h b/webkit/pending/FileSystem.h deleted file mode 100644 index 1e7edf1..0000000 --- a/webkit/pending/FileSystem.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2008 Collabora, Ltd. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FileSystem_h -#define FileSystem_h - -#if PLATFORM(GTK) -#include <gmodule.h> -#endif -#if PLATFORM(QT) -#include <QFile> -#include <QLibrary> -#if defined(Q_OS_WIN32) -#include <windows.h> -#endif -#endif - -#include <time.h> - -#include <wtf/Platform.h> -#include <wtf/Vector.h> - -#include "PlatformString.h" - -typedef const struct __CFData* CFDataRef; - -#if PLATFORM(WIN) -// These are to avoid including <winbase.h> in a header for Chromium -typedef void *HANDLE; -// Assuming STRICT -typedef struct HINSTANCE__* HINSTANCE; -typedef HINSTANCE HMODULE; -#endif - -namespace WebCore { - -class CString; - -#if PLATFORM(WIN) -typedef HANDLE PlatformFileHandle; -typedef HMODULE PlatformModule; -// HACK: -1 is INVALID_HANDLE_VALUE, defined in <winbase.h>. Chromium tries to -// avoid using Windows headers in headers. We'd rather move this into the .cpp. -const PlatformFileHandle invalidPlatformFileHandle = (HANDLE)-1; - -struct PlatformModuleVersion { - unsigned leastSig; - unsigned mostSig; - - PlatformModuleVersion(unsigned) - : leastSig(0) - , mostSig(0) - { - } - - PlatformModuleVersion(unsigned lsb, unsigned msb) - : leastSig(lsb) - , mostSig(msb) - { - } - -}; -#elif PLATFORM(QT) - -typedef QFile* PlatformFileHandle; -const PlatformFileHandle invalidPlatformFileHandle = 0; -#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS) -typedef QLibrary* PlatformModule; -typedef unsigned PlatformModuleVersion; -#elif defined(Q_OS_WIN32) -typedef HMODULE PlatformModule; -struct PlatformModuleVersion { - unsigned leastSig; - unsigned mostSig; - - PlatformModuleVersion(unsigned) - : leastSig(0) - , mostSig(0) - { - } - - PlatformModuleVersion(unsigned lsb, unsigned msb) - : leastSig(lsb) - , mostSig(msb) - { - } - -}; -#endif - -#else -typedef int PlatformFileHandle; -#if PLATFORM(GTK) -typedef GModule* PlatformModule; -#else -typedef void* PlatformModule; -#endif -const PlatformFileHandle invalidPlatformFileHandle = -1; - -typedef unsigned PlatformModuleVersion; -#endif - -bool fileExists(const String&); -bool deleteFile(const String&); -bool deleteEmptyDirectory(const String&); -bool getFileSize(const String&, long long& result); -bool getFileModificationTime(const String&, time_t& result); -String pathByAppendingComponent(const String& path, const String& component); -bool makeAllDirectories(const String& path); -String homeDirectoryPath(); -String pathGetFileName(const String&); -String directoryName(const String&); - -Vector<String> listDirectory(const String& path, const String& filter = String()); - -CString fileSystemRepresentation(const String&); - -inline bool isHandleValid(const PlatformFileHandle& handle) { return handle != invalidPlatformFileHandle; } - -// Prefix is what the filename should be prefixed with, not the full path. -CString openTemporaryFile(const char* prefix, PlatformFileHandle&); -void closeFile(PlatformFileHandle&); -int writeToFile(PlatformFileHandle, const char* data, int length); - -// Methods for dealing with loadable modules -bool unloadModule(PlatformModule); - -#if PLATFORM(WIN) -String localUserSpecificStorageDirectory(); -String roamingUserSpecificStorageDirectory(); - -bool safeCreateFile(const String&, CFDataRef); -#endif - -} // namespace WebCore - -#endif // FileSystem_h diff --git a/webkit/pending/FileSystemWin.cpp b/webkit/pending/FileSystemWin.cpp deleted file mode 100644 index d14babb..0000000 --- a/webkit/pending/FileSystemWin.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2008 Collabora, Ltd. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include <windows.h> -#include "FileSystem.h" - -#include "CString.h" -#include "NotImplemented.h" -#include "PlatformString.h" - -#include <shlwapi.h> - -namespace WebCore { - -// Don't include any of the file system code, since the renderer can't do -// file system operations from sandbox. -// These methods are hot referenced, so no definition is needed. - -String pathGetFileName(const String& path) -{ - return String(::PathFindFileName(String(path).charactersWithNullTermination())); -} - -String directoryName(const String& path) -{ - notImplemented(); - return String(); -} - -// Used by Page::userStyleSheet(). -// The custom user stylesheets should be implemented more generically, in -// order to support other protocols, like http: and data: -bool getFileModificationTime(const String& /*path*/, time_t& /*result*/) -{ - notImplemented(); - return false; -} - -bool fileExists(const String& path) -{ - notImplemented(); - return false; -} - -bool getFileSize(const String&, long long& result) -{ - notImplemented(); - return false; -} - -// delteFile() and deleteEmptyDirectory() are used by -// FormData::removeGeneratedFilesIfNeeded() for uploading bundles: -// http://trac.webkit.org/changeset/32666 -// This approach will need refactoring to isolate file system operations -// between browser/renderer - -bool deleteFile(const String& /*path*/) -{ - notImplemented(); - return false; -} - -bool deleteEmptyDirectory(const String& /*path*/) -{ - notImplemented(); - return false; -} - -bool unloadModule(PlatformModule module) -{ - notImplemented(); - return false; -} - -} // namespace WebCore diff --git a/webkit/pending/Font.cpp b/webkit/pending/Font.cpp deleted file mode 100644 index eafc11a..0000000 --- a/webkit/pending/Font.cpp +++ /dev/null @@ -1,839 +0,0 @@ -/** - * This file is part of the html renderer for KDE. - * - * Copyright (C) 1999 Lars Knoll (knoll@kde.org) - * (C) 1999 Antti Koivisto (koivisto@kde.org) - * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2003, 2006 Apple Computer, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" -#include "Font.h" - -#include "CharacterNames.h" -#include "FloatRect.h" -#include "FontCache.h" -#include "FontFallbackList.h" -#include "IntPoint.h" -#include "GlyphBuffer.h" -#include <wtf/unicode/Unicode.h> -#include <wtf/MathExtras.h> - -#if USE(ICU_UNICODE) -#include <unicode/unorm.h> -#endif - -using namespace WTF; -using namespace Unicode; - -namespace WebCore { - -// According to http://www.unicode.org/Public/UNIDATA/UCD.html#Canonical_Combining_Class_Values -const uint8_t hiraganaKatakanaVoicingMarksCombiningClass = 8; - -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 /*?*/, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1 /*no-break space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -Font::CodePath Font::codePath = Auto; - -struct WidthIterator { - WidthIterator(const Font* font, const TextRun& run); - - void advance(int to, GlyphBuffer* glyphBuffer = 0); - bool advanceOneCharacter(float& width, GlyphBuffer* glyphBuffer = 0); - - const Font* m_font; - - const TextRun& m_run; - int m_end; - - unsigned m_currentCharacter; - float m_runWidthSoFar; - float m_padding; - float m_padPerSpace; - float m_finalRoundingWidth; - -private: - UChar32 normalizeVoicingMarks(int currentCharacter); -}; - -WidthIterator::WidthIterator(const Font* font, const TextRun& run) - : m_font(font) - , m_run(run) - , m_end(run.length()) - , m_currentCharacter(0) - , m_runWidthSoFar(0) - , m_finalRoundingWidth(0) -{ - // If the padding is non-zero, count the number of spaces in the run - // and divide that by the padding for per space addition. - m_padding = m_run.padding(); - if (!m_padding) - m_padPerSpace = 0; - else { - float numSpaces = 0; - for (int i = 0; i < run.length(); i++) - if (Font::treatAsSpace(m_run[i])) - numSpaces++; - - if (numSpaces == 0) - m_padPerSpace = 0; - else - m_padPerSpace = ceilf(m_run.padding() / numSpaces); - } -} - -void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer) -{ - if (offset > m_end) - offset = m_end; - - int currentCharacter = m_currentCharacter; - const UChar* cp = m_run.data(currentCharacter); - - bool rtl = m_run.rtl(); - bool hasExtraSpacing = m_font->letterSpacing() || m_font->wordSpacing() || m_padding; - - float runWidthSoFar = m_runWidthSoFar; - float lastRoundingWidth = m_finalRoundingWidth; - - while (currentCharacter < offset) { - UChar32 c = *cp; - unsigned clusterLength = 1; - if (c >= 0x3041) { - if (c <= 0x30FE) { - // Deal with Hiragana and Katakana voiced and semi-voiced syllables. - // Normalize into composed form, and then look for glyph with base + combined mark. - // Check above for character range to minimize performance impact. - UChar32 normalized = normalizeVoicingMarks(currentCharacter); - if (normalized) { - c = normalized; - clusterLength = 2; - } - } else if (U16_IS_SURROGATE(c)) { - if (!U16_IS_SURROGATE_LEAD(c)) - break; - - // Do we have a surrogate pair? If so, determine the full Unicode (32 bit) - // code point before glyph lookup. - // Make sure we have another character and it's a low surrogate. - if (currentCharacter + 1 >= m_run.length()) - break; - UChar low = cp[1]; - if (!U16_IS_TRAIL(low)) - break; - c = U16_GET_SUPPLEMENTARY(c, low); - clusterLength = 2; - } - } - - const GlyphData& glyphData = m_font->glyphDataForCharacter(c, rtl); - Glyph glyph = glyphData.glyph; - const SimpleFontData* fontData = glyphData.fontData; - - ASSERT(fontData); - - // Now that we have a glyph and font data, get its width. - float width; - if (c == '\t' && m_run.allowTabs()) { - float tabWidth = m_font->tabWidth(); - width = tabWidth - fmodf(m_run.xPos() + runWidthSoFar, tabWidth); - } else { - width = fontData->widthForGlyph(glyph); - // We special case spaces in two ways when applying word rounding. - // First, we round spaces to an adjusted width in all fonts. - // Second, in fixed-pitch fonts we ensure that all characters that - // match the width of the space character have the same width as the space character. - if (width == fontData->m_spaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) && m_run.applyWordRounding()) - width = fontData->m_adjustedSpaceWidth; - } - - if (hasExtraSpacing && !m_run.spacingDisabled()) { - // Account for letter-spacing. - if (width && m_font->letterSpacing()) - width += m_font->letterSpacing(); - - if (Font::treatAsSpace(c)) { - // Account for padding. WebCore uses space padding to justify text. - // We distribute the specified padding over the available spaces in the run. - if (m_padding) { - // Use left over padding if not evenly divisible by number of spaces. - if (m_padding < m_padPerSpace) { - width += m_padding; - m_padding = 0; - } else { - width += m_padPerSpace; - m_padding -= m_padPerSpace; - } - } - - // Account for word spacing. - // We apply additional space between "words" by adding width to the space character. - if (currentCharacter != 0 && !Font::treatAsSpace(cp[-1]) && m_font->wordSpacing()) - width += m_font->wordSpacing(); - } - } - - // Advance past the character we just dealt with. - cp += clusterLength; - currentCharacter += clusterLength; - - // Account for float/integer impedance mismatch between CG and KHTML. "Words" (characters - // followed by a character defined by isRoundingHackCharacter()) are always an integer width. - // We adjust the width of the last character of a "word" to ensure an integer width. - // If we move KHTML to floats we can remove this (and related) hacks. - - float oldWidth = width; - - // Force characters that are used to determine word boundaries for the rounding hack - // to be integer width, so following words will start on an integer boundary. - if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(c)) - width = ceilf(width); - - // Check to see if the next character is a "rounding hack character", if so, adjust - // width so that the total run width will be on an integer boundary. - if ((m_run.applyWordRounding() && currentCharacter < m_run.length() && Font::isRoundingHackCharacter(*cp)) - || (m_run.applyRunRounding() && currentCharacter >= m_end)) { - float totalWidth = runWidthSoFar + width; - width += ceilf(totalWidth) - totalWidth; - } - - runWidthSoFar += width; - - if (glyphBuffer) - glyphBuffer->add(glyph, fontData, (rtl ? oldWidth + lastRoundingWidth : width)); - - lastRoundingWidth = width - oldWidth; - } - - m_currentCharacter = currentCharacter; - m_runWidthSoFar = runWidthSoFar; - m_finalRoundingWidth = lastRoundingWidth; -} - -bool WidthIterator::advanceOneCharacter(float& width, GlyphBuffer* glyphBuffer) -{ - glyphBuffer->clear(); - advance(m_currentCharacter + 1, glyphBuffer); - float w = 0; - for (int i = 0; i < glyphBuffer->size(); ++i) - w += glyphBuffer->advanceAt(i); - width = w; - return !glyphBuffer->isEmpty(); -} - -UChar32 WidthIterator::normalizeVoicingMarks(int currentCharacter) -{ - if (currentCharacter + 1 < m_end) { - if (combiningClass(m_run[currentCharacter + 1]) == hiraganaKatakanaVoicingMarksCombiningClass) { -#if USE(ICU_UNICODE) - // Normalize into composed form using 3.2 rules. - UChar normalizedCharacters[2] = { 0, 0 }; - UErrorCode uStatus = U_ZERO_ERROR; - int32_t resultLength = unorm_normalize(m_run.data(currentCharacter), 2, - UNORM_NFC, UNORM_UNICODE_3_2, &normalizedCharacters[0], 2, &uStatus); - if (resultLength == 1 && uStatus == 0) - return normalizedCharacters[0]; -#elif USE(QT4_UNICODE) - QString tmp(reinterpret_cast<const QChar*>(m_run.data(currentCharacter)), 2); - QString res = tmp.normalized(QString::NormalizationForm_C, QChar::Unicode_3_2); - if (res.length() == 1) - return res.at(0).unicode(); -#endif - } - } - return 0; -} - -// ============================================================================================ -// Font Implementation (Cross-Platform Portion) -// ============================================================================================ - -Font::Font() - : m_pageZero(0) - , m_cachedPrimaryFont(0) - , m_letterSpacing(0) - , m_wordSpacing(0) - , m_isPlatformFont(false) -{ -} - -Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing) - : m_fontDescription(fd) - , m_pageZero(0) - , m_cachedPrimaryFont(0) - , m_letterSpacing(letterSpacing) - , m_wordSpacing(wordSpacing) - , m_isPlatformFont(false) -{ -} - -Font::Font(const FontPlatformData& fontData, bool isPrinterFont) - : m_fontList(FontFallbackList::create()) - , m_pageZero(0) - , m_cachedPrimaryFont(0) - , m_letterSpacing(0) - , m_wordSpacing(0) - , m_isPlatformFont(true) -{ - m_fontDescription.setUsePrinterFont(isPrinterFont); - m_fontList->setPlatformFont(fontData); -} - -Font::Font(const Font& other) - : m_fontDescription(other.m_fontDescription) - , m_fontList(other.m_fontList) - , m_pages(other.m_pages) - , m_pageZero(other.m_pageZero) - , m_cachedPrimaryFont(other.m_cachedPrimaryFont) - , m_letterSpacing(other.m_letterSpacing) - , m_wordSpacing(other.m_wordSpacing) - , m_isPlatformFont(other.m_isPlatformFont) -{ -} - -Font& Font::operator=(const Font& other) -{ - m_fontDescription = other.m_fontDescription; - m_fontList = other.m_fontList; - m_pages = other.m_pages; - m_pageZero = other.m_pageZero; - m_cachedPrimaryFont = other.m_cachedPrimaryFont; - m_letterSpacing = other.m_letterSpacing; - m_wordSpacing = other.m_wordSpacing; - m_isPlatformFont = other.m_isPlatformFont; - return *this; -} - -Font::~Font() -{ -} - -bool Font::operator==(const Font& other) const -{ - // Our FontData don't have to be checked, since checking the font description will be fine. - // FIXME: This does not work if the font was made with the FontPlatformData constructor. - if ((m_fontList && m_fontList->loadingCustomFonts()) || - (other.m_fontList && other.m_fontList->loadingCustomFonts())) - return false; - - FontSelector* first = m_fontList ? m_fontList->fontSelector() : 0; - FontSelector* second = other.m_fontList ? other.m_fontList->fontSelector() : 0; - - return first == second - && m_fontDescription == other.m_fontDescription - && m_letterSpacing == other.m_letterSpacing - && m_wordSpacing == other.m_wordSpacing - && (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); - ASSERT(!m_cachedPrimaryFont); - m_cachedPrimaryFont = m_fontList->primaryFont(this)->fontDataForCharacter(' '); -} - -const FontData* Font::fontDataAt(unsigned index) const -{ - ASSERT(m_fontList); - return m_fontList->fontDataAt(this, index); -} - -const FontData* Font::fontDataForCharacters(const UChar* characters, int length) const -{ - ASSERT(m_fontList); - return m_fontList->fontDataForCharacters(this, characters, length); -} - -void Font::update(PassRefPtr<FontSelector> fontSelector) const -{ - // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up - // being reasonably safe (because inherited fonts in the render tree pick up the new - // style anyway. Other copies are transient, e.g., the state in the GraphicsContext, and - // won't stick around long enough to get you in trouble). Still, this is pretty disgusting, - // and could eventually be rectified by using RefPtrs for Fonts themselves. - if (!m_fontList) - m_fontList = FontFallbackList::create(); - m_fontList->invalidate(fontSelector); - m_cachedPrimaryFont = 0; - m_pageZero = 0; - 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) -{ - codePath = p; -} - -bool Font::canUseGlyphCache(const TextRun& run) const -{ - switch (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. - if (m_fontList && m_fontList->loadingCustomFonts()) - return; - - to = (to == -1 ? run.length() : to); - -#if ENABLE(SVG_FONTS) - if (primaryFont()->isSVGFont()) { - drawTextUsingSVGFont(context, run, point, from, to); - return; - } -#endif - - if (canUseGlyphCache(run)) - drawSimpleText(context, run, point, from, to); - else - drawComplexText(context, run, point, from, to); -} - -float Font::floatWidth(const TextRun& run) const -{ -#if ENABLE(SVG_FONTS) - if (primaryFont()->isSVGFont()) - return floatWidthUsingSVGFont(run); -#endif - - if (canUseGlyphCache(run)) - return floatWidthForSimpleText(run, 0); - return floatWidthForComplexText(run); -} - -float Font::floatWidth(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const -{ -#if ENABLE(SVG_FONTS) - if (primaryFont()->isSVGFont()) - return floatWidthUsingSVGFont(run, extraCharsAvailable, charsConsumed, glyphName); -#endif - - charsConsumed = run.length(); - glyphName = ""; - if (canUseGlyphCache(run)) - return floatWidthForSimpleText(run, 0); - return floatWidthForComplexText(run); -} - -float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer) const -{ - WidthIterator it(this, run); - it.advance(run.length(), glyphBuffer); - return it.m_runWidthSoFar; -} - -FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& point, int h, int from, int to) const -{ -#if ENABLE(SVG_FONTS) - if (primaryFont()->isSVGFont()) - return selectionRectForTextUsingSVGFont(run, point, h, from, to); -#endif - - to = (to == -1 ? run.length() : to); - if (canUseGlyphCache(run)) - return selectionRectForSimpleText(run, point, h, from, to); - return selectionRectForComplexText(run, point, h, from, to); -} - -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::offsetForPosition(const TextRun& run, int x, bool includePartialGlyphs) const -{ -#if ENABLE(SVG_FONTS) - if (primaryFont()->isSVGFont()) - return offsetForPositionForTextUsingSVGFont(run, x, includePartialGlyphs); -#endif - - 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; - } - } - } - - return offset; -} - -#if ENABLE(SVG_FONTS) -bool Font::isSVGFont() const -{ - return primaryFont()->isSVGFont(); -} -#endif - -FontSelector* Font::fontSelector() const -{ - return m_fontList ? m_fontList->fontSelector() : 0; -} - -} diff --git a/webkit/pending/FontCache.cpp b/webkit/pending/FontCache.cpp deleted file mode 100644 index 6ef1b63..0000000 --- a/webkit/pending/FontCache.cpp +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "FontCache.h" - -#include "Font.h" -#include "FontFallbackList.h" -#include "FontPlatformData.h" -#include "FontSelector.h" -#include "StringHash.h" -#include <wtf/HashMap.h> -#include <wtf/ListHashSet.h> - -using namespace WTF; - -namespace WebCore { - -struct FontPlatformDataCacheKey { - FontPlatformDataCacheKey(const AtomicString& family = AtomicString(), unsigned size = 0, unsigned weight = 0, bool italic = false, - bool isPrinterFont = false, FontRenderingMode renderingMode = NormalRenderingMode) - : m_family(family) - , m_size(size) - , m_weight(weight) - , m_italic(italic) - , m_printerFont(isPrinterFont) - , m_renderingMode(renderingMode) - { - } - - FontPlatformDataCacheKey(HashTableDeletedValueType) : m_size(hashTableDeletedSize()) { } - bool isHashTableDeletedValue() const { return m_size == hashTableDeletedSize(); } - - bool operator==(const FontPlatformDataCacheKey& other) const - { - return equalIgnoringCase(m_family, other.m_family) && m_size == other.m_size && - m_weight == other.m_weight && m_italic == other.m_italic && m_printerFont == other.m_printerFont && - m_renderingMode == other.m_renderingMode; - } - - AtomicString m_family; - unsigned m_size; - unsigned m_weight; - bool m_italic; - bool m_printerFont; - FontRenderingMode m_renderingMode; - -private: - static unsigned hashTableDeletedSize() { return 0xFFFFFFFFU; } -}; - -inline unsigned computeHash(const FontPlatformDataCacheKey& fontKey) -{ - unsigned hashCodes[4] = { - CaseFoldingHash::hash(fontKey.m_family), - fontKey.m_size, - fontKey.m_weight, - static_cast<unsigned>(fontKey.m_italic) << 2 | static_cast<unsigned>(fontKey.m_printerFont) << 1 | static_cast<unsigned>(fontKey.m_renderingMode) - }; - return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar)); -} - -struct FontPlatformDataCacheKeyHash { - static unsigned hash(const FontPlatformDataCacheKey& font) - { - return computeHash(font); - } - - static bool equal(const FontPlatformDataCacheKey& a, const FontPlatformDataCacheKey& b) - { - return a == b; - } - - static const bool safeToCompareToEmptyOrDeleted = true; -}; - -struct FontPlatformDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformDataCacheKey> { - static const bool emptyValueIsZero = true; - static const FontPlatformDataCacheKey& emptyValue() - { - static FontPlatformDataCacheKey key(nullAtom); - return key; - } - static void constructDeletedValue(FontPlatformDataCacheKey& slot) - { - new (&slot) FontPlatformDataCacheKey(HashTableDeletedValue); - } - static bool isDeletedValue(const FontPlatformDataCacheKey& value) - { - return value.isHashTableDeletedValue(); - } -}; - -typedef HashMap<FontPlatformDataCacheKey, FontPlatformData*, FontPlatformDataCacheKeyHash, FontPlatformDataCacheKeyTraits> FontPlatformDataCache; - -static FontPlatformDataCache* gFontPlatformDataCache = 0; - -FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& fontDescription, - const AtomicString& familyName, - bool checkingAlternateName) -{ - if (!gFontPlatformDataCache) { - gFontPlatformDataCache = new FontPlatformDataCache; - platformInit(); - } - - FontPlatformDataCacheKey key(familyName, fontDescription.computedPixelSize(), fontDescription.weight(), fontDescription.italic(), - fontDescription.usePrinterFont(), fontDescription.renderingMode()); - FontPlatformData* result = 0; - bool foundResult; - FontPlatformDataCache::iterator it = gFontPlatformDataCache->find(key); - if (it == gFontPlatformDataCache->end()) { - result = createFontPlatformData(fontDescription, familyName); - gFontPlatformDataCache->set(key, result); - foundResult = result; - } else { - result = it->second; - foundResult = true; - } - - if (!foundResult && !checkingAlternateName) { - // We were unable to find a font. We have a small set of fonts that we alias to other names, - // e.g., Arial/Helvetica, Courier/Courier New, etc. Try looking up the font under the aliased name. - const AtomicString& alternateName = alternateFamilyName(familyName); - if (!alternateName.isEmpty()) - result = getCachedFontPlatformData(fontDescription, alternateName, true); - if (result) - gFontPlatformDataCache->set(key, new FontPlatformData(*result)); // Cache the result under the old name. - } - - return result; -} - -struct FontDataCacheKeyHash { - static unsigned hash(const FontPlatformData& platformData) - { - return platformData.hash(); - } - - static bool equal(const FontPlatformData& a, const FontPlatformData& b) - { - return a == b; - } - - static const bool safeToCompareToEmptyOrDeleted = true; -}; - -struct FontDataCacheKeyTraits : WTF::GenericHashTraits<FontPlatformData> { - static const bool emptyValueIsZero = true; - static const bool needsDestruction = true; - static const FontPlatformData& emptyValue() - { - static FontPlatformData key; - return key; - } - static void constructDeletedValue(FontPlatformData& slot) - { - new (&slot) FontPlatformData(HashTableDeletedValue); - } - static bool isDeletedValue(const FontPlatformData& value) - { - return value.isHashTableDeletedValue(); - } -}; - -typedef HashMap<FontPlatformData, pair<SimpleFontData*, unsigned>, FontDataCacheKeyHash, FontDataCacheKeyTraits> FontDataCache; - -static FontDataCache* gFontDataCache = 0; - -const int cMaxInactiveFontData = 120; // Pretty Low Threshold -const float cTargetInactiveFontData = 100; -static ListHashSet<const SimpleFontData*>* gInactiveFontData = 0; - -SimpleFontData* FontCache::getCachedFontData(const FontPlatformData* platformData) -{ - if (!platformData) - return 0; - - if (!gFontDataCache) { - gFontDataCache = new FontDataCache; - gInactiveFontData = new ListHashSet<const SimpleFontData*>; - } - - FontDataCache::iterator result = gFontDataCache->find(*platformData); - if (result == gFontDataCache->end()) { - pair<SimpleFontData*, unsigned> newValue(new SimpleFontData(*platformData), 1); - gFontDataCache->set(*platformData, newValue); - return newValue.first; - } - if (!result.get()->second.second++) { - ASSERT(gInactiveFontData->contains(result.get()->second.first)); - gInactiveFontData->remove(result.get()->second.first); - } - - return result.get()->second.first; -} - -void FontCache::releaseFontData(const SimpleFontData* fontData) -{ - ASSERT(gFontDataCache); - ASSERT(!fontData->isCustomFont()); - - FontDataCache::iterator it = gFontDataCache->find(fontData->platformData()); - ASSERT(it != gFontDataCache->end()); - - if (!--it->second.second) { - gInactiveFontData->add(fontData); - if (gInactiveFontData->size() > cMaxInactiveFontData) - purgeInactiveFontData(gInactiveFontData->size() - cTargetInactiveFontData); - } -} - -void FontCache::purgeInactiveFontData(int count) -{ - if (!gInactiveFontData) - return; - - static bool isPurging; // Guard against reentry when e.g. a deleted FontData releases its small caps FontData. - if (isPurging) - return; - - isPurging = true; - - ListHashSet<const SimpleFontData*>::iterator end = gInactiveFontData->end(); - ListHashSet<const SimpleFontData*>::iterator it = gInactiveFontData->begin(); - for (int i = 0; i < count && it != end; ++it, ++i) { - const SimpleFontData* fontData = *it.get(); - gFontDataCache->remove(fontData->platformData()); - delete fontData; - } - - if (it == end) { - // Removed everything - gInactiveFontData->clear(); - } else { - for (int i = 0; i < count; ++i) - gInactiveFontData->remove(gInactiveFontData->begin()); - } - - Vector<FontPlatformDataCacheKey> keysToRemove; - keysToRemove.reserveCapacity(gFontPlatformDataCache->size()); - FontPlatformDataCache::iterator platformDataEnd = gFontPlatformDataCache->end(); - for (FontPlatformDataCache::iterator platformData = gFontPlatformDataCache->begin(); platformData != platformDataEnd; ++platformData) { - if (platformData->second && !gFontDataCache->contains(*platformData->second)) - keysToRemove.append(platformData->first); - } - - size_t keysToRemoveCount = keysToRemove.size(); - for (size_t i = 0; i < keysToRemoveCount; ++i) - delete gFontPlatformDataCache->take(keysToRemove[i]); - - isPurging = false; -} - -size_t FontCache::fontDataCount() -{ - if (gFontDataCache) - return gFontDataCache->size(); - return 0; -} - -size_t FontCache::inactiveFontDataCount() -{ - if (gInactiveFontData) - return gInactiveFontData->size(); - return 0; -} - -const FontData* FontCache::getFontData(const Font& font, int& familyIndex, FontSelector* fontSelector) -{ - FontPlatformData* result = 0; - - int startIndex = familyIndex; - const FontFamily* startFamily = &font.fontDescription().family(); - for (int i = 0; startFamily && i < startIndex; i++) - startFamily = startFamily->next(); - const FontFamily* currFamily = startFamily; - while (currFamily && !result) { - familyIndex++; - if (currFamily->family().length()) { - if (fontSelector) { - FontData* data = fontSelector->getFontData(font.fontDescription(), currFamily->family()); - if (data) - return data; - } - result = getCachedFontPlatformData(font.fontDescription(), currFamily->family()); - } - currFamily = currFamily->next(); - } - - if (!currFamily) - familyIndex = cAllFamiliesScanned; - - if (!result) - // We didn't find a font. Try to find a similar font using our own specific knowledge about our platform. - // For example on OS X, we know to map any families containing the words Arabic, Pashto, or Urdu to the - // Geeza Pro font. - result = getSimilarFontPlatformData(font); - - if (!result && startIndex == 0) { - // If it's the primary font that we couldn't find, we try the following. In all other cases, we will - // just use per-character system fallback. - - if (fontSelector) { - // Try the user's preferred standard font. - if (FontData* data = fontSelector->getFontData(font.fontDescription(), "-webkit-standard")) - return data; - } - - // Still no result. Hand back our last resort fallback font. - result = getLastResortFallbackFont(font.fontDescription()); - } - - // Now that we have a result, we need to go from FontPlatformData -> FontData. - return getCachedFontData(result); -} - -static HashSet<FontSelector*>* gClients; - -void FontCache::addClient(FontSelector* client) -{ - if (!gClients) - gClients = new HashSet<FontSelector*>; - - ASSERT(!gClients->contains(client)); - gClients->add(client); -} - -void FontCache::removeClient(FontSelector* client) -{ - ASSERT(gClients); - ASSERT(gClients->contains(client)); - - gClients->remove(client); -} - -static unsigned gGeneration = 0; - -unsigned FontCache::generation() -{ - return gGeneration; -} - -void FontCache::invalidate() -{ - if (!gClients) { - ASSERT(!gFontPlatformDataCache); - return; - } - - if (gFontPlatformDataCache) { - deleteAllValues(*gFontPlatformDataCache); - delete gFontPlatformDataCache; - gFontPlatformDataCache = new FontPlatformDataCache; - } - - gGeneration++; - - Vector<RefPtr<FontSelector> > clients; - size_t numClients = gClients->size(); - clients.reserveCapacity(numClients); - HashSet<FontSelector*>::iterator end = gClients->end(); - for (HashSet<FontSelector*>::iterator it = gClients->begin(); it != end; ++it) - clients.append(*it); - - ASSERT(numClients == clients.size()); - for (size_t i = 0; i < numClients; ++i) - clients[i]->fontCacheInvalidated(); - - purgeInactiveFontData(); -} - -} // namespace WebCore diff --git a/webkit/pending/FontCache.h b/webkit/pending/FontCache.h deleted file mode 100644 index 9c588aa..0000000 --- a/webkit/pending/FontCache.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2006, 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. - * 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 FontCache_h -#define FontCache_h - -#include <limits.h> -#include <wtf/Vector.h> -#include <unicode/uscript.h> -#include <wtf/unicode/Unicode.h> - -#if PLATFORM(WIN) -#include <objidl.h> -#include <mlang.h> -#endif - -namespace WebCore -{ - -class AtomicString; -class Font; -class FontPlatformData; -class FontData; -class FontDescription; -class FontSelector; -class SimpleFontData; - -class FontCache { -public: - static const FontData* getFontData(const Font&, int& familyIndex, FontSelector*); - static 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); - - // Also implemented by the platform. - static void platformInit(); - -#if PLATFORM(WIN) - static IMLangFontLink2* getFontLinkInterface(); -#endif - - static 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&); - - bool fontExists(const FontDescription&, const AtomicString& family); - - // TODO(jungshik): Is this the best place to put this function? It may - // or may not be. Font.h is another place we can cosider. - // Return a font family for |script| and |FontDescription.genericFamily()|. - // It will return an empty atom if we can't find a font matching - // script and genericFamily in FontDescription. A caller should check - // the emptyness before using it. - static AtomicString getGenericFontForScript(UScriptCode script, const FontDescription&); - static void addClient(FontSelector*); - static void removeClient(FontSelector*); - - static unsigned generation(); - static void invalidate(); - - static size_t fontDataCount(); - static size_t inactiveFontDataCount(); - static void purgeInactiveFontData(int count = INT_MAX); - -private: - // These methods are implemented by each platform. - static FontPlatformData* getSimilarFontPlatformData(const Font&); - static FontPlatformData* createFontPlatformData(const FontDescription&, const AtomicString& family); - static const AtomicString& alternateFamilyName(const AtomicString& family); - - friend class SimpleFontData; - friend class FontFallbackList; -}; - -} - -#endif diff --git a/webkit/pending/FontDescription.h b/webkit/pending/FontDescription.h deleted file mode 100644 index fa95928..0000000 --- a/webkit/pending/FontDescription.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.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.LIother.m_ If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USm_ - * - */ - -#ifndef FontDescription_h -#define FontDescription_h - -#include "FontFamily.h" -#include "FontRenderingMode.h" -#include "FontTraitsMask.h" -#include <unicode/uscript.h> - -namespace WebCore { - -enum FontWeight { - FontWeight100, - FontWeight200, - FontWeight300, - FontWeight400, - FontWeight500, - FontWeight600, - FontWeight700, - FontWeight800, - FontWeight900, - FontWeightNormal = FontWeight400, - FontWeightBold = FontWeight700 -}; - -class FontDescription { -public: - enum GenericFamilyType { NoFamily, StandardFamily, SerifFamily, SansSerifFamily, - MonospaceFamily, CursiveFamily, FantasyFamily }; - - FontDescription() - : m_specifiedSize(0) - , m_computedSize(0) - , m_italic(false) - , m_smallCaps(false) - , m_isAbsoluteSize(false) - , m_weight(FontWeightNormal) - , m_genericFamily(NoFamily) - , m_usePrinterFont(false) - , m_renderingMode(NormalRenderingMode) - , m_keywordSize(0) - , m_dominantScript(USCRIPT_INVALID_CODE) - { - } - - bool operator==(const FontDescription&) const; - bool operator!=(const FontDescription& other) const { return !(*this == other); } - - const FontFamily& family() const { return m_familyList; } - FontFamily& firstFamily() { return m_familyList; } - float specifiedSize() const { return m_specifiedSize; } - float computedSize() const { return m_computedSize; } - bool italic() const { return m_italic; } - int computedPixelSize() const { return int(m_computedSize + 0.5f); } - bool smallCaps() const { return m_smallCaps; } - bool isAbsoluteSize() const { return m_isAbsoluteSize; } - FontWeight weight() const { return static_cast<FontWeight>(m_weight); } - FontWeight lighterWeight() const; - FontWeight bolderWeight() const; - GenericFamilyType genericFamily() const { return static_cast<GenericFamilyType>(m_genericFamily); } - bool usePrinterFont() const { return m_usePrinterFont; } - FontRenderingMode renderingMode() const { return static_cast<FontRenderingMode>(m_renderingMode); } - int keywordSize() const { return m_keywordSize; } - UScriptCode dominantScript() const { return m_dominantScript; } - - FontTraitsMask traitsMask() const; - - void setFamily(const FontFamily& family) { m_familyList = family; } - void setComputedSize(float s) { m_computedSize = s; } - void setSpecifiedSize(float s) { m_specifiedSize = s; } - void setItalic(bool i) { m_italic = i; } - void setSmallCaps(bool c) { m_smallCaps = c; } - void setIsAbsoluteSize(bool s) { m_isAbsoluteSize = s; } - void setWeight(FontWeight w) { m_weight = w; } - void setGenericFamily(GenericFamilyType genericFamily) { m_genericFamily = genericFamily; } - void setUsePrinterFont(bool p) { m_usePrinterFont = p; } - void setRenderingMode(FontRenderingMode mode) { m_renderingMode = mode; } - void setKeywordSize(int s) { m_keywordSize = s; } - void setDominantScript(UScriptCode s) { m_dominantScript = s; } - -private: - FontFamily m_familyList; // The list of font families to be used. - - float m_specifiedSize; // Specified CSS value. Independent of rendering issues such as integer - // rounding, minimum font sizes, and zooming. - float m_computedSize; // Computed size adjusted for the minimum font size and the zoom factor. - - bool m_italic : 1; - bool m_smallCaps : 1; - bool m_isAbsoluteSize : 1; // Whether or not CSS specified an explicit size - // (logical sizes like "medium" don't count). - unsigned m_weight : 8; // FontWeight - unsigned m_genericFamily : 3; // GenericFamilyType - bool m_usePrinterFont : 1; - - unsigned m_renderingMode : 1; // Used to switch between CG and GDI text on Windows. - - int m_keywordSize : 4; // We cache whether or not a font is currently represented by a CSS keyword (e.g., medium). If so, - // then we can accurately translate across different generic families to adjust for different preference settings - // (e.g., 13px monospace vs. 16px everything else). Sizes are 1-8 (like the HTML size values for <font>). - UScriptCode m_dominantScript; // See the comment in Document.h - -}; - -inline bool FontDescription::operator==(const FontDescription& other) const -{ - return m_familyList == other.m_familyList - && m_specifiedSize == other.m_specifiedSize - && m_computedSize == other.m_computedSize - && m_italic == other.m_italic - && m_smallCaps == other.m_smallCaps - && m_isAbsoluteSize == other.m_isAbsoluteSize - && m_weight == other.m_weight - && m_genericFamily == other.m_genericFamily - && m_usePrinterFont == other.m_usePrinterFont - && m_renderingMode == other.m_renderingMode - && m_keywordSize == other.m_keywordSize; -} - -} - -#endif diff --git a/webkit/pending/Frame.cpp b/webkit/pending/Frame.cpp deleted file mode 100644 index 0b1483a..0000000 --- a/webkit/pending/Frame.cpp +++ /dev/null @@ -1,1905 +0,0 @@ -/* - * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> - * 1999 Lars Knoll <knoll@kde.org> - * 1999 Antti Koivisto <koivisto@kde.org> - * 2000 Simon Hausmann <hausmann@kde.org> - * 2000 Stefan Schimanski <1Stein@gmx.de> - * 2001 George Staikos <staikos@kde.org> - * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. - * Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com> - * Copyright (C) 2007 Trolltech ASA - * Copyright (C) 2008 Eric Seidel <eric@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. - */ - -#include "config.h" -#include "Frame.h" -#include "FramePrivate.h" - -#include "ApplyStyleCommand.h" -#include "BeforeUnloadEvent.h" -#include "CSSComputedStyleDeclaration.h" -#include "CSSProperty.h" -#include "CSSPropertyNames.h" -#include "CachedCSSStyleSheet.h" -#include "DOMWindow.h" -#include "DocLoader.h" -#include "DocumentType.h" -#include "EditingText.h" -#include "EditorClient.h" -#include "EventNames.h" -#include "FocusController.h" -#include "FrameLoader.h" -#include "FrameView.h" -#include "GraphicsContext.h" -#include "HTMLDocument.h" -#include "HTMLFormElement.h" -#include "HTMLFrameElementBase.h" -#include "HTMLFormControlElement.h" -#include "HTMLNames.h" -#include "HTMLTableCellElement.h" -#include "HitTestResult.h" -#include "Logging.h" -#include "markup.h" -#include "MediaFeatureNames.h" -#include "Navigator.h" -#include "NodeList.h" -#include "Page.h" -#include "RegularExpression.h" -#include "RenderPart.h" -#include "RenderTableCell.h" -#include "RenderTextControl.h" -#include "RenderTheme.h" -#include "RenderView.h" -#include "ScriptController.h" -#include "Settings.h" -#include "SystemTime.h" -#include "TextIterator.h" -#include "TextResourceDecoder.h" -#include "XMLNames.h" -#include "ScriptController.h" -#include "npruntime_impl.h" -#include "runtime_root.h" -#include "visible_units.h" -#include <wtf/RefCountedLeakCounter.h> - -#if USE(JSC) -#include "JSDOMWindowShell.h" -#endif - -#if FRAME_LOADS_USER_STYLESHEET -#include "UserStyleSheetLoader.h" -#endif - -#if ENABLE(SVG) -#include "SVGDocument.h" -#include "SVGDocumentExtensions.h" -#include "SVGNames.h" -#include "XLinkNames.h" -#endif - -using namespace std; - -namespace WebCore { - -using namespace EventNames; -using namespace HTMLNames; - -double Frame::s_currentPaintTimeStamp = 0.0; - -#ifndef NDEBUG -static WTF::RefCountedLeakCounter frameCounter("Frame"); -#endif - -static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement) -{ - if (!ownerElement) - return 0; - return ownerElement->document()->frame(); -} - -Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient) - : d(new FramePrivate(page, parentFromOwnerElement(ownerElement), this, ownerElement, frameLoaderClient)) -{ - AtomicString::init(); - EventNames::init(); - HTMLNames::init(); - QualifiedName::init(); - MediaFeatureNames::init(); - -#if ENABLE(SVG) - SVGNames::init(); - XLinkNames::init(); -#endif - - XMLNames::init(); - - if (!ownerElement) - page->setMainFrame(this); - else { - page->incrementFrameCount(); - // Make sure we will not end up with two frames referencing the same owner element. - ASSERT((!(ownerElement->m_contentFrame)) || (ownerElement->m_contentFrame->ownerElement() != ownerElement)); - ownerElement->m_contentFrame = this; - } - -#ifndef NDEBUG - frameCounter.increment(); -#endif -} - -Frame::~Frame() -{ - setView(0); - loader()->clearRecordedFormValues(); - loader()->cancelAndClear(); - - // FIXME: We should not be doing all this work inside the destructor - - ASSERT(!d->m_lifeSupportTimer.isActive()); - -#ifndef NDEBUG - frameCounter.decrement(); -#endif - - d->m_script.disconnectFrame(); - - disconnectOwnerElement(); - - if (d->m_domWindow) - d->m_domWindow->disconnectFrame(); - - HashSet<DOMWindow*>::iterator end = d->m_liveFormerWindows.end(); - for (HashSet<DOMWindow*>::iterator it = d->m_liveFormerWindows.begin(); it != end; ++it) - (*it)->disconnectFrame(); - - if (d->m_view) { - d->m_view->hide(); - d->m_view->clearFrame(); - } - - ASSERT(!d->m_lifeSupportTimer.isActive()); - -#if FRAME_LOADS_USER_STYLESHEET - delete d->m_userStyleSheetLoader; -#endif - - delete d; - d = 0; -} - -void Frame::init() -{ - d->m_loader.init(); -} - -FrameLoader* Frame::loader() const -{ - return &d->m_loader; -} - -FrameView* Frame::view() const -{ - return d->m_view.get(); -} - -void Frame::setView(FrameView* view) -{ - // Detach the document now, so any onUnload handlers get run - if - // we wait until the view is destroyed, then things won't be - // hooked up enough for some JavaScript calls to work. - if (!view && d->m_doc && d->m_doc->attached() && !d->m_doc->inPageCache()) { - // FIXME: We don't call willRemove here. Why is that OK? - d->m_doc->detach(); - if (d->m_view) - d->m_view->unscheduleRelayout(); - } - eventHandler()->clear(); - - d->m_view = view; - - // Only one form submission is allowed per view of a part. - // Since this part may be getting reused as a result of being - // pulled from the back/forward cache, reset this flag. - loader()->resetMultipleFormSubmissionProtection(); -} - -ScriptController* Frame::script() -{ - return &d->m_script; -} - -Document* Frame::document() const -{ - return d->m_doc.get(); -} - -void Frame::setDocument(PassRefPtr<Document> newDoc) -{ - if (d->m_doc && d->m_doc->attached() && !d->m_doc->inPageCache()) { - // FIXME: We don't call willRemove here. Why is that OK? - d->m_doc->detach(); - } - - d->m_doc = newDoc; - if (d->m_doc && selection()->isFocusedAndActive()) - setUseSecureKeyboardEntry(d->m_doc->useSecureKeyboardEntryWhenActive()); - - if (d->m_doc && !d->m_doc->attached()) - d->m_doc->attach(); - - // Update the cached 'document' property, which is now stale. - d->m_script.updateDocument(); -} - -Settings* Frame::settings() const -{ - return d->m_page ? d->m_page->settings() : 0; -} - -String Frame::selectedText() const -{ - return plainText(selection()->toRange().get()); -} - -IntRect Frame::firstRectForRange(Range* range) const -{ - int extraWidthToEndOfLine = 0; - ExceptionCode ec = 0; - ASSERT(range->startContainer(ec)); - ASSERT(range->endContainer(ec)); - InlineBox* startInlineBox; - int startCaretOffset; - range->startPosition().getInlineBoxAndOffset(DOWNSTREAM, startInlineBox, startCaretOffset); - IntRect startCaretRect = range->startContainer(ec)->renderer()->caretRect(startInlineBox, startCaretOffset, &extraWidthToEndOfLine); - - InlineBox* endInlineBox; - int endCaretOffset; - range->endPosition().getInlineBoxAndOffset(UPSTREAM, endInlineBox, endCaretOffset); - IntRect endCaretRect = range->endContainer(ec)->renderer()->caretRect(endInlineBox, endCaretOffset); - - if (startCaretRect.y() == endCaretRect.y()) { - // start and end are on the same line - return IntRect(min(startCaretRect.x(), endCaretRect.x()), - startCaretRect.y(), - abs(endCaretRect.x() - startCaretRect.x()), - max(startCaretRect.height(), endCaretRect.height())); - } - - // start and end aren't on the same line, so go from start to the end of its line - return IntRect(startCaretRect.x(), - startCaretRect.y(), - startCaretRect.width() + extraWidthToEndOfLine, - startCaretRect.height()); -} - -SelectionController* Frame::selection() const -{ - return &d->m_selectionController; -} - -Editor* Frame::editor() const -{ - return &d->m_editor; -} - -TextGranularity Frame::selectionGranularity() const -{ - return d->m_selectionGranularity; -} - -void Frame::setSelectionGranularity(TextGranularity granularity) const -{ - d->m_selectionGranularity = granularity; -} - -SelectionController* Frame::dragCaretController() const -{ - return d->m_page->dragCaretController(); -} - - -AnimationController* Frame::animation() const -{ - return &d->m_animationController; -} - -static RegularExpression* createRegExpForLabels(const Vector<String>& labels) -{ - // REVIEW- version of this call in FrameMac.mm caches based on the NSArray ptrs being - // the same across calls. We can't do that. - - static RegularExpression wordRegExp = RegularExpression("\\w"); - String pattern("("); - unsigned int numLabels = labels.size(); - unsigned int i; - for (i = 0; i < numLabels; i++) { - String label = labels[i]; - - bool startsWithWordChar = false; - bool endsWithWordChar = false; - if (label.length() != 0) { - startsWithWordChar = wordRegExp.search(label.substring(0, 1)) >= 0; - endsWithWordChar = wordRegExp.search(label.substring(label.length() - 1, 1)) >= 0; - } - - if (i != 0) - pattern.append("|"); - // Search for word boundaries only if label starts/ends with "word characters". - // If we always searched for word boundaries, this wouldn't work for languages - // such as Japanese. - if (startsWithWordChar) { - pattern.append("\\b"); - } - pattern.append(label); - if (endsWithWordChar) { - pattern.append("\\b"); - } - } - pattern.append(")"); - return new RegularExpression(pattern, false); -} - -String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell) -{ - RenderTableCell* cellRenderer = static_cast<RenderTableCell*>(cell->renderer()); - - if (cellRenderer && cellRenderer->isTableCell()) { - RenderTableCell* cellAboveRenderer = cellRenderer->table()->cellAbove(cellRenderer); - - if (cellAboveRenderer) { - HTMLTableCellElement* aboveCell = - static_cast<HTMLTableCellElement*>(cellAboveRenderer->element()); - - if (aboveCell) { - // search within the above cell we found for a match - for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) { - if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) { - // For each text chunk, run the regexp - String nodeString = n->nodeValue(); - int pos = regExp->searchRev(nodeString); - if (pos >= 0) - return nodeString.substring(pos, regExp->matchedLength()); - } - } - } - } - } - // Any reason in practice to search all cells in that are above cell? - return String(); -} - -String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element) -{ - OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels)); - // We stop searching after we've seen this many chars - const unsigned int charsSearchedThreshold = 500; - // This is the absolute max we search. We allow a little more slop than - // charsSearchedThreshold, to make it more likely that we'll search whole nodes. - const unsigned int maxCharsSearched = 600; - // If the starting element is within a table, the cell that contains it - HTMLTableCellElement* startingTableCell = 0; - bool searchedCellAbove = false; - - // walk backwards in the node tree, until another element, or form, or end of tree - int unsigned lengthSearched = 0; - Node* n; - for (n = element->traversePreviousNode(); - n && lengthSearched < charsSearchedThreshold; - n = n->traversePreviousNode()) - { - if (n->hasTagName(formTag) - || (n->isHTMLElement() - && static_cast<HTMLElement*>(n)->isGenericFormElement())) - { - // We hit another form element or the start of the form - bail out - break; - } else if (n->hasTagName(tdTag) && !startingTableCell) { - startingTableCell = static_cast<HTMLTableCellElement*>(n); - } else if (n->hasTagName(trTag) && startingTableCell) { - String result = searchForLabelsAboveCell(regExp.get(), startingTableCell); - if (!result.isEmpty()) - return result; - searchedCellAbove = true; - } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) { - // For each text chunk, run the regexp - String nodeString = n->nodeValue(); - // add 100 for slop, to make it more likely that we'll search whole nodes - if (lengthSearched + nodeString.length() > maxCharsSearched) - nodeString = nodeString.right(charsSearchedThreshold - lengthSearched); - int pos = regExp->searchRev(nodeString); - if (pos >= 0) - return nodeString.substring(pos, regExp->matchedLength()); - lengthSearched += nodeString.length(); - } - } - - // If we started in a cell, but bailed because we found the start of the form or the - // previous element, we still might need to search the row above us for a label. - if (startingTableCell && !searchedCellAbove) { - return searchForLabelsAboveCell(regExp.get(), startingTableCell); - } - return String(); -} - -String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* element) -{ - String name = element->getAttribute(nameAttr); - if (name.isEmpty()) - return String(); - - // Make numbers and _'s in field names behave like word boundaries, e.g., "address2" - replace(name, RegularExpression("\\d"), " "); - name.replace('_', ' '); - - OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels)); - // Use the largest match we can find in the whole name string - int pos; - int length; - int bestPos = -1; - int bestLength = -1; - int start = 0; - do { - pos = regExp->search(name, start); - if (pos != -1) { - length = regExp->matchedLength(); - if (length >= bestLength) { - bestPos = pos; - bestLength = length; - } - start = pos + 1; - } - } while (pos != -1); - - if (bestPos != -1) - return name.substring(bestPos, bestLength); - return String(); -} - -const Selection& Frame::mark() const -{ - return d->m_mark; -} - -void Frame::setMark(const Selection& s) -{ - ASSERT(!s.base().node() || s.base().node()->document() == document()); - ASSERT(!s.extent().node() || s.extent().node()->document() == document()); - ASSERT(!s.start().node() || s.start().node()->document() == document()); - ASSERT(!s.end().node() || s.end().node()->document() == document()); - - d->m_mark = s; -} - -void Frame::notifyRendererOfSelectionChange(bool userTriggered) -{ - RenderObject* renderer = 0; - if (selection()->rootEditableElement()) - renderer = selection()->rootEditableElement()->shadowAncestorNode()->renderer(); - - // If the current selection is in a textfield or textarea, notify the renderer that the selection has changed - if (renderer && (renderer->isTextArea() || renderer->isTextField())) - static_cast<RenderTextControl*>(renderer)->selectionChanged(userTriggered); -} - -void Frame::invalidateSelection() -{ - selection()->setNeedsLayout(); - selectionLayoutChanged(); -} - -void Frame::setCaretVisible(bool flag) -{ - if (d->m_caretVisible == flag) - return; - clearCaretRectIfNeeded(); - d->m_caretVisible = flag; - selectionLayoutChanged(); -} - -void Frame::clearCaretRectIfNeeded() -{ - if (d->m_caretPaint) { - d->m_caretPaint = false; - selection()->invalidateCaretRect(); - } -} - -// Helper function that tells whether a particular node is an element that has an entire -// Frame and FrameView, a <frame>, <iframe>, or <object>. -static bool isFrameElement(const Node *n) -{ - if (!n) - return false; - RenderObject *renderer = n->renderer(); - if (!renderer || !renderer->isWidget()) - return false; - Widget* widget = static_cast<RenderWidget*>(renderer)->widget(); - return widget && widget->isFrameView(); -} - -void Frame::setFocusedNodeIfNeeded() -{ - if (!document() || selection()->isNone() || !selection()->isFocusedAndActive()) - return; - - Node* target = selection()->rootEditableElement(); - if (target) { - RenderObject* renderer = target->renderer(); - - // Walk up the render tree to search for a node to focus. - // Walking up the DOM tree wouldn't work for shadow trees, like those behind the engine-based text fields. - while (renderer) { - // We don't want to set focus on a subframe when selecting in a parent frame, - // so add the !isFrameElement check here. There's probably a better way to make this - // work in the long term, but this is the safest fix at this time. - if (target && target->isMouseFocusable() && !isFrameElement(target)) { - page()->focusController()->setFocusedNode(target, this); - return; - } - renderer = renderer->parent(); - if (renderer) - target = renderer->element(); - } - document()->setFocusedNode(0); - } -} - -void Frame::selectionLayoutChanged() -{ - bool caretRectChanged = selection()->recomputeCaretRect(); - - bool shouldBlink = d->m_caretVisible - && selection()->isCaret() && selection()->isContentEditable(); - - // If the caret moved, stop the blink timer so we can restart with a - // black caret in the new location. - if (caretRectChanged || !shouldBlink) - d->m_caretBlinkTimer.stop(); - - // Start blinking with a black caret. Be sure not to restart if we're - // already blinking in the right location. - if (shouldBlink && !d->m_caretBlinkTimer.isActive()) { - d->m_caretBlinkTimer.startRepeating(theme()->caretBlinkFrequency()); - if (!d->m_caretPaint) { - d->m_caretPaint = true; - selection()->invalidateCaretRect(); - } - } - - RenderView* canvas = contentRenderer(); - if (!canvas) - return; - - Selection selection = this->selection()->selection(); - - if (!selection.isRange()) - canvas->clearSelection(); - else { - // Use the rightmost candidate for the start of the selection, and the leftmost candidate for the end of the selection. - // Example: foo <a>bar</a>. Imagine that a line wrap occurs after 'foo', and that 'bar' is selected. If we pass [foo, 3] - // as the start of the selection, the selection painting code will think that content on the line containing 'foo' is selected - // and will fill the gap before 'bar'. - Position startPos = selection.start(); - if (startPos.downstream().isCandidate()) - startPos = startPos.downstream(); - Position endPos = selection.end(); - if (endPos.upstream().isCandidate()) - endPos = endPos.upstream(); - - // We can get into a state where the selection endpoints map to the same VisiblePosition when a selection is deleted - // because we don't yet notify the SelectionController of text removal. - if (startPos.isNotNull() && endPos.isNotNull() && selection.visibleStart() != selection.visibleEnd()) { - RenderObject *startRenderer = startPos.node()->renderer(); - RenderObject *endRenderer = endPos.node()->renderer(); - canvas->setSelection(startRenderer, startPos.offset(), endRenderer, endPos.offset()); - } - } -} - -void Frame::caretBlinkTimerFired(Timer<Frame>*) -{ - ASSERT(d->m_caretVisible); - ASSERT(selection()->isCaret()); - bool caretPaint = d->m_caretPaint; - if (selection()->isCaretBlinkingSuspended() && caretPaint) - return; - d->m_caretPaint = !caretPaint; - selection()->invalidateCaretRect(); -} - -void Frame::paintCaret(GraphicsContext* p, const IntRect& rect) const -{ - if (d->m_caretPaint && d->m_caretVisible) - selection()->paintCaret(p, rect); -} - -void Frame::paintDragCaret(GraphicsContext* p, const IntRect& rect) const -{ - SelectionController* dragCaretController = d->m_page->dragCaretController(); - ASSERT(dragCaretController->selection().isCaret()); - if (dragCaretController->selection().start().node()->document()->frame() == this) - dragCaretController->paintCaret(p, rect); -} - -float Frame::zoomFactor() const -{ - return d->m_zoomFactor; -} - -bool Frame::isZoomFactorTextOnly() const -{ - return d->m_page->settings()->zoomsTextOnly(); -} - -bool Frame::shouldApplyTextZoom() const -{ - if (d->m_zoomFactor == 1.0f || !isZoomFactorTextOnly()) - return false; -#if ENABLE(SVG) - if (d->m_doc && d->m_doc->isSVGDocument()) - return false; -#endif - return true; -} - -bool Frame::shouldApplyPageZoom() const -{ - if (d->m_zoomFactor == 1.0f || isZoomFactorTextOnly()) - return false; -#if ENABLE(SVG) - if (d->m_doc && d->m_doc->isSVGDocument()) - return false; -#endif - return true; -} - -void Frame::setZoomFactor(float percent, bool isTextOnly) -{ - if (d->m_zoomFactor == percent && isZoomFactorTextOnly()) - return; - -#if ENABLE(SVG) - // SVG doesn't care if the zoom factor is text only. It will always apply a - // zoom to the whole SVG. - if (d->m_doc && d->m_doc->isSVGDocument()) { - if (!static_cast<SVGDocument*>(d->m_doc.get())->zoomAndPanEnabled()) - return; - d->m_zoomFactor = percent; - d->m_page->settings()->setZoomsTextOnly(true); // We do this to avoid doing any scaling of CSS pixels, since the SVG has its own notion of zoom. - if (d->m_doc->renderer()) - d->m_doc->renderer()->repaint(); - return; - } -#endif - - d->m_zoomFactor = percent; - d->m_page->settings()->setZoomsTextOnly(isTextOnly); - - if (d->m_doc) - d->m_doc->recalcStyle(Node::Force); - - for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling()) - child->setZoomFactor(d->m_zoomFactor, isTextOnly); - - if (d->m_doc && d->m_doc->renderer() && d->m_doc->renderer()->needsLayout() && view()->didFirstLayout()) - view()->layout(); -} - -void Frame::setPrinting(bool printing, float minPageWidth, float maxPageWidth, bool adjustViewSize) -{ - if (!d->m_doc) - return; - - d->m_doc->setPrinting(printing); - view()->setMediaType(printing ? "print" : "screen"); - d->m_doc->updateStyleSelector(); - forceLayoutWithPageWidthRange(minPageWidth, maxPageWidth, adjustViewSize); - - for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling()) - child->setPrinting(printing, minPageWidth, maxPageWidth, adjustViewSize); -} - -void Frame::setJSStatusBarText(const String& text) -{ - d->m_kjsStatusBarText = text; - if (d->m_page) - d->m_page->chrome()->setStatusbarText(this, d->m_kjsStatusBarText); -} - -void Frame::setJSDefaultStatusBarText(const String& text) -{ - d->m_kjsDefaultStatusBarText = text; - if (d->m_page) - d->m_page->chrome()->setStatusbarText(this, d->m_kjsDefaultStatusBarText); -} - -String Frame::jsStatusBarText() const -{ - return d->m_kjsStatusBarText; -} - -String Frame::jsDefaultStatusBarText() const -{ - return d->m_kjsDefaultStatusBarText; -} - -void Frame::setNeedsReapplyStyles() -{ - if (d->m_needsReapplyStyles) - return; - - d->m_needsReapplyStyles = true; - - // Invalidate the FrameView so that FrameView::layout will get called, - // which calls reapplyStyles. - FrameView* curView = view(); - if (curView) - curView->invalidate(); -} - -bool Frame::needsReapplyStyles() const -{ - return d->m_needsReapplyStyles; -} - -void Frame::reapplyStyles() -{ - d->m_needsReapplyStyles = false; - - // FIXME: This call doesn't really make sense in a method called - // "reapplyStyles". We should probably eventually move it into its own - // method. - if (d->m_doc) - d->m_doc->docLoader()->setAutoLoadImages(d->m_page && d->m_page->settings()->loadsImagesAutomatically()); - -#if FRAME_LOADS_USER_STYLESHEET - const KURL userStyleSheetLocation = d->m_page ? d->m_page->settings()->userStyleSheetLocation() : KURL(); - if (!userStyleSheetLocation.isEmpty()) - setUserStyleSheetLocation(userStyleSheetLocation); - else - setUserStyleSheet(String()); -#endif - - // FIXME: It's not entirely clear why the following is needed. - // The document automatically does this as required when you set the style sheet. - // But we had problems when this code was removed. Details are in - // <http://bugs.webkit.org/show_bug.cgi?id=8079>. - if (d->m_doc) - d->m_doc->updateStyleSelector(); -} - -bool Frame::shouldChangeSelection(const Selection& newSelection) const -{ - return shouldChangeSelection(selection()->selection(), newSelection, newSelection.affinity(), false); -} - -bool Frame::shouldChangeSelection(const Selection& oldSelection, const Selection& newSelection, EAffinity affinity, bool stillSelecting) const -{ - return editor()->client()->shouldChangeSelectedRange(oldSelection.toRange().get(), newSelection.toRange().get(), - affinity, stillSelecting); -} - -bool Frame::shouldDeleteSelection(const Selection& selection) const -{ - return editor()->client()->shouldDeleteRange(selection.toRange().get()); -} - -bool Frame::isContentEditable() const -{ - if (d->m_editor.clientIsEditable()) - return true; - if (!d->m_doc) - return false; - return d->m_doc->inDesignMode(); -} - -#if !PLATFORM(MAC) - -void Frame::setUseSecureKeyboardEntry(bool) -{ -} - -#endif - -void Frame::updateSecureKeyboardEntryIfActive() -{ - if (selection()->isFocusedAndActive()) - setUseSecureKeyboardEntry(d->m_doc->useSecureKeyboardEntryWhenActive()); -} - -CSSMutableStyleDeclaration *Frame::typingStyle() const -{ - return d->m_typingStyle.get(); -} - -void Frame::setTypingStyle(CSSMutableStyleDeclaration *style) -{ - d->m_typingStyle = style; -} - -void Frame::clearTypingStyle() -{ - d->m_typingStyle = 0; -} - -void Frame::computeAndSetTypingStyle(CSSStyleDeclaration *style, EditAction editingAction) -{ - if (!style || style->length() == 0) { - clearTypingStyle(); - return; - } - - // Calculate the current typing style. - RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable(); - if (typingStyle()) { - typingStyle()->merge(mutableStyle.get()); - mutableStyle = typingStyle(); - } - - Node* node = selection()->selection().visibleStart().deepEquivalent().node(); - computedStyle(node)->diff(mutableStyle.get()); - - // Handle block styles, substracting these from the typing style. - RefPtr<CSSMutableStyleDeclaration> blockStyle = mutableStyle->copyBlockProperties(); - blockStyle->diff(mutableStyle.get()); - if (document() && blockStyle->length() > 0) - applyCommand(ApplyStyleCommand::create(document(), blockStyle.get(), editingAction)); - - // Set the remaining style as the typing style. - d->m_typingStyle = mutableStyle.release(); -} - -String Frame::selectionStartStylePropertyValue(int stylePropertyID) const -{ - Node *nodeToRemove; - RefPtr<CSSStyleDeclaration> selectionStyle = selectionComputedStyle(nodeToRemove); - if (!selectionStyle) - return String(); - - String value = selectionStyle->getPropertyValue(stylePropertyID); - - if (nodeToRemove) { - ExceptionCode ec = 0; - nodeToRemove->remove(ec); - ASSERT(ec == 0); - } - - return value; -} - -PassRefPtr<CSSComputedStyleDeclaration> Frame::selectionComputedStyle(Node*& nodeToRemove) const -{ - nodeToRemove = 0; - - if (!document()) - return 0; - - if (selection()->isNone()) - return 0; - - RefPtr<Range> range(selection()->toRange()); - Position pos = range->editingStartPosition(); - - Element *elem = pos.element(); - if (!elem) - return 0; - - RefPtr<Element> styleElement = elem; - ExceptionCode ec = 0; - - if (d->m_typingStyle) { - styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec); - ASSERT(ec == 0); - - styleElement->setAttribute(styleAttr, d->m_typingStyle->cssText().impl(), ec); - ASSERT(ec == 0); - - styleElement->appendChild(document()->createEditingTextNode(""), ec); - ASSERT(ec == 0); - - if (elem->renderer() && elem->renderer()->canHaveChildren()) { - elem->appendChild(styleElement, ec); - } else { - Node *parent = elem->parent(); - Node *next = elem->nextSibling(); - - if (next) { - parent->insertBefore(styleElement, next, ec); - } else { - parent->appendChild(styleElement, ec); - } - } - ASSERT(ec == 0); - - nodeToRemove = styleElement.get(); - } - - return computedStyle(styleElement.release()); -} - -void Frame::textFieldDidBeginEditing(Element* e) -{ - if (editor()->client()) - editor()->client()->textFieldDidBeginEditing(e); -} - -void Frame::textFieldDidEndEditing(Element* e) -{ - if (editor()->client()) - editor()->client()->textFieldDidEndEditing(e); -} - -void Frame::textDidChangeInTextField(Element* e) -{ - if (editor()->client()) - editor()->client()->textDidChangeInTextField(e); -} - -bool Frame::doTextFieldCommandFromEvent(Element* e, KeyboardEvent* ke) -{ - if (editor()->client()) - return editor()->client()->doTextFieldCommandFromEvent(e, ke); - - return false; -} - -void Frame::textWillBeDeletedInTextField(Element* input) -{ - if (editor()->client()) - editor()->client()->textWillBeDeletedInTextField(input); -} - -void Frame::textDidChangeInTextArea(Element* e) -{ - if (editor()->client()) - editor()->client()->textDidChangeInTextArea(e); -} - -void Frame::applyEditingStyleToBodyElement() const -{ - if (!d->m_doc) - return; - - RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body"); - unsigned len = list->length(); - for (unsigned i = 0; i < len; i++) { - applyEditingStyleToElement(static_cast<Element*>(list->item(i))); - } -} - -void Frame::removeEditingStyleFromBodyElement() const -{ - if (!d->m_doc) - return; - - RefPtr<NodeList> list = d->m_doc->getElementsByTagName("body"); - unsigned len = list->length(); - for (unsigned i = 0; i < len; i++) { - removeEditingStyleFromElement(static_cast<Element*>(list->item(i))); - } -} - -void Frame::applyEditingStyleToElement(Element* element) const -{ - if (!element) - return; - - CSSStyleDeclaration* style = element->style(); - ASSERT(style); - - ExceptionCode ec = 0; - style->setProperty(CSSPropertyWordWrap, "break-word", false, ec); - ASSERT(ec == 0); - style->setProperty(CSSPropertyWebkitNbspMode, "space", false, ec); - ASSERT(ec == 0); - style->setProperty(CSSPropertyWebkitLineBreak, "after-white-space", false, ec); - ASSERT(ec == 0); -} - -void Frame::removeEditingStyleFromElement(Element*) const -{ -} - -#ifndef NDEBUG -static HashSet<Frame*>& keepAliveSet() -{ - static HashSet<Frame*> staticKeepAliveSet; - return staticKeepAliveSet; -} -#endif - -void Frame::keepAlive() -{ - if (d->m_lifeSupportTimer.isActive()) - return; -#ifndef NDEBUG - keepAliveSet().add(this); -#endif - ref(); - d->m_lifeSupportTimer.startOneShot(0); -} - -#ifndef NDEBUG -void Frame::cancelAllKeepAlive() -{ - HashSet<Frame*>::iterator end = keepAliveSet().end(); - for (HashSet<Frame*>::iterator it = keepAliveSet().begin(); it != end; ++it) { - Frame* frame = *it; - frame->d->m_lifeSupportTimer.stop(); - frame->deref(); - } - keepAliveSet().clear(); -} -#endif - -void Frame::lifeSupportTimerFired(Timer<Frame>*) -{ -#ifndef NDEBUG - keepAliveSet().remove(this); -#endif - deref(); -} - -void Frame::clearDOMWindow() -{ - if (d->m_domWindow) { - d->m_liveFormerWindows.add(d->m_domWindow.get()); - d->m_domWindow->clear(); - } - d->m_script.clearPluginObjects(); -} - -RenderView* Frame::contentRenderer() const -{ - Document* doc = document(); - if (!doc) - return 0; - RenderObject* object = doc->renderer(); - if (!object) - return 0; - ASSERT(object->isRenderView()); - return static_cast<RenderView*>(object); -} - -HTMLFrameOwnerElement* Frame::ownerElement() const -{ - return d->m_ownerElement; -} - -RenderPart* Frame::ownerRenderer() const -{ - HTMLFrameOwnerElement* ownerElement = d->m_ownerElement; - if (!ownerElement) - return 0; - RenderObject* object = ownerElement->renderer(); - if (!object) - return 0; - // FIXME: If <object> is ever fixed to disassociate itself from frames - // that it has started but canceled, then this can turn into an ASSERT - // since d->m_ownerElement would be 0 when the load is canceled. - // https://bugs.webkit.org/show_bug.cgi?id=18585 - if (!object->isRenderPart()) - return 0; - return static_cast<RenderPart*>(object); -} - -bool Frame::isDisconnected() const -{ - return d->m_isDisconnected; -} - -void Frame::setIsDisconnected(bool isDisconnected) -{ - d->m_isDisconnected = isDisconnected; -} - -bool Frame::excludeFromTextSearch() const -{ - return d->m_excludeFromTextSearch; -} - -void Frame::setExcludeFromTextSearch(bool exclude) -{ - d->m_excludeFromTextSearch = exclude; -} - -// returns FloatRect because going through IntRect would truncate any floats -FloatRect Frame::selectionRect(bool clipToVisibleContent) const -{ - RenderView* root = contentRenderer(); - if (!root) - return IntRect(); - - IntRect selectionRect = root->selectionRect(clipToVisibleContent); - return clipToVisibleContent ? intersection(selectionRect, d->m_view->visibleContentRect()) : selectionRect; -} - -void Frame::selectionTextRects(Vector<FloatRect>& rects, bool clipToVisibleContent) const -{ - RenderView* root = contentRenderer(); - if (!root) - return; - - RefPtr<Range> selectedRange = selection()->toRange(); - - Vector<IntRect> intRects; - selectedRange->addLineBoxRects(intRects, true); - - unsigned size = intRects.size(); - FloatRect visibleContentRect = d->m_view->visibleContentRect(); - for (unsigned i = 0; i < size; ++i) - if (clipToVisibleContent) - rects.append(intersection(intRects[i], visibleContentRect)); - else - rects.append(intRects[i]); -} - - -bool Frame::isFrameSet() const -{ - Document* document = d->m_doc.get(); - if (!document || !document->isHTMLDocument()) - return false; - Node *body = static_cast<HTMLDocument*>(document)->body(); - return body && body->renderer() && body->hasTagName(framesetTag); -} - -// Scans logically forward from "start", including any child frames -static HTMLFormElement *scanForForm(Node *start) -{ - Node *n; - for (n = start; n; n = n->traverseNextNode()) { - if (n->hasTagName(formTag)) - return static_cast<HTMLFormElement*>(n); - else if (n->isHTMLElement() && static_cast<HTMLElement*>(n)->isGenericFormElement()) - return static_cast<HTMLFormControlElement*>(n)->form(); - else if (n->hasTagName(frameTag) || n->hasTagName(iframeTag)) { - Node *childDoc = static_cast<HTMLFrameElementBase*>(n)->contentDocument(); - if (HTMLFormElement *frameResult = scanForForm(childDoc)) - return frameResult; - } - } - return 0; -} - -// We look for either the form containing the current focus, or for one immediately after it -HTMLFormElement *Frame::currentForm() const -{ - // start looking either at the active (first responder) node, or where the selection is - Node *start = d->m_doc ? d->m_doc->focusedNode() : 0; - if (!start) - start = selection()->start().node(); - - // try walking up the node tree to find a form element - Node *n; - for (n = start; n; n = n->parentNode()) { - if (n->hasTagName(formTag)) - return static_cast<HTMLFormElement*>(n); - else if (n->isHTMLElement() - && static_cast<HTMLElement*>(n)->isGenericFormElement()) - return static_cast<HTMLFormControlElement*>(n)->form(); - } - - // try walking forward in the node tree to find a form element - return start ? scanForForm(start) : 0; -} - -// FIXME: should this go in SelectionController? -void Frame::revealSelection(const RenderLayer::ScrollAlignment& alignment) const -{ - IntRect rect; - - switch (selection()->state()) { - case Selection::NONE: - return; - - case Selection::CARET: - rect = selection()->caretRect(); - break; - - case Selection::RANGE: - rect = enclosingIntRect(selectionRect(false)); - break; - } - - Position start = selection()->start(); - - ASSERT(start.node()); - if (start.node() && start.node()->renderer()) { - // FIXME: This code only handles scrolling the startContainer's layer, but - // the selection rect could intersect more than just that. - // See <rdar://problem/4799899>. - if (RenderLayer *layer = start.node()->renderer()->enclosingLayer()) - layer->scrollRectToVisible(rect, false, alignment, alignment); - } -} - -void Frame::revealCaret(const RenderLayer::ScrollAlignment& alignment) const -{ - if (selection()->isNone()) - return; - - Position extent = selection()->extent(); - if (extent.node() && extent.node()->renderer()) { - IntRect extentRect = VisiblePosition(extent).caretRect(); - RenderLayer* layer = extent.node()->renderer()->enclosingLayer(); - if (layer) - layer->scrollRectToVisible(extentRect, false, alignment, alignment); - } -} - -// FIXME: why is this here instead of on the FrameView? -void Frame::paint(GraphicsContext* p, const IntRect& rect) -{ -#ifndef NDEBUG - bool fillWithRed; - if (!document() || document()->printing()) - fillWithRed = false; // Printing, don't fill with red (can't remember why). - else if (document()->ownerElement()) - fillWithRed = false; // Subframe, don't fill with red. - else if (view() && view()->isTransparent()) - fillWithRed = false; // Transparent, don't fill with red. - else if (d->m_paintRestriction == PaintRestrictionSelectionOnly || d->m_paintRestriction == PaintRestrictionSelectionOnlyBlackText) - fillWithRed = false; // Selections are transparent, don't fill with red. - else if (d->m_elementToDraw) - fillWithRed = false; // Element images are transparent, don't fill with red. - else - fillWithRed = true; - - if (fillWithRed) - p->fillRect(rect, Color(0xFF, 0, 0)); -#endif - - bool isTopLevelPainter = !s_currentPaintTimeStamp; - if (isTopLevelPainter) - s_currentPaintTimeStamp = currentTime(); - - if (contentRenderer()) { - ASSERT(d->m_view && !d->m_view->needsLayout()); - ASSERT(!d->m_isPainting); - - d->m_isPainting = true; - - // d->m_elementToDraw is used to draw only one element - RenderObject* eltRenderer = d->m_elementToDraw ? d->m_elementToDraw->renderer() : 0; - if (d->m_paintRestriction == PaintRestrictionNone) - document()->invalidateRenderedRectsForMarkersInRect(rect); - contentRenderer()->layer()->paint(p, rect, d->m_paintRestriction, eltRenderer); - - d->m_isPainting = false; - -#if ENABLE(DASHBOARD_SUPPORT) - // Regions may have changed as a result of the visibility/z-index of element changing. - if (document()->dashboardRegionsDirty()) - view()->updateDashboardRegions(); -#endif - } else - LOG_ERROR("called Frame::paint with nil renderer"); - - if (isTopLevelPainter) - s_currentPaintTimeStamp = 0; -} - -void Frame::setPaintRestriction(PaintRestriction pr) -{ - d->m_paintRestriction = pr; -} - -bool Frame::isPainting() const -{ - return d->m_isPainting; -} - -void Frame::adjustPageHeight(float *newBottom, float oldTop, float oldBottom, float bottomLimit) -{ - RenderView* root = contentRenderer(); - if (root) { - // Use a context with painting disabled. - GraphicsContext context((PlatformGraphicsContext*)0); - root->setTruncatedAt((int)floorf(oldBottom)); - IntRect dirtyRect(0, (int)floorf(oldTop), root->docWidth(), (int)ceilf(oldBottom - oldTop)); - root->layer()->paint(&context, dirtyRect); - *newBottom = root->bestTruncatedAt(); - if (*newBottom == 0) - *newBottom = oldBottom; - } else - *newBottom = oldBottom; -} - -Frame* Frame::frameForWidget(const Widget* widget) -{ - ASSERT_ARG(widget, widget); - - if (RenderWidget* renderer = RenderWidget::find(widget)) - if (Node* node = renderer->node()) - return node->document()->frame(); - - // Assume all widgets are either a FrameView or owned by a RenderWidget. - // FIXME: That assumption is not right for scroll bars! - ASSERT(widget->isFrameView()); - return static_cast<const FrameView*>(widget)->frame(); -} - -void Frame::forceLayout(bool allowSubtree) -{ - FrameView *v = d->m_view.get(); - if (v) { - v->layout(allowSubtree); - // We cannot unschedule a pending relayout, since the force can be called with - // a tiny rectangle from a drawRect update. By unscheduling we in effect - // "validate" and stop the necessary full repaint from occurring. Basically any basic - // append/remove DHTML is broken by this call. For now, I have removed the optimization - // until we have a better invalidation stategy. -dwh - //v->unscheduleRelayout(); - } -} - -void Frame::forceLayoutWithPageWidthRange(float minPageWidth, float maxPageWidth, bool adjustViewSize) -{ - // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see - // the state of things before and after the layout - RenderView *root = static_cast<RenderView*>(document()->renderer()); - if (root) { - // This magic is basically copied from khtmlview::print - int pageW = (int)ceilf(minPageWidth); - root->setWidth(pageW); - root->setNeedsLayoutAndPrefWidthsRecalc(); - forceLayout(); - - // If we don't fit in the minimum page width, we'll lay out again. If we don't fit in the - // maximum page width, we will lay out to the maximum page width and clip extra content. - // FIXME: We are assuming a shrink-to-fit printing implementation. A cropping - // implementation should not do this! - int rightmostPos = root->rightmostPosition(); - if (rightmostPos > minPageWidth) { - pageW = min(rightmostPos, (int)ceilf(maxPageWidth)); - root->setWidth(pageW); - root->setNeedsLayoutAndPrefWidthsRecalc(); - forceLayout(); - } - } - - if (adjustViewSize && view()) - view()->adjustViewSize(); -} - -void Frame::sendResizeEvent() -{ - if (Document* doc = document()) - doc->dispatchWindowEvent(EventNames::resizeEvent, false, false); -} - -void Frame::sendScrollEvent() -{ - FrameView* v = d->m_view.get(); - if (!v) - return; - v->setWasScrolledByUser(true); - Document* doc = document(); - if (!doc) - return; - doc->dispatchHTMLEvent(scrollEvent, true, false); -} - -void Frame::clearTimers(FrameView *view, Document *document) -{ - if (view) { - view->unscheduleRelayout(); - if (view->frame()) { - if (document && document->renderer() && document->renderer()->hasLayer()) - document->renderer()->layer()->suspendMarquees(); - view->frame()->animation()->suspendAnimations(document); - view->frame()->eventHandler()->stopAutoscrollTimer(); - } - } -} - -void Frame::clearTimers() -{ - clearTimers(d->m_view.get(), document()); -} - -RenderStyle *Frame::styleForSelectionStart(Node *&nodeToRemove) const -{ - nodeToRemove = 0; - - if (!document()) - return 0; - if (selection()->isNone()) - return 0; - - Position pos = selection()->selection().visibleStart().deepEquivalent(); - if (!pos.isCandidate()) - return 0; - Node *node = pos.node(); - if (!node) - return 0; - - if (!d->m_typingStyle) - return node->renderer()->style(); - - ExceptionCode ec = 0; - RefPtr<Element> styleElement = document()->createElementNS(xhtmlNamespaceURI, "span", ec); - ASSERT(ec == 0); - - String styleText = d->m_typingStyle->cssText() + " display: inline"; - styleElement->setAttribute(styleAttr, styleText.impl(), ec); - ASSERT(ec == 0); - - styleElement->appendChild(document()->createEditingTextNode(""), ec); - ASSERT(ec == 0); - - node->parentNode()->appendChild(styleElement, ec); - ASSERT(ec == 0); - - nodeToRemove = styleElement.get(); - return styleElement->renderer() ? styleElement->renderer()->style() : 0; -} - -void Frame::setSelectionFromNone() -{ - // Put a caret inside the body if the entire frame is editable (either the - // entire WebView is editable or designMode is on for this document). - Document *doc = document(); - if (!doc || !selection()->isNone() || !isContentEditable()) - return; - - Node* node = doc->documentElement(); - while (node && !node->hasTagName(bodyTag)) - node = node->traverseNextNode(); - if (node) - selection()->setSelection(Selection(Position(node, 0), DOWNSTREAM)); -} - -bool Frame::inViewSourceMode() const -{ - return d->m_inViewSourceMode; -} - -void Frame::setInViewSourceMode(bool mode) const -{ - d->m_inViewSourceMode = mode; -} - -UChar Frame::backslashAsCurrencySymbol() const -{ - Document *doc = document(); - if (!doc) - return '\\'; - TextResourceDecoder *decoder = doc->decoder(); - if (!decoder) - return '\\'; - - return decoder->encoding().backslashAsCurrencySymbol(); -} - -// Searches from the beginning of the document if nothing is selected. -bool Frame::findString(const String& target, bool forward, bool caseFlag, bool wrapFlag, bool startInSelection) -{ - if (target.isEmpty() || !document()) - return false; - - if (excludeFromTextSearch()) - return false; - - // Start from an edge of the selection, if there's a selection that's not in shadow content. Which edge - // is used depends on whether we're searching forward or backward, and whether startInSelection is set. - RefPtr<Range> searchRange(rangeOfContents(document())); - Selection selection = this->selection()->selection(); - - if (forward) - setStart(searchRange.get(), startInSelection ? selection.visibleStart() : selection.visibleEnd()); - else - setEnd(searchRange.get(), startInSelection ? selection.visibleEnd() : selection.visibleStart()); - - Node* shadowTreeRoot = selection.shadowTreeRootNode(); - if (shadowTreeRoot) { - ExceptionCode ec = 0; - if (forward) - searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec); - else - searchRange->setStart(shadowTreeRoot, 0, ec); - } - - RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, forward, caseFlag)); - // If we started in the selection and the found range exactly matches the existing selection, find again. - // Build a selection with the found range to remove collapsed whitespace. - // Compare ranges instead of selection objects to ignore the way that the current selection was made. - if (startInSelection && *Selection(resultRange.get()).toRange() == *selection.toRange()) { - searchRange = rangeOfContents(document()); - if (forward) - setStart(searchRange.get(), selection.visibleEnd()); - else - setEnd(searchRange.get(), selection.visibleStart()); - - if (shadowTreeRoot) { - ExceptionCode ec = 0; - if (forward) - searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec); - else - searchRange->setStart(shadowTreeRoot, 0, ec); - } - - resultRange = findPlainText(searchRange.get(), target, forward, caseFlag); - } - - ExceptionCode exception = 0; - - // If nothing was found in the shadow tree, search in main content following the shadow tree. - if (resultRange->collapsed(exception) && shadowTreeRoot) { - searchRange = rangeOfContents(document()); - if (forward) - searchRange->setStartAfter(shadowTreeRoot->shadowParentNode(), exception); - else - searchRange->setEndBefore(shadowTreeRoot->shadowParentNode(), exception); - - resultRange = findPlainText(searchRange.get(), target, forward, caseFlag); - } - - if (!editor()->insideVisibleArea(resultRange.get())) { - resultRange = editor()->nextVisibleRange(resultRange.get(), target, forward, caseFlag, wrapFlag); - if (!resultRange) - return false; - } - - // If we didn't find anything and we're wrapping, search again in the entire document (this will - // redundantly re-search the area already searched in some cases). - if (resultRange->collapsed(exception) && wrapFlag) { - searchRange = rangeOfContents(document()); - resultRange = findPlainText(searchRange.get(), target, forward, caseFlag); - // We used to return false here if we ended up with the same range that we started with - // (e.g., the selection was already the only instance of this text). But we decided that - // this should be a success case instead, so we'll just fall through in that case. - } - - if (resultRange->collapsed(exception)) - return false; - - this->selection()->setSelection(Selection(resultRange.get(), DOWNSTREAM)); - revealSelection(); - return true; -} - -unsigned Frame::markAllMatchesForText(const String& target, bool caseFlag, unsigned limit) -{ - if (target.isEmpty() || !document()) - return 0; - - RefPtr<Range> searchRange(rangeOfContents(document())); - - ExceptionCode exception = 0; - unsigned matchCount = 0; - do { - RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, caseFlag)); - if (resultRange->collapsed(exception)) { - if (!resultRange->startContainer()->isInShadowTree()) - break; - - searchRange = rangeOfContents(document()); - searchRange->setStartAfter(resultRange->startContainer()->shadowAncestorNode(), exception); - continue; - } - - // A non-collapsed result range can in some funky whitespace cases still not - // advance the range's start position (4509328). Break to avoid infinite loop. - VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM); - if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM)) - break; - - // Only treat the result as a match if it is visible - if (editor()->insideVisibleArea(resultRange.get())) { - ++matchCount; - document()->addMarker(resultRange.get(), DocumentMarker::TextMatch); - } - - // Stop looking if we hit the specified limit. A limit of 0 means no limit. - if (limit > 0 && matchCount >= limit) - break; - - setStart(searchRange.get(), newStart); - Node* shadowTreeRoot = searchRange->shadowTreeRootNode(); - if (searchRange->collapsed(exception) && shadowTreeRoot) - searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), exception); - } while (true); - - // Do a "fake" paint in order to execute the code that computes the rendered rect for - // each text match. - Document* doc = document(); - if (doc && d->m_view && contentRenderer()) { - doc->updateLayout(); // Ensure layout is up to date. - IntRect visibleRect(enclosingIntRect(d->m_view->visibleContentRect())); - if (!visibleRect.isEmpty()) { - GraphicsContext context((PlatformGraphicsContext*)0); - context.setPaintingDisabled(true); - paint(&context, visibleRect); - } - } - - return matchCount; -} - -bool Frame::markedTextMatchesAreHighlighted() const -{ - return d->m_highlightTextMatches; -} - -void Frame::setMarkedTextMatchesAreHighlighted(bool flag) -{ - if (flag == d->m_highlightTextMatches || !document()) - return; - - d->m_highlightTextMatches = flag; - document()->repaintMarkers(DocumentMarker::TextMatch); -} - -FrameTree* Frame::tree() const -{ - return &d->m_treeNode; -} - -DOMWindow* Frame::domWindow() const -{ - if (!d->m_domWindow) - d->m_domWindow = DOMWindow::create(const_cast<Frame*>(this)); - - return d->m_domWindow.get(); -} - -void Frame::clearFormerDOMWindow(DOMWindow* window) -{ - d->m_liveFormerWindows.remove(window); -} - -Page* Frame::page() const -{ - return d->m_page; -} - -EventHandler* Frame::eventHandler() const -{ - return &d->m_eventHandler; -} - -void Frame::pageDestroyed() -{ - if (Frame* parent = tree()->parent()) - parent->loader()->checkLoadComplete(); - - // FIXME: It's unclear as to why this is called more than once, but it is, - // so page() could be NULL. - if (page() && page()->focusController()->focusedFrame() == this) - page()->focusController()->setFocusedFrame(0); - - // This will stop any JS timers - script()->disconnectFrame(); - - script()->clearScriptObjects(); - - d->m_page = 0; -} - -void Frame::disconnectOwnerElement() -{ - if (d->m_ownerElement) { - if (Document* doc = document()) - doc->clearAXObjectCache(); - d->m_ownerElement->m_contentFrame = 0; - if (d->m_page) - d->m_page->decrementFrameCount(); - } - d->m_ownerElement = 0; -} - -String Frame::documentTypeString() const -{ - if (Document* doc = document()) { - if (DocumentType* doctype = doc->doctype()) - return createMarkup(doctype); - } - - return String(); -} - -bool Frame::prohibitsScrolling() const -{ - return d->m_prohibitsScrolling; -} - -void Frame::setProhibitsScrolling(bool prohibit) -{ - d->m_prohibitsScrolling = prohibit; -} - -void Frame::focusWindow() -{ - if (!page()) - return; - - // If we're a top level window, bring the window to the front. - if (!tree()->parent()) - page()->chrome()->focus(); - - eventHandler()->focusDocumentView(); -} - -void Frame::unfocusWindow() -{ - if (!page()) - return; - - // If we're a top level window, deactivate the window. - if (!tree()->parent()) - page()->chrome()->unfocus(); -} - -bool Frame::shouldClose() -{ - Chrome* chrome = page() ? page()->chrome() : 0; - if (!chrome || !chrome->canRunBeforeUnloadConfirmPanel()) - return true; - - RefPtr<Document> doc = document(); - if (!doc) - return true; - HTMLElement* body = doc->body(); - if (!body) - return true; - - loader()->setFiringUnloadEvents(true); - - RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create(); - beforeUnloadEvent->setTarget(doc); - doc->handleWindowEvent(beforeUnloadEvent.get(), false); - - if (!beforeUnloadEvent->defaultPrevented() && doc) - doc->defaultEventHandler(beforeUnloadEvent.get()); - - loader()->setFiringUnloadEvents(false); - - if (beforeUnloadEvent->result().isNull()) - return true; - - String text = beforeUnloadEvent->result(); - text.replace('\\', backslashAsCurrencySymbol()); - - return chrome->runBeforeUnloadConfirmPanel(text, this); -} - -void Frame::scheduleClose() -{ - if (!shouldClose()) - return; - - Chrome* chrome = page() ? page()->chrome() : 0; - if (chrome) - chrome->closeWindowSoon(); -} - -void Frame::respondToChangedSelection(const Selection& oldSelection, bool closeTyping) -{ - if (document()) { - bool isContinuousSpellCheckingEnabled = editor()->isContinuousSpellCheckingEnabled(); - bool isContinuousGrammarCheckingEnabled = isContinuousSpellCheckingEnabled && editor()->isGrammarCheckingEnabled(); - if (isContinuousSpellCheckingEnabled) { - Selection newAdjacentWords; - Selection newSelectedSentence; - if (selection()->selection().isContentEditable()) { - VisiblePosition newStart(selection()->selection().visibleStart()); - newAdjacentWords = Selection(startOfWord(newStart, LeftWordIfOnBoundary), endOfWord(newStart, RightWordIfOnBoundary)); - if (isContinuousGrammarCheckingEnabled) - newSelectedSentence = Selection(startOfSentence(newStart), endOfSentence(newStart)); - } - - // When typing we check spelling elsewhere, so don't redo it here. - // If this is a change in selection resulting from a delete operation, - // oldSelection may no longer be in the document. - if (closeTyping && oldSelection.isContentEditable() && oldSelection.start().node() && oldSelection.start().node()->inDocument()) { - VisiblePosition oldStart(oldSelection.visibleStart()); - Selection oldAdjacentWords = Selection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary)); - if (oldAdjacentWords != newAdjacentWords) { - editor()->markMisspellings(oldAdjacentWords); - if (isContinuousGrammarCheckingEnabled) { - Selection oldSelectedSentence = Selection(startOfSentence(oldStart), endOfSentence(oldStart)); - if (oldSelectedSentence != newSelectedSentence) - editor()->markBadGrammar(oldSelectedSentence); - } - } - } - - // This only erases markers that are in the first unit (word or sentence) of the selection. - // Perhaps peculiar, but it matches AppKit. - if (RefPtr<Range> wordRange = newAdjacentWords.toRange()) - document()->removeMarkers(wordRange.get(), DocumentMarker::Spelling); - if (RefPtr<Range> sentenceRange = newSelectedSentence.toRange()) - document()->removeMarkers(sentenceRange.get(), DocumentMarker::Grammar); - } - - // When continuous spell checking is off, existing markers disappear after the selection changes. - if (!isContinuousSpellCheckingEnabled) - document()->removeMarkers(DocumentMarker::Spelling); - if (!isContinuousGrammarCheckingEnabled) - document()->removeMarkers(DocumentMarker::Grammar); - } - - editor()->respondToChangedSelection(oldSelection); -} - -VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint) -{ - HitTestResult result = eventHandler()->hitTestResultAtPoint(framePoint, true); - Node* node = result.innerNode(); - if (!node) - return VisiblePosition(); - RenderObject* renderer = node->renderer(); - if (!renderer) - return VisiblePosition(); - VisiblePosition visiblePos = renderer->positionForCoordinates(result.localPoint().x(), result.localPoint().y()); - if (visiblePos.isNull()) - visiblePos = VisiblePosition(Position(node, 0)); - return visiblePos; -} - -Document* Frame::documentAtPoint(const IntPoint& point) -{ - if (!view()) - return 0; - - IntPoint pt = view()->windowToContents(point); - HitTestResult result = HitTestResult(pt); - - if (contentRenderer()) - result = eventHandler()->hitTestResultAtPoint(pt, false); - return result.innerNode() ? result.innerNode()->document() : 0; -} - -FramePrivate::FramePrivate(Page* page, Frame* parent, Frame* thisFrame, HTMLFrameOwnerElement* ownerElement, - FrameLoaderClient* frameLoaderClient) - : m_page(page) - , m_treeNode(thisFrame, parent) - , m_loader(thisFrame, frameLoaderClient) - , m_ownerElement(ownerElement) - , m_script(thisFrame) - , m_zoomFactor(parent ? parent->d->m_zoomFactor : 1.0f) - , m_selectionGranularity(CharacterGranularity) - , m_selectionController(thisFrame) - , m_caretBlinkTimer(thisFrame, &Frame::caretBlinkTimerFired) - , m_editor(thisFrame) - , m_eventHandler(thisFrame) - , m_animationController(thisFrame) - , m_lifeSupportTimer(thisFrame, &Frame::lifeSupportTimerFired) - , m_paintRestriction(PaintRestrictionNone) - , m_caretVisible(false) - , m_caretPaint(true) - , m_isPainting(false) - , m_highlightTextMatches(false) - , m_inViewSourceMode(false) - , m_prohibitsScrolling(false) - , m_needsReapplyStyles(false) - , m_isDisconnected(false) - , m_excludeFromTextSearch(false) -#if FRAME_LOADS_USER_STYLESHEET - , m_userStyleSheetLoader(0) -#endif -{ -} - -FramePrivate::~FramePrivate() -{ -} - -} // namespace WebCore diff --git a/webkit/pending/FrameLoader.cpp b/webkit/pending/FrameLoader.cpp deleted file mode 100644 index a5d1f27..0000000 --- a/webkit/pending/FrameLoader.cpp +++ /dev/null @@ -1,5186 +0,0 @@ -/* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2007 Trolltech ASA - * - * 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 "FrameLoader.h" - -#include "Archive.h" -#include "ArchiveFactory.h" -#include "CString.h" -#include "Cache.h" -#include "CachedPage.h" -#include "Chrome.h" -#include "DOMImplementation.h" -#include "DOMWindow.h" -#include "DocLoader.h" -#include "Document.h" -#include "DocumentLoader.h" -#include "Editor.h" -#include "EditorClient.h" -#include "Element.h" -#include "Event.h" -#include "EventNames.h" -#include "FloatRect.h" -#include "FormState.h" -#include "Frame.h" -#include "FrameLoadRequest.h" -#include "FrameLoaderClient.h" -#include "FramePrivate.h" -#include "FrameTree.h" -#include "FrameView.h" -#include "HTMLFormElement.h" -#include "HTMLFrameElement.h" -#include "HTMLNames.h" -#include "HTMLObjectElement.h" -#include "HTTPParsers.h" -#include "HistoryItem.h" -#include "IconDatabase.h" -#include "IconLoader.h" -#include "InspectorController.h" -#include "Logging.h" -#include "MIMETypeRegistry.h" -#include "MainResourceLoader.h" -#include "Page.h" -#include "PageCache.h" -#include "PageGroup.h" -#include "PluginData.h" -#include "ProgressTracker.h" -#include "RenderPart.h" -#include "RenderWidget.h" -#include "RenderView.h" -#include "ResourceHandle.h" -#include "ResourceRequest.h" -#include "SecurityOrigin.h" -#include "SegmentedString.h" -#include "Settings.h" -#include "SystemTime.h" -#include "TextResourceDecoder.h" -#include "WindowFeatures.h" -#include "XMLHttpRequest.h" -#include "XMLTokenizer.h" -#include "ScriptController.h" - -#if USE(JSC) -#include "JSDOMBinding.h" -#include <kjs/JSObject.h> -#endif - -#if ENABLE(OFFLINE_WEB_APPLICATIONS) -#include "ApplicationCache.h" -#include "ApplicationCacheResource.h" -#endif - -#if ENABLE(SVG) -#include "SVGDocument.h" -#include "SVGLocatable.h" -#include "SVGNames.h" -#include "SVGPreserveAspectRatio.h" -#include "SVGSVGElement.h" -#include "SVGViewElement.h" -#include "SVGViewSpec.h" -#endif - -namespace WebCore { - -#if ENABLE(SVG) -using namespace SVGNames; -#endif -using namespace HTMLNames; -using namespace EventNames; - -#if USE(LOW_BANDWIDTH_DISPLAY) -const unsigned int cMaxPendingSourceLengthInLowBandwidthDisplay = 128 * 1024; -#endif - -struct FormSubmission { - const char* action; - String url; - RefPtr<FormData> data; - String target; - String contentType; - String boundary; - RefPtr<Event> event; - - FormSubmission(const char* a, const String& u, PassRefPtr<FormData> d, const String& t, - const String& ct, const String& b, PassRefPtr<Event> e) - : action(a) - , url(u) - , data(d) - , target(t) - , contentType(ct) - , boundary(b) - , event(e) - { - } -}; - -struct ScheduledRedirection { - enum Type { redirection, locationChange, historyNavigation, locationChangeDuringLoad, reload }; - Type type; - double delay; - String url; - String referrer; - bool lockHistory; - bool wasUserGesture; - RefPtr<HistoryItem> historyItem; - - ScheduledRedirection(double redirectDelay, const String& redirectURL, bool redirectLockHistory, bool userGesture) - : type(redirection) - , delay(redirectDelay) - , url(redirectURL) - , lockHistory(redirectLockHistory) - , wasUserGesture(userGesture) - { - } - - ScheduledRedirection(Type locationChangeType, - const String& locationChangeURL, const String& locationChangeReferrer, - bool locationChangeLockHistory, bool locationChangeWasUserGesture) - : type(locationChangeType) - , delay(0) - , url(locationChangeURL) - , referrer(locationChangeReferrer) - , lockHistory(locationChangeLockHistory) - , wasUserGesture(locationChangeWasUserGesture) - { - } - - explicit ScheduledRedirection(HistoryItem* item) - : type(historyNavigation) - , delay(0) - , lockHistory(false) - , wasUserGesture(false) - , historyItem(item) - { - } -}; - -static double storedTimeOfLastCompletedLoad; -static FrameLoader::LocalLoadPolicy localLoadPolicy = FrameLoader::AllowLocalLoadsForLocalOnly; - -bool isBackForwardLoadType(FrameLoadType type) -{ - switch (type) { - case FrameLoadTypeStandard: - case FrameLoadTypeReload: - case FrameLoadTypeReloadAllowingStaleData: - case FrameLoadTypeSame: - case FrameLoadTypeRedirectWithLockedHistory: - case FrameLoadTypeReplace: - return false; - case FrameLoadTypeBack: - case FrameLoadTypeForward: - case FrameLoadTypeIndexedBackForward: - return true; - } - ASSERT_NOT_REACHED(); - return false; -} - -static int numRequests(Document* document) -{ - if (!document) - return 0; - - return document->docLoader()->requestCount(); -} - -FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client) - : m_frame(frame) - , m_client(client) - , m_state(FrameStateCommittedPage) - , m_loadType(FrameLoadTypeStandard) - , m_policyLoadType(FrameLoadTypeStandard) - , m_delegateIsHandlingProvisionalLoadError(false) - , m_delegateIsDecidingNavigationPolicy(false) - , m_delegateIsHandlingUnimplementablePolicy(false) - , m_firstLayoutDone(false) - , m_quickRedirectComing(false) - , m_sentRedirectNotification(false) - , m_inStopAllLoaders(false) - , m_navigationDuringLoad(false) - , m_cachePolicy(CachePolicyVerify) - , m_isExecutingJavaScriptFormAction(false) - , m_isRunningScript(false) - , m_didCallImplicitClose(false) - , m_wasUnloadEventEmitted(false) - , m_isComplete(false) - , m_isLoadingMainResource(false) - , m_firingUnloadEvents(false) - , m_cancellingWithLoadInProgress(false) - , m_needsClear(false) - , m_receivedData(false) - , m_encodingWasChosenByUser(false) - , m_containsPlugIns(false) - , m_redirectionTimer(this, &FrameLoader::redirectionTimerFired) - , m_checkCompletedTimer(this, &FrameLoader::checkCompletedTimerFired) - , m_checkLoadCompleteTimer(this, &FrameLoader::checkLoadCompleteTimerFired) - , m_opener(0) - , m_openedByDOM(false) - , m_creatingInitialEmptyDocument(false) - , m_isDisplayingInitialEmptyDocument(false) - , m_committedFirstRealDocumentLoad(false) - , m_didPerformFirstNavigation(false) -#ifndef NDEBUG - , m_didDispatchDidCommitLoad(false) -#endif -#if USE(LOW_BANDWIDTH_DISPLAY) - , m_useLowBandwidthDisplay(true) - , m_finishedParsingDuringLowBandwidthDisplay(false) - , m_needToSwitchOutLowBandwidthDisplay(false) -#endif -{ -} - -FrameLoader::~FrameLoader() -{ - setOpener(0); - - HashSet<Frame*>::iterator end = m_openedFrames.end(); - for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it) - (*it)->loader()->m_opener = 0; - - m_client->frameLoaderDestroyed(); -} - -void FrameLoader::init() -{ - // this somewhat odd set of steps is needed to give the frame an initial empty document - m_isDisplayingInitialEmptyDocument = false; - m_creatingInitialEmptyDocument = true; - setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(String("")), SubstituteData()).get()); - setProvisionalDocumentLoader(m_policyDocumentLoader.get()); - setState(FrameStateProvisional); - m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String())); - m_provisionalDocumentLoader->finishedLoading(); - begin(KURL(), false); - end(); - m_frame->document()->cancelParsing(); - m_creatingInitialEmptyDocument = false; - m_didCallImplicitClose = true; -} - -void FrameLoader::setDefersLoading(bool defers) -{ - if (m_documentLoader) - m_documentLoader->setDefersLoading(defers); - if (m_provisionalDocumentLoader) - m_provisionalDocumentLoader->setDefersLoading(defers); - if (m_policyDocumentLoader) - m_policyDocumentLoader->setDefersLoading(defers); -} - -Frame* FrameLoader::createWindow(FrameLoader* frameLoaderForFrameLookup, const FrameLoadRequest& request, const WindowFeatures& features, bool& created) -{ - ASSERT(!features.dialog || request.frameName().isEmpty()); - - if (!request.frameName().isEmpty() && request.frameName() != "_blank") { - Frame* frame = frameLoaderForFrameLookup->frame()->tree()->find(request.frameName()); - if (frame && shouldAllowNavigation(frame)) { - if (!request.resourceRequest().url().isEmpty()) - frame->loader()->loadFrameRequestWithFormAndValues(request, false, 0, 0, HashMap<String, String>()); - if (Page* page = frame->page()) - page->chrome()->focus(); - created = false; - return frame; - } - } - - // FIXME: Setting the referrer should be the caller's responsibility. - FrameLoadRequest requestWithReferrer = request; - requestWithReferrer.resourceRequest().setHTTPReferrer(m_outgoingReferrer); - - Page* oldPage = m_frame->page(); - if (!oldPage) - return 0; - - Page* page = oldPage->chrome()->createWindow(m_frame, requestWithReferrer, features); - if (!page) - return 0; - - Frame* frame = page->mainFrame(); - if (request.frameName() != "_blank") - frame->tree()->setName(request.frameName()); - - page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locationBarVisible); - page->chrome()->setStatusbarVisible(features.statusBarVisible); - page->chrome()->setScrollbarsVisible(features.scrollbarsVisible); - page->chrome()->setMenubarVisible(features.menuBarVisible); - page->chrome()->setResizable(features.resizable); - - // 'x' and 'y' specify the location of the window, while 'width' and 'height' - // specify the size of the page. We can only resize the window, so - // adjust for the difference between the window size and the page size. - - FloatRect windowRect = page->chrome()->windowRect(); - FloatSize pageSize = page->chrome()->pageRect().size(); - if (features.xSet) - windowRect.setX(features.x); - if (features.ySet) - windowRect.setY(features.y); - if (features.widthSet) - windowRect.setWidth(features.width + (windowRect.width() - pageSize.width())); - if (features.heightSet) - windowRect.setHeight(features.height + (windowRect.height() - pageSize.height())); - page->chrome()->setWindowRect(windowRect); - - page->chrome()->show(); - - created = true; - return frame; -} - -bool FrameLoader::canHandleRequest(const ResourceRequest& request) -{ - return m_client->canHandleRequest(request); -} - -void FrameLoader::changeLocation(const String& url, const String& referrer, bool lockHistory, bool userGesture) -{ - // http://b/1082089 - // Hack to prevent FMW in WebCore::FrameLoader::checkNavigationPolicy. - // Without this, if the frame's javascript onload handler removes the frame, - // then once control returns into FrameLoader::checkNavigationPolicy (from - // the call to m_client->dispatchDecidePolicyForNavigationAction()), - // 'this' has been deallocated and we trash memory. - RefPtr<Frame> protector(m_frame); - - changeLocation(completeURL(url), referrer, lockHistory, userGesture); -} - - -void FrameLoader::changeLocation(const KURL& url, const String& referrer, bool lockHistory, bool userGesture) -{ - ResourceRequestCachePolicy policy = (m_cachePolicy == CachePolicyReload) || (m_cachePolicy == CachePolicyRefresh) - ? ReloadIgnoringCacheData : UseProtocolCachePolicy; - ResourceRequest request(url, referrer, policy); - - if (executeIfJavaScriptURL(request.url(), userGesture)) - return; - - urlSelected(request, "_self", 0, lockHistory, userGesture); -} - -void FrameLoader::urlSelected(const FrameLoadRequest& request, Event* event, bool lockHistory) -{ - FrameLoadRequest copy = request; - if (copy.resourceRequest().httpReferrer().isEmpty()) - copy.resourceRequest().setHTTPReferrer(m_outgoingReferrer); - - loadFrameRequestWithFormAndValues(copy, lockHistory, event, 0, HashMap<String, String>()); -} - -void FrameLoader::urlSelected(const ResourceRequest& request, const String& _target, Event* triggeringEvent, bool lockHistory, bool userGesture) -{ - if (executeIfJavaScriptURL(request.url(), userGesture, false)) - return; - - String target = _target; - if (target.isEmpty() && m_frame->document()) - target = m_frame->document()->baseTarget(); - - FrameLoadRequest frameRequest(request, target); - - urlSelected(frameRequest, triggeringEvent, lockHistory); -} - -bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName) -{ -#if USE(LOW_BANDWIDTH_DISPLAY) - // don't create sub-frame during low bandwidth display - if (frame()->document()->inLowBandwidthDisplay()) { - m_needToSwitchOutLowBandwidthDisplay = true; - return false; - } -#endif - - // Support for <frame src="javascript:string"> - KURL scriptURL; - KURL url; - if (protocolIs(urlString, "javascript")) { - scriptURL = KURL(urlString); - url = blankURL(); - } else - url = completeURL(urlString); - - Frame* frame = ownerElement->contentFrame(); - if (frame) - frame->loader()->scheduleLocationChange(url.string(), m_outgoingReferrer, true, userGestureHint()); - else - frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer); - - if (!frame) - return false; - - if (!scriptURL.isEmpty()) - frame->loader()->executeIfJavaScriptURL(scriptURL); - - return true; -} - -Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer) -{ - bool allowsScrolling = true; - int marginWidth = -1; - int marginHeight = -1; - if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) { - HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement); - allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff; - marginWidth = o->getMarginWidth(); - marginHeight = o->getMarginHeight(); - } - - if (!canLoad(url, referrer)) { - FrameLoader::reportLocalLoadFailed(m_frame, url.string()); - return 0; - } - - bool hideReferrer = shouldHideReferrer(url, referrer); - RefPtr<Frame> frame = m_client->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer, - allowsScrolling, marginWidth, marginHeight); - - if (!frame) { - checkCallImplicitClose(); - return 0; - } - - frame->loader()->m_isComplete = false; - - RenderObject* renderer = ownerElement->renderer(); - FrameView* view = frame->view(); - if (renderer && renderer->isWidget() && view) - static_cast<RenderWidget*>(renderer)->setWidget(view); - - checkCallImplicitClose(); - - // In these cases, the synchronous load would have finished - // before we could connect the signals, so make sure to send the - // completed() signal for the child by hand - // FIXME: In this case the Frame will have finished loading before - // it's being added to the child list. It would be a good idea to - // create the child first, then invoke the loader separately. - if (url.isEmpty() || url == blankURL()) { - frame->loader()->completed(); - frame->loader()->checkCompleted(); - } - - return frame.get(); -} - -void FrameLoader::submitFormAgain() -{ - if (m_isRunningScript) - return; - OwnPtr<FormSubmission> form(m_deferredFormSubmission.release()); - if (form) - submitForm(form->action, form->url, form->data, form->target, - form->contentType, form->boundary, form->event.get()); -} - -void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<FormData> formData, - const String& target, const String& contentType, const String& boundary, Event* event) -{ - ASSERT(formData); - - if (!m_frame->page()) - return; - - KURL u = completeURL(url.isNull() ? "" : url); - // FIXME: Do we really need to special-case an empty URL? - // Would it be better to just go on with the form submisson and let the I/O fail? - if (u.isEmpty()) - return; - - if (u.protocolIs("javascript")) { - m_isExecutingJavaScriptFormAction = true; - executeIfJavaScriptURL(u, false, false); - m_isExecutingJavaScriptFormAction = false; - return; - } - - if (m_isRunningScript) { - if (m_deferredFormSubmission) - return; - m_deferredFormSubmission.set(new FormSubmission(action, url, formData, target, - contentType, boundary, event)); - return; - } - - formData->generateFiles(m_frame->page()->chrome()->client()); - - FrameLoadRequest frameRequest; - - if (!m_outgoingReferrer.isEmpty()) - frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer); - - frameRequest.setFrameName(target.isEmpty() ? m_frame->document()->baseTarget() : target); - - // Handle mailto: forms - bool isMailtoForm = equalIgnoringCase(u.protocol(), "mailto"); - if (isMailtoForm && strcmp(action, "GET") != 0) { - // Append body= for POST mailto, replace the whole query string for GET one. - String body = formData->flattenToString(); - String query = u.query(); - if (!query.isEmpty()) - query.append('&'); - u.setQuery(query + body); - } - - if (strcmp(action, "GET") == 0) { - u.setQuery(formData->flattenToString()); - } else { - if (!isMailtoForm) - frameRequest.resourceRequest().setHTTPBody(formData.get()); - frameRequest.resourceRequest().setHTTPMethod("POST"); - - // construct some user headers if necessary - if (contentType.isNull() || contentType == "application/x-www-form-urlencoded") - frameRequest.resourceRequest().setHTTPContentType(contentType); - else // contentType must be "multipart/form-data" - frameRequest.resourceRequest().setHTTPContentType(contentType + "; boundary=" + boundary); - } - - frameRequest.resourceRequest().setURL(u); - - submitForm(frameRequest, event); -} - -void FrameLoader::stopLoading(bool sendUnload) -{ - if (m_frame->document() && m_frame->document()->tokenizer()) - m_frame->document()->tokenizer()->stopParsing(); - - if (sendUnload) { - if (m_frame->document()) { - if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) { - Node* currentFocusedNode = m_frame->document()->focusedNode(); - if (currentFocusedNode) - currentFocusedNode->aboutToUnload(); - setFiringUnloadEvents(true); - m_frame->document()->dispatchWindowEvent(unloadEvent, false, false); - setFiringUnloadEvents(false); - if (m_frame->document()) - m_frame->document()->updateRendering(); - m_wasUnloadEventEmitted = true; - if (m_frame->eventHandler()->pendingFrameUnloadEventCount()) - m_frame->eventHandler()->clearPendingFrameUnloadEventCount(); - if (m_frame->eventHandler()->pendingFrameBeforeUnloadEventCount()) - m_frame->eventHandler()->clearPendingFrameBeforeUnloadEventCount(); - } - } - if (m_frame->document() && !m_frame->document()->inPageCache()) - m_frame->document()->removeAllEventListenersFromAllNodes(); - } - - m_isComplete = true; // to avoid calling completed() in finishedParsing() (David) - m_isLoadingMainResource = false; - m_didCallImplicitClose = true; // don't want that one either - m_cachePolicy = CachePolicyVerify; // Why here? - - if (m_frame->document() && m_frame->document()->parsing()) { - finishedParsing(); - m_frame->document()->setParsing(false); - } - - m_workingURL = KURL(); - - if (Document* doc = m_frame->document()) { - if (DocLoader* docLoader = doc->docLoader()) - cache()->loader()->cancelRequests(docLoader); - XMLHttpRequest::cancelRequests(doc); -#if ENABLE(DATABASE) -#endif - } - - // tell all subframes to stop as well - for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) - child->loader()->stopLoading(sendUnload); - - cancelRedirection(); - -#if USE(LOW_BANDWIDTH_DISPLAY) - if (m_frame->document() && m_frame->document()->inLowBandwidthDisplay()) { - // Since loading is forced to stop, reset the state without really switching. - m_needToSwitchOutLowBandwidthDisplay = false; - switchOutLowBandwidthDisplayIfReady(); - } -#endif -} - -void FrameLoader::stop() -{ - // http://bugs.webkit.org/show_bug.cgi?id=10854 - // The frame's last ref may be removed and it will be deleted by checkCompleted(). - RefPtr<Frame> protector(m_frame); - - if (m_frame->document()) { - if (m_frame->document()->tokenizer()) - m_frame->document()->tokenizer()->stopParsing(); - m_frame->document()->finishParsing(); - } else - // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but - // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to - // become true. An example is when a subframe is a pure text doc, and that subframe is the - // last one to complete. - checkCompleted(); - if (m_iconLoader) - m_iconLoader->stopLoading(); -} - -bool FrameLoader::closeURL() -{ - saveDocumentState(); - stopLoading(true); - m_frame->editor()->clearUndoRedoOperations(); - return true; -} - -void FrameLoader::cancelRedirection(bool cancelWithLoadInProgress) -{ - m_cancellingWithLoadInProgress = cancelWithLoadInProgress; - - stopRedirectionTimer(); - - m_scheduledRedirection.clear(); -} - -KURL FrameLoader::iconURL() -{ - // If this isn't a top level frame, return nothing - if (m_frame->tree() && m_frame->tree()->parent()) - return KURL(); - - // If we have an iconURL from a Link element, return that - if (m_frame->document() && !m_frame->document()->iconURL().isEmpty()) - return KURL(m_frame->document()->iconURL()); - - // Don't return a favicon iconURL unless we're http or https - if (!m_URL.protocolIs("http") && !m_URL.protocolIs("https")) - return KURL(); - - KURL url; - url.setProtocol(m_URL.protocol()); - url.setHost(m_URL.host()); - if (int port = m_URL.port()) - url.setPort(port); - url.setPath("/favicon.ico"); - return url; -} - -bool FrameLoader::didOpenURL(const KURL& url) -{ - if (m_scheduledRedirection && m_scheduledRedirection->type == ScheduledRedirection::locationChangeDuringLoad) - // A redirect was scheduled before the document was created. - // This can happen when one frame changes another frame's location. - return false; - - cancelRedirection(); - m_frame->editor()->clearLastEditCommand(); - closeURL(); - - m_isComplete = false; - m_isLoadingMainResource = true; - m_didCallImplicitClose = false; - - m_frame->setJSStatusBarText(String()); - m_frame->setJSDefaultStatusBarText(String()); - - m_URL = url; - if ((m_URL.protocolIs("http") || m_URL.protocolIs("https")) && !m_URL.host().isEmpty() && m_URL.path().isEmpty()) - m_URL.setPath("/"); - m_workingURL = m_URL; - - started(); - - return true; -} - -void FrameLoader::didExplicitOpen() -{ - m_isComplete = false; - m_didCallImplicitClose = false; - - // Calling document.open counts as committing the first real document load. - m_committedFirstRealDocumentLoad = true; - - // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results - // from a subsequent window.document.open / window.document.write call. - // Cancelling redirection here works for all cases because document.open - // implicitly precedes document.write. - cancelRedirection(); - if (m_frame->document()->url() != blankURL()) - m_URL = m_frame->document()->url(); -} - -bool FrameLoader::executeIfJavaScriptURL(const KURL& url, bool userGesture, bool replaceDocument) -{ - if (!url.protocolIs("javascript")) - return false; - - String script = decodeURLEscapeSequences(url.string().substring(strlen("javascript:"))); - - bool succ; - String scriptResult = executeScript(script, &succ, userGesture); - if (!succ) return true; - - SecurityOrigin* currentSecurityOrigin = 0; - if (m_frame->document()) - currentSecurityOrigin = m_frame->document()->securityOrigin(); - - // FIXME: We should always replace the document, but doing so - // synchronously can cause crashes: - // http://bugs.webkit.org/show_bug.cgi?id=16782 - if (replaceDocument) { - begin(m_URL, true, currentSecurityOrigin); - write(scriptResult); - end(); - } - - return true; -} - -void FrameLoader::executeScript(const String& url, int baseLine, const String& script) { - bool succ; - executeScript(url, baseLine, script, &succ); -} - -void FrameLoader::executeScript(const String& script, bool forceUserGesture) -{ - bool succ; - executeScript(forceUserGesture ? String() : m_URL.string(), 0, script, &succ); -} - -String FrameLoader::executeScript(const String& script, bool* succ, bool forceUserGesture) -{ - return executeScript(forceUserGesture ? String() : m_URL.string(), 1, script, succ); -} - -String FrameLoader::executeScript(const String& url, int baseLine, const String& script, bool* succ) -{ - *succ = false; - if (!m_frame->script()->isEnabled() || m_frame->script()->isPaused()) - return String(); - - bool wasRunningScript = m_isRunningScript; - m_isRunningScript = true; - - String result = m_frame->script()->evaluate(url, baseLine, script, 0, succ); - - if (!wasRunningScript) { - m_isRunningScript = false; - submitFormAgain(); - Document::updateDocumentsRendering(); - } - - return result; -} - -void FrameLoader::cancelAndClear() -{ - cancelRedirection(); - - if (!m_isComplete) - closeURL(); - - clear(false); -} - -void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects) -{ - // FIXME: Commenting out the below line causes <http://bugs.webkit.org/show_bug.cgi?id=11212>, but putting it - // back causes a measurable performance regression which we will need to fix to restore the correct behavior - // urlsBridgeKnowsAbout.clear(); - - m_frame->editor()->clear(); - - if (!m_needsClear) - return; - m_needsClear = false; - - if (m_frame->document() && !m_frame->document()->inPageCache()) { - m_frame->document()->cancelParsing(); - if (m_frame->document()->attached()) { - m_frame->document()->willRemove(); - m_frame->document()->detach(); - - m_frame->document()->removeFocusedNodeOfSubtree(m_frame->document()); - } - } - - // Do this after detaching the document so that the unload event works. - if (clearWindowProperties) { - m_frame->clearDOMWindow(); - m_frame->script()->clearWindowShell(); - } - - m_frame->selection()->clear(); - m_frame->eventHandler()->clear(); - if (m_frame->view()) - m_frame->view()->clear(); - - m_frame->setSelectionGranularity(CharacterGranularity); - - // Do not drop the document before the ScriptController and view are cleared - // as some destructors might still try to access the document. - m_frame->setDocument(0); - m_decoder = 0; - - m_containsPlugIns = false; - - if (clearScriptObjects) - m_frame->script()->clearScriptObjects(); - - m_redirectionTimer.stop(); - m_scheduledRedirection.clear(); - - m_checkCompletedTimer.stop(); - m_checkLoadCompleteTimer.stop(); - - m_receivedData = false; - m_isDisplayingInitialEmptyDocument = false; - - if (!m_encodingWasChosenByUser) - m_encoding = String(); -} - -void FrameLoader::receivedFirstData() -{ - begin(m_workingURL, false); - - dispatchDidCommitLoad(); - dispatchWindowObjectAvailable(); - - String ptitle = m_documentLoader->title(); - // If we have a title let the WebView know about it. - if (!ptitle.isNull()) - m_client->dispatchDidReceiveTitle(ptitle); - - m_frame->document()->docLoader()->setCachePolicy(m_cachePolicy); - m_workingURL = KURL(); - - double delay; - String url; - if (!m_documentLoader) - return; - if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, url)) - return; - - if (url.isEmpty()) - url = m_URL.string(); - else - url = m_frame->document()->completeURL(url).string(); - - scheduleHTTPRedirection(delay, url); -} - -const String& FrameLoader::responseMIMEType() const -{ - return m_responseMIMEType; -} - -void FrameLoader::setResponseMIMEType(const String& type) -{ - m_responseMIMEType = type; -} - -void FrameLoader::begin() -{ - begin(KURL()); -} - -void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin) -{ - // We need to take a reference to the security origin because |clear| - // might destroy the document that owns it. - RefPtr<SecurityOrigin> forcedSecurityOrigin = origin; - - bool resetScripting = !(m_isDisplayingInitialEmptyDocument && m_frame->document() && m_frame->document()->securityOrigin()->isSecureTransitionTo(url)); - clear(resetScripting, resetScripting); - if (dispatch) - dispatchWindowObjectAvailable(); - - m_needsClear = true; - m_isComplete = false; - m_didCallImplicitClose = false; - m_isLoadingMainResource = true; - m_isDisplayingInitialEmptyDocument = m_creatingInitialEmptyDocument; - - KURL ref(url); - ref.setUser(String()); - ref.setPass(String()); - ref.setRef(String()); - m_outgoingReferrer = ref.string(); - m_URL = url; - - RefPtr<Document> document = DOMImplementation::createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode()); - m_frame->setDocument(document); - - document->setURL(m_URL); - if (m_decoder) - document->setDecoder(m_decoder.get()); - if (forcedSecurityOrigin) - document->setSecurityOrigin(forcedSecurityOrigin.get()); - - m_frame->domWindow()->setURL(document->url()); - m_frame->domWindow()->setSecurityOrigin(document->securityOrigin()); - - updatePolicyBaseURL(); - - Settings* settings = document->settings(); - document->docLoader()->setAutoLoadImages(settings && settings->loadsImagesAutomatically()); - - if (m_documentLoader) { - String dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control"); - if (!dnsPrefetchControl.isEmpty()) - document->setDNSPrefetchControl(dnsPrefetchControl); - } - -#if FRAME_LOADS_USER_STYLESHEET - KURL userStyleSheet = settings ? settings->userStyleSheetLocation() : KURL(); - if (!userStyleSheet.isEmpty()) - m_frame->setUserStyleSheetLocation(userStyleSheet); -#endif - - restoreDocumentState(); - - document->implicitOpen(); - - if (m_frame->view()) - m_frame->view()->resizeContents(0, 0); - -#if USE(LOW_BANDWIDTH_DISPLAY) - // Low bandwidth display is a first pass display without external resources - // used to give an instant visual feedback. We currently only enable it for - // HTML documents in the top frame. - if (document->isHTMLDocument() && !m_frame->tree()->parent() && m_useLowBandwidthDisplay) { - m_pendingSourceInLowBandwidthDisplay = String(); - m_finishedParsingDuringLowBandwidthDisplay = false; - m_needToSwitchOutLowBandwidthDisplay = false; - document->setLowBandwidthDisplay(true); - } -#endif -} - -void FrameLoader::write(const char* str, int len, bool flush) -{ - if (len == 0 && !flush) - return; - - if (len == -1) - len = strlen(str); - - Tokenizer* tokenizer = m_frame->document()->tokenizer(); - if (tokenizer && tokenizer->wantsRawData()) { - if (len > 0) - tokenizer->writeRawData(str, len); - return; - } - - if (!m_decoder) { - Settings* settings = m_frame->settings(); - if (settings) { - TextResourceDecoder* hintDecoder = NULL; - Frame* parentFrame = m_frame->tree()->parent(); - if (parentFrame && parentFrame->document()) - hintDecoder = parentFrame->document()->decoder(); - m_decoder = TextResourceDecoder::create(m_responseMIMEType, settings->defaultTextEncodingName(), settings->usesEncodingDetector(), hintDecoder); - } else - m_decoder = TextResourceDecoder::create(m_responseMIMEType, String()); - if (m_encoding.isEmpty()) { - Frame* parentFrame = m_frame->tree()->parent(); - // TODO(jungshik) : We might as well consider allowing inheriting charset - // from parent even if canAccess returns false as long as the parent charset - // is regarded as safe (that is, it's not UTF-7/ISO-2022-XX/HZ), of which - // we're not yet sure. - if (parentFrame && parentFrame->document()->securityOrigin()->canAccess(m_frame->document()->securityOrigin())) - m_decoder->setEncoding(parentFrame->document()->inputEncoding(), TextResourceDecoder::EncodingFromParentFrame); - } else { - m_decoder->setEncoding(m_encoding, - m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader); - } - m_frame->document()->setDecoder(m_decoder.get()); - } - - String decoded = m_decoder->decode(str, len); - if (flush) - decoded += m_decoder->flush(); - if (decoded.isEmpty()) - return; - -#if USE(LOW_BANDWIDTH_DISPLAY) - if (m_frame->document()->inLowBandwidthDisplay()) - m_pendingSourceInLowBandwidthDisplay.append(decoded); - else // reset policy which is changed in switchOutLowBandwidthDisplayIfReady() - m_frame->document()->docLoader()->setCachePolicy(m_cachePolicy); -#endif - - if (!m_receivedData) { - m_receivedData = true; - if (m_decoder->encoding().usesVisualOrdering()) - m_frame->document()->setVisuallyOrdered(); - m_frame->document()->recalcStyle(Node::Force); - } - - if (tokenizer) { - ASSERT(!tokenizer->wantsRawData()); - tokenizer->write(decoded, true); - } -} - -void FrameLoader::write(const String& str) -{ - if (str.isNull()) - return; - - if (!m_receivedData) { - m_receivedData = true; - m_frame->document()->setParseMode(Document::Strict); - } - - if (Tokenizer* tokenizer = m_frame->document()->tokenizer()) - tokenizer->write(str, true); -} - -void FrameLoader::end() -{ - m_isLoadingMainResource = false; - endIfNotLoadingMainResource(); -} - -void FrameLoader::endIfNotLoadingMainResource() -{ - if (m_isLoadingMainResource || !m_frame->page()) - return; - - // http://bugs.webkit.org/show_bug.cgi?id=10854 - // The frame's last ref may be removed and it can be deleted by checkCompleted(), - // so we'll add a protective refcount - RefPtr<Frame> protector(m_frame); - - // make sure nothing's left in there - if (m_frame->document()) { - write(0, 0, true); - m_frame->document()->finishParsing(); -#if USE(LOW_BANDWIDTH_DISPLAY) - if (m_frame->document()->inLowBandwidthDisplay()) { - m_finishedParsingDuringLowBandwidthDisplay = true; - switchOutLowBandwidthDisplayIfReady(); - } -#endif - } else - // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but - // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to - // become true. An example is when a subframe is a pure text doc, and that subframe is the - // last one to complete. - checkCompleted(); -} - -void FrameLoader::iconLoadDecisionAvailable() -{ - if (!m_mayLoadIconLater) - return; - LOG(IconDatabase, "FrameLoader %p was told a load decision is available for its icon", this); - startIconLoader(); - m_mayLoadIconLater = false; -} - -void FrameLoader::startIconLoader() -{ - // FIXME: We kick off the icon loader when the frame is done receiving its main resource. - // But we should instead do it when we're done parsing the head element. - if (!isLoadingMainFrame()) - return; - - if (!iconDatabase() || !iconDatabase()->isEnabled()) - return; - - KURL url(iconURL()); - String urlString(url.string()); - if (urlString.isEmpty()) - return; - - // If we're not reloading and the icon database doesn't say to load now then bail before we actually start the load - if (loadType() != FrameLoadTypeReload) { - IconLoadDecision decision = iconDatabase()->loadDecisionForIconURL(urlString, m_documentLoader.get()); - if (decision == IconLoadNo) { - LOG(IconDatabase, "FrameLoader::startIconLoader() - Told not to load this icon, committing iconURL %s to database for pageURL mapping", urlString.ascii().data()); - commitIconURLToIconDatabase(url); - - // We were told not to load this icon - that means this icon is already known by the database - // If the icon data hasn't been read in from disk yet, kick off the read of the icon from the database to make sure someone - // has done it. This is after registering for the notification so the WebView can call the appropriate delegate method. - // Otherwise if the icon data *is* available, notify the delegate - if (!iconDatabase()->iconDataKnownForIconURL(urlString)) { - LOG(IconDatabase, "Told not to load icon %s but icon data is not yet available - registering for notification and requesting load from disk", urlString.ascii().data()); - m_client->registerForIconNotification(); - iconDatabase()->iconForPageURL(m_URL.string(), IntSize(0, 0)); - iconDatabase()->iconForPageURL(originalRequestURL().string(), IntSize(0, 0)); - } else - m_client->dispatchDidReceiveIcon(); - - return; - } - - if (decision == IconLoadUnknown) { - // In this case, we may end up loading the icon later, but we still want to commit the icon url mapping to the database - // just in case we don't end up loading later - if we commit the mapping a second time after the load, that's no big deal - // We also tell the client to register for the notification that the icon is received now so it isn't missed in case the - // icon is later read in from disk - LOG(IconDatabase, "FrameLoader %p might load icon %s later", this, urlString.ascii().data()); - m_mayLoadIconLater = true; - m_client->registerForIconNotification(); - commitIconURLToIconDatabase(url); - return; - } - } - - // This is either a reload or the icon database said "yes, load the icon", so kick off the load! - if (!m_iconLoader) - m_iconLoader.set(IconLoader::create(m_frame).release()); - - m_iconLoader->startLoading(); -} - -void FrameLoader::setLocalLoadPolicy(LocalLoadPolicy policy) -{ - localLoadPolicy = policy; -} - -bool FrameLoader::restrictAccessToLocal() -{ - return localLoadPolicy != FrameLoader::AllowLocalLoadsForAll; -} - -bool FrameLoader::allowSubstituteDataAccessToLocal() -{ - return localLoadPolicy != FrameLoader::AllowLocalLoadsForLocalOnly; -} - -static HashSet<String, CaseFoldingHash>& localSchemes() -{ - static HashSet<String, CaseFoldingHash> localSchemes; - - if (localSchemes.isEmpty()) { - localSchemes.add("file"); - localSchemes.add("chrome-resource"); -#if PLATFORM(MAC) - localSchemes.add("applewebdata"); -#endif -#if PLATFORM(QT) - localSchemes.add("qrc"); -#endif - } - - return localSchemes; -} - -void FrameLoader::commitIconURLToIconDatabase(const KURL& icon) -{ - ASSERT(iconDatabase()); - LOG(IconDatabase, "Committing iconURL %s to database for pageURLs %s and %s", icon.string().ascii().data(), m_URL.string().ascii().data(), originalRequestURL().string().ascii().data()); - iconDatabase()->setIconURLForPageURL(icon.string(), m_URL.string()); - iconDatabase()->setIconURLForPageURL(icon.string(), originalRequestURL().string()); -} - -void FrameLoader::restoreDocumentState() -{ - Document* doc = m_frame->document(); - if (!doc) - return; - - HistoryItem* itemToRestore = 0; - - switch (loadType()) { - case FrameLoadTypeReload: - case FrameLoadTypeReloadAllowingStaleData: - case FrameLoadTypeSame: - case FrameLoadTypeReplace: - break; - case FrameLoadTypeBack: - case FrameLoadTypeForward: - case FrameLoadTypeIndexedBackForward: - case FrameLoadTypeRedirectWithLockedHistory: - case FrameLoadTypeStandard: - itemToRestore = m_currentHistoryItem.get(); - } - - if (!itemToRestore) - return; - - doc->setStateForNewFormElements(itemToRestore->documentState()); -} - -void FrameLoader::gotoAnchor() -{ - // If our URL has no ref, then we have no place we need to jump to. - // OTOH If CSS target was set previously, we want to set it to 0, recalc - // and possibly repaint because :target pseudo class may have been - // set (see bug 11321). - if (!m_URL.hasRef() && !(m_frame->document() && m_frame->document()->getCSSTarget())) - return; - - String ref = m_URL.ref(); - if (gotoAnchor(ref)) - return; - - // Try again after decoding the ref, based on the document's encoding. - if (m_decoder) - gotoAnchor(decodeURLEscapeSequences(ref, m_decoder->encoding())); -} - -void FrameLoader::finishedParsing() -{ - if (m_creatingInitialEmptyDocument) - return; - - // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves - // because doing so will cause us to re-enter the destructor when protector goes out of scope. - // Null-checking the FrameView indicates whether or not we're in the destructor. - RefPtr<Frame> protector = m_frame->view() ? m_frame : 0; - - checkCompleted(); - - if (!m_frame->view()) - return; // We are being destroyed by something checkCompleted called. - - // Check if the scrollbars are really needed for the content. - // If not, remove them, relayout, and repaint. - m_frame->view()->restoreScrollbar(); - - m_client->dispatchDidFinishDocumentLoad(); - - gotoAnchor(); -} - -void FrameLoader::loadDone() -{ - if (m_frame->document()) - checkCompleted(); -} - -void FrameLoader::checkCompleted() -{ - // Any frame that hasn't completed yet? - for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) - if (!child->loader()->m_isComplete) - return; - - // Have we completed before? - if (m_isComplete) - return; - - // Are we still parsing? - if (m_frame->document() && m_frame->document()->parsing()) - return; - - // Still waiting for images/scripts? - if (m_frame->document()) - if (numRequests(m_frame->document())) - return; - -#if USE(LOW_BANDWIDTH_DISPLAY) - // as switch will be called, don't complete yet - if (m_frame->document() && m_frame->document()->inLowBandwidthDisplay() && m_needToSwitchOutLowBandwidthDisplay) - return; -#endif - - // OK, completed. - m_isComplete = true; - - RefPtr<Frame> protect(m_frame); - checkCallImplicitClose(); // if we didn't do it before - - // Do not start a redirection timer for subframes here. - // That is deferred until the parent is completed. - if (m_scheduledRedirection && !m_frame->tree()->parent()) - startRedirectionTimer(); - - completed(); - if (m_frame->page()) - checkLoadComplete(); -} - -void FrameLoader::checkCompletedTimerFired(Timer<FrameLoader>*) -{ - checkCompleted(); -} - -void FrameLoader::scheduleCheckCompleted() -{ - if (!m_checkCompletedTimer.isActive()) - m_checkCompletedTimer.startOneShot(0); -} - -void FrameLoader::checkLoadCompleteTimerFired(Timer<FrameLoader>*) -{ - if (!m_frame->page()) - return; - checkLoadComplete(); -} - -void FrameLoader::scheduleCheckLoadComplete() -{ - if (!m_checkLoadCompleteTimer.isActive()) - m_checkLoadCompleteTimer.startOneShot(0); -} - -void FrameLoader::checkCallImplicitClose() -{ - if (m_didCallImplicitClose || !m_frame->document() || m_frame->document()->parsing()) - return; - - for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) - if (!child->loader()->m_isComplete) // still got a frame running -> too early - return; - - m_didCallImplicitClose = true; - m_wasUnloadEventEmitted = false; - if (m_frame->document()) - m_frame->document()->implicitClose(); -} - -KURL FrameLoader::baseURL() const -{ - ASSERT(m_frame->document()); - return m_frame->document()->baseURL(); -} - -String FrameLoader::baseTarget() const -{ - ASSERT(m_frame->document()); - return m_frame->document()->baseTarget(); -} - -KURL FrameLoader::completeURL(const String& url) -{ - ASSERT(m_frame->document()); - return m_frame->document()->completeURL(url); -} - -void FrameLoader::scheduleHTTPRedirection(double delay, const String& url) -{ - if (delay < 0 || delay > INT_MAX / 1000) - return; - - if (!m_frame->page()) - return; - - // We want a new history item if the refresh timeout is > 1 second. - if (!m_scheduledRedirection || delay <= m_scheduledRedirection->delay) - scheduleRedirection(new ScheduledRedirection(delay, url, delay <= 1, false)); -} - -void FrameLoader::scheduleLocationChange(const String& url, const String& referrer, bool lockHistory, bool wasUserGesture) -{ - if (!m_frame->page()) - return; - - // If the URL we're going to navigate to is the same as the current one, except for the - // fragment part, we don't need to schedule the location change. - KURL parsedURL(url); - if (parsedURL.hasRef() && equalIgnoringRef(m_URL, parsedURL)) { - changeLocation(url, referrer, lockHistory, wasUserGesture); - return; - } - - // Handle a location change of a page with no document as a special case. - // This may happen when a frame changes the location of another frame. - bool duringLoad = !m_committedFirstRealDocumentLoad; - - // If a redirect was scheduled during a load, then stop the current load. - // Otherwise when the current load transitions from a provisional to a - // committed state, pending redirects may be cancelled. - if (duringLoad) { - if (m_provisionalDocumentLoader) - m_provisionalDocumentLoader->stopLoading(); - stopLoading(true); - } - - ScheduledRedirection::Type type = duringLoad - ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection::locationChange; - scheduleRedirection(new ScheduledRedirection(type, url, referrer, lockHistory, wasUserGesture)); -} - -void FrameLoader::scheduleRefresh(bool wasUserGesture) -{ - if (!m_frame->page()) - return; - - // Handle a location change of a page with no document as a special case. - // This may happen when a frame requests a refresh of another frame. - bool duringLoad = !m_frame->document(); - - // If a refresh was scheduled during a load, then stop the current load. - // Otherwise when the current load transitions from a provisional to a - // committed state, pending redirects may be cancelled. - if (duringLoad) - stopLoading(true); - - ScheduledRedirection::Type type = duringLoad - ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection::locationChange; - scheduleRedirection(new ScheduledRedirection(type, m_URL.string(), m_outgoingReferrer, true, wasUserGesture)); - m_cachePolicy = CachePolicyRefresh; -} - -bool FrameLoader::isLocationChange(const ScheduledRedirection& redirection) -{ - switch (redirection.type) { - case ScheduledRedirection::redirection: - return false; - case ScheduledRedirection::reload: - case ScheduledRedirection::historyNavigation: - case ScheduledRedirection::locationChange: - case ScheduledRedirection::locationChangeDuringLoad: - return true; - } - ASSERT_NOT_REACHED(); - return false; -} - -void FrameLoader::scheduleHistoryNavigation(int steps) -{ - if (!m_frame->page()) - return; - - // navigation will always be allowed in the 0 steps case, which is OK because that's supposed to force a reload. - if (!canGoBackOrForward(steps)) { - cancelRedirection(); - return; - } - - if (steps == 0) { - // Special case for go(0) from a frame -> reload only the frame - scheduleRedirection(new ScheduledRedirection(ScheduledRedirection::reload, String(), String(), false, false)); - return; - } - - Page* page = m_frame->page(); - if (!page) - return; - BackForwardList* list = page->backForwardList(); - if (!list) - return; - - // Asynchronously loads the item at the given offset in the history. - list->goToItemAtIndexAsync(steps); - - // The redirection will be handled elsewhere. - cancelRedirection(); -} - -// This is called by ContextMenuController, which is only used in test shell -// and not Chrome. -void FrameLoader::goBackOrForward(int distance) -{ - if (distance == 0) - return; - - Page* page = m_frame->page(); - if (!page) - return; - BackForwardList* list = page->backForwardList(); - if (!list) - return; - - HistoryItem* item = list->itemAtIndex(distance); - if (!item) { - if (distance > 0) { - int forwardListCount = list->forwardListCount(); - if (forwardListCount > 0) - item = list->itemAtIndex(forwardListCount); - } else { - int backListCount = list->backListCount(); - if (backListCount > 0) - item = list->itemAtIndex(-backListCount); - } - } - - ASSERT(item); // we should not reach this line with an empty back/forward list - if (item) - page->goToItem(item, FrameLoadTypeIndexedBackForward); -} - -void FrameLoader::goToHistoryItem(HistoryItem* item) -{ - Page* page = m_frame->page(); - if (!page) - return; - - page->goToItem(item, FrameLoadTypeIndexedBackForward); -} - -void FrameLoader::redirectionTimerFired(Timer<FrameLoader>*) -{ - ASSERT(m_frame->page()); - - OwnPtr<ScheduledRedirection> redirection(m_scheduledRedirection.release()); - - switch (redirection->type) { - case ScheduledRedirection::redirection: - case ScheduledRedirection::locationChange: - case ScheduledRedirection::locationChangeDuringLoad: - changeLocation(redirection->url, redirection->referrer, - redirection->lockHistory, redirection->wasUserGesture); - return; - case ScheduledRedirection::reload: - urlSelected(m_URL, "", 0, false, false); - return; - case ScheduledRedirection::historyNavigation: - goToHistoryItem(redirection->historyItem.get()); - return; - } - - ASSERT_NOT_REACHED(); -} - -/* - In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree. - The item that was the target of the user's navigation is designated as the "targetItem". - When this method is called with doClip=YES we're able to create the whole tree except for the target's children, - which will be loaded in the future. That part of the tree will be filled out as the child loads are committed. -*/ -void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer, Frame* childFrame) -{ - ASSERT(childFrame); - HistoryItem* parentItem = currentHistoryItem(); - FrameLoadType loadType = this->loadType(); - FrameLoadType childLoadType = FrameLoadTypeRedirectWithLockedHistory; - - KURL workingURL = url; - - // If we're moving in the backforward list, we might want to replace the content - // of this child frame with whatever was there at that point. - // Reload will maintain the frame contents, LoadSame will not. - if (parentItem && parentItem->children().size() && - (isBackForwardLoadType(loadType) || loadType == FrameLoadTypeReloadAllowingStaleData)) - { - HistoryItem* childItem = parentItem->childItemWithName(childFrame->tree()->name()); - if (childItem) { - // Use the original URL to ensure we get all the side-effects, such as - // onLoad handlers, of any redirects that happened. An example of where - // this is needed is Radar 3213556. - workingURL = KURL(childItem->originalURLString()); - // These behaviors implied by these loadTypes should apply to the child frames - childLoadType = loadType; - - if (isBackForwardLoadType(loadType)) { - // For back/forward, remember this item so we can traverse any child items as child frames load - childFrame->loader()->setProvisionalHistoryItem(childItem); - } else { - // For reload, just reinstall the current item, since a new child frame was created but we won't be creating a new BF item - childFrame->loader()->setCurrentHistoryItem(childItem); - } - } - } - - RefPtr<Archive> subframeArchive = activeDocumentLoader()->popArchiveForSubframe(childFrame->tree()->name()); - - if (subframeArchive) - childFrame->loader()->loadArchive(subframeArchive.release()); - else - childFrame->loader()->loadURL(workingURL, referer, String(), childLoadType, 0, 0); -} - -void FrameLoader::loadArchive(PassRefPtr<Archive> prpArchive) -{ - RefPtr<Archive> archive = prpArchive; - - ArchiveResource* mainResource = archive->mainResource(); - ASSERT(mainResource); - if (!mainResource) - return; - - SubstituteData substituteData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), KURL()); - - ResourceRequest request(mainResource->url()); -#if PLATFORM(MAC) - request.applyWebArchiveHackForMail(); -#endif - - RefPtr<DocumentLoader> documentLoader = m_client->createDocumentLoader(request, substituteData); - documentLoader->addAllArchiveResources(archive.get()); - load(documentLoader.get()); -} - -String FrameLoader::encoding() const -{ - if (m_encodingWasChosenByUser && !m_encoding.isEmpty()) - return m_encoding; - if (m_decoder && m_decoder->encoding().isValid()) - return m_decoder->encoding().name(); - Settings* settings = m_frame->settings(); - return settings ? settings->defaultTextEncodingName() : String(); -} - -bool FrameLoader::gotoAnchor(const String& name) -{ - ASSERT(m_frame->document()); - - if (!m_frame->document()->haveStylesheetsLoaded()) { - m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true); - return false; - } - - m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false); - - Node* anchorNode = m_frame->document()->getElementById(AtomicString(name)); - if (!anchorNode && !name.isEmpty()) - anchorNode = m_frame->document()->anchors()->namedItem(name, !m_frame->document()->inCompatMode()); - -#if ENABLE(SVG) - if (m_frame->document()->isSVGDocument()) { - if (name.startsWith("xpointer(")) { - // We need to parse the xpointer reference here - } else if (name.startsWith("svgView(")) { - RefPtr<SVGSVGElement> svg = static_cast<SVGDocument*>(m_frame->document())->rootElement(); - if (!svg->currentView()->parseViewSpec(name)) - return false; - svg->setUseCurrentView(true); - } else { - if (anchorNode && anchorNode->hasTagName(SVGNames::viewTag)) { - RefPtr<SVGViewElement> viewElement = anchorNode->hasTagName(SVGNames::viewTag) ? static_cast<SVGViewElement*>(anchorNode) : 0; - if (viewElement.get()) { - RefPtr<SVGSVGElement> svg = static_cast<SVGSVGElement*>(SVGLocatable::nearestViewportElement(viewElement.get())); - svg->inheritViewAttributes(viewElement.get()); - } - } - } - // FIXME: need to decide which <svg> to focus on, and zoom to that one - // FIXME: need to actually "highlight" the viewTarget(s) - } -#endif - - m_frame->document()->setCSSTarget(anchorNode); // Setting to null will clear the current target. - - // Implement the rule that "" and "top" both mean top of page as in other browsers. - if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top"))) - return false; - - // We need to update the layout before scrolling, otherwise we could - // really mess things up if an anchor scroll comes at a bad moment. - if (m_frame->document()) { - m_frame->document()->updateRendering(); - // Only do a layout if changes have occurred that make it necessary. - if (m_frame->view() && m_frame->contentRenderer() && m_frame->contentRenderer()->needsLayout()) - m_frame->view()->layout(); - } - - // Scroll nested layers and frames to reveal the anchor. - // Align to the top and to the closest side (this matches other browsers). - RenderObject* renderer; - IntRect rect; - if (!anchorNode) - renderer = m_frame->document()->renderer(); // top of document - else { - renderer = anchorNode->renderer(); - rect = anchorNode->getRect(); - } - if (renderer) - renderer->enclosingLayer()->scrollRectToVisible(rect, true, RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignTopAlways); - - return true; -} - -bool FrameLoader::requestObject(RenderPart* renderer, const String& url, const AtomicString& frameName, - const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues) -{ - if (url.isEmpty() && mimeType.isEmpty()) - return false; - -#if USE(LOW_BANDWIDTH_DISPLAY) - // don't care object during low bandwidth display - if (frame()->document()->inLowBandwidthDisplay()) { - m_needToSwitchOutLowBandwidthDisplay = true; - return false; - } -#endif - - KURL completedURL; - if (!url.isEmpty()) - completedURL = completeURL(url); - - bool useFallback; - if (shouldUsePlugin(completedURL, mimeType, renderer->hasFallbackContent(), useFallback)) { - Settings* settings = m_frame->settings(); - if (!settings || !settings->arePluginsEnabled() || - (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMEType(mimeType))) - return false; - return loadPlugin(renderer, completedURL, mimeType, paramNames, paramValues, useFallback); - } - - ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagName(embedTag)); - HTMLPlugInElement* element = static_cast<HTMLPlugInElement*>(renderer->node()); - - // FIXME: OK to always make a new frame? When does the old frame get removed? - return loadSubframe(element, completedURL, frameName, m_outgoingReferrer); -} - -bool FrameLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback) -{ - if (m_frame->page() && (mimeType == "image/tiff" || mimeType == "image/tif" || mimeType == "image/x-tiff")) { - String pluginName = m_frame->page()->pluginData()->pluginNameForMimeType(mimeType); - if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false)) - return true; - } - - ObjectContentType objectType = m_client->objectContentType(url, mimeType); - // If an object's content can't be handled and it has no fallback, let - // it be handled as a plugin to show the broken plugin icon. - useFallback = objectType == ObjectContentNone && hasFallback; - return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin; -} - -bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String& mimeType, - const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback) -{ - Widget* widget = 0; - - if (renderer && !useFallback) { - Element* pluginElement = 0; - if (renderer->node() && renderer->node()->isElementNode()) - pluginElement = static_cast<Element*>(renderer->node()); - - if (!canLoad(url, String(), frame()->document())) { - FrameLoader::reportLocalLoadFailed(m_frame, url.string()); - return false; - } - - widget = m_client->createPlugin(IntSize(renderer->contentWidth(), renderer->contentHeight()), - pluginElement, url, paramNames, paramValues, mimeType, - m_frame->document()->isPluginDocument()); - if (widget) { - renderer->setWidget(widget); - m_containsPlugIns = true; - } - } - - return widget != 0; -} - -void FrameLoader::clearRecordedFormValues() -{ - m_formAboutToBeSubmitted = 0; - m_formValuesAboutToBeSubmitted.clear(); -} - -void FrameLoader::setFormAboutToBeSubmitted(PassRefPtr<HTMLFormElement> element) -{ - m_formAboutToBeSubmitted = element; -} - -void FrameLoader::recordFormValue(const String& name, const String& value) -{ - m_formValuesAboutToBeSubmitted.set(name, value); -} - -void FrameLoader::parentCompleted() -{ - if (m_scheduledRedirection && !m_redirectionTimer.isActive()) - startRedirectionTimer(); -} - -String FrameLoader::outgoingReferrer() const -{ - return m_outgoingReferrer; -} - -Frame* FrameLoader::opener() -{ - return m_opener; -} - -void FrameLoader::setOpener(Frame* opener) -{ - if (m_opener) - m_opener->loader()->m_openedFrames.remove(m_frame); - if (opener) - opener->loader()->m_openedFrames.add(m_frame); - m_opener = opener; - - if (m_frame->document()) { - m_frame->document()->initSecurityContext(); - m_frame->domWindow()->setSecurityOrigin(m_frame->document()->securityOrigin()); - } -} - -bool FrameLoader::openedByDOM() const -{ - return m_openedByDOM; -} - -void FrameLoader::setOpenedByDOM() -{ - m_openedByDOM = true; -} - -void FrameLoader::handleFallbackContent() -{ - HTMLFrameOwnerElement* owner = m_frame->ownerElement(); - if (!owner || !owner->hasTagName(objectTag)) - return; - static_cast<HTMLObjectElement*>(owner)->renderFallbackContent(); -} - -void FrameLoader::provisionalLoadStarted() -{ - Page* page = m_frame->page(); - - // this is used to update the current history item - // in the event of a navigation aytime during loading - m_navigationDuringLoad = false; - if (page) { - Document *document = page->mainFrame()->document(); - m_navigationDuringLoad = !page->mainFrame()->loader()->isComplete() || (document && document->processingLoadEvent()); - } - - m_firstLayoutDone = false; - cancelRedirection(true); - m_client->provisionalLoadStarted(); -} - -bool FrameLoader::userGestureHint() -{ - Frame* rootFrame = m_frame; - while (rootFrame->tree()->parent()) - rootFrame = rootFrame->tree()->parent(); - - if (rootFrame->script()->isEnabled()) - return rootFrame->script()->processingUserGesture(); - - return true; // If JavaScript is disabled, a user gesture must have initiated the navigation -} - -void FrameLoader::didNotOpenURL(const KURL& url) -{ - if (m_submittedFormURL == url) - m_submittedFormURL = KURL(); -} - -void FrameLoader::resetMultipleFormSubmissionProtection() -{ - m_submittedFormURL = KURL(); -} - -void FrameLoader::setEncoding(const String& name, bool userChosen) -{ - if (!m_workingURL.isEmpty()) - receivedFirstData(); - m_encoding = name; - m_encodingWasChosenByUser = userChosen; -} - -void FrameLoader::addData(const char* bytes, int length) -{ - ASSERT(m_workingURL.isEmpty()); - ASSERT(m_frame->document()); - ASSERT(m_frame->document()->parsing()); - write(bytes, length); -} - -bool FrameLoader::canCachePage() -{ - // Cache the page, if possible. - // Don't write to the cache if in the middle of a redirect, since we will want to - // store the final page we end up on. - // No point writing to the cache on a reload or loadSame, since we will just write - // over it again when we leave that page. - // FIXME: <rdar://problem/4886592> - We should work out the complexities of caching pages with frames as they - // are the most interesting pages on the web, and often those that would benefit the most from caching! - FrameLoadType loadType = this->loadType(); - - return m_documentLoader - && m_documentLoader->mainDocumentError().isNull() - && !m_frame->tree()->childCount() - && !m_frame->tree()->parent() - // FIXME: If we ever change this so that pages with plug-ins will be cached, - // we need to make sure that we don't cache pages that have outstanding NPObjects - // (objects created by the plug-in). Since there is no way to pause/resume a Netscape plug-in, - // they would need to be destroyed and then recreated, and there is no way that we can recreate - // the right NPObjects. See <rdar://problem/5197041> for more information. - && !m_containsPlugIns - && !m_URL.protocolIs("https") - && m_frame->document() - && !m_frame->document()->hasWindowEventListener(unloadEvent) -#if ENABLE(DATABASE) - && !m_frame->document()->hasOpenDatabases() -#endif - && m_frame->page() - && m_frame->page()->backForwardList()->enabled() - && m_frame->page()->backForwardList()->capacity() > 0 - && m_frame->page()->settings()->usesPageCache() - && m_currentHistoryItem - && !isQuickRedirectComing() - && loadType != FrameLoadTypeReload - && loadType != FrameLoadTypeReloadAllowingStaleData - && loadType != FrameLoadTypeSame - && !m_documentLoader->isLoadingInAPISense() - && !m_documentLoader->isStopping() -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - // FIXME: We should investigating caching pages that have an associated - // application cache. <rdar://problem/5917899> tracks that work. - && !m_documentLoader->applicationCache() - && !m_documentLoader->candidateApplicationCacheGroup() -#endif - ; -} - -void FrameLoader::updatePolicyBaseURL() -{ - if (m_frame->tree()->parent() && m_frame->tree()->parent()->document()) - setPolicyBaseURL(m_frame->tree()->parent()->document()->policyBaseURL()); - else - setPolicyBaseURL(m_URL); -} - -void FrameLoader::setPolicyBaseURL(const KURL& url) -{ - if (m_frame->document()) - m_frame->document()->setPolicyBaseURL(url); - for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) - child->loader()->setPolicyBaseURL(url); -} - -// This does the same kind of work that didOpenURL does, except it relies on the fact -// that a higher level already checked that the URLs match and the scrolling is the right thing to do. -void FrameLoader::scrollToAnchor(const KURL& url) -{ - m_URL = url; - updateHistoryForAnchorScroll(); - - // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor - m_frame->eventHandler()->stopAutoscrollTimer(); - started(); - gotoAnchor(); - - // It's important to model this as a load that starts and immediately finishes. - // Otherwise, the parent frame may think we never finished loading. - m_isComplete = false; - checkCompleted(); -} - -bool FrameLoader::isComplete() const -{ - return m_isComplete; -} - -void FrameLoader::scheduleRedirection(ScheduledRedirection* redirection) -{ - ASSERT(m_frame->page()); - - stopRedirectionTimer(); - m_scheduledRedirection.set(redirection); - if (!m_isComplete && redirection->type != ScheduledRedirection::redirection) - completed(); - if (m_isComplete || redirection->type != ScheduledRedirection::redirection) - startRedirectionTimer(); -} - -void FrameLoader::startRedirectionTimer() -{ - ASSERT(m_frame->page()); - ASSERT(m_scheduledRedirection); - - m_redirectionTimer.stop(); - m_redirectionTimer.startOneShot(m_scheduledRedirection->delay); - - switch (m_scheduledRedirection->type) { - case ScheduledRedirection::redirection: - case ScheduledRedirection::locationChange: - case ScheduledRedirection::locationChangeDuringLoad: - clientRedirected(KURL(m_scheduledRedirection->url), - m_scheduledRedirection->delay, - currentTime() + m_redirectionTimer.nextFireInterval(), - m_scheduledRedirection->lockHistory, - m_isExecutingJavaScriptFormAction); - return; - case ScheduledRedirection::reload: - case ScheduledRedirection::historyNavigation: - // Don't report history navigations. - return; - } - ASSERT_NOT_REACHED(); -} - -void FrameLoader::stopRedirectionTimer() -{ - if (!m_redirectionTimer.isActive()) - return; - - m_redirectionTimer.stop(); - - if (m_scheduledRedirection) { - switch (m_scheduledRedirection->type) { - case ScheduledRedirection::redirection: - case ScheduledRedirection::locationChange: - case ScheduledRedirection::locationChangeDuringLoad: - clientRedirectCancelledOrFinished(m_cancellingWithLoadInProgress); - return; - case ScheduledRedirection::reload: - case ScheduledRedirection::historyNavigation: - // Don't report history navigations. - return; - } - ASSERT_NOT_REACHED(); - } -} - -void FrameLoader::completed() -{ - RefPtr<Frame> protect(m_frame); - for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) - child->loader()->parentCompleted(); - if (Frame* parent = m_frame->tree()->parent()) - parent->loader()->checkCompleted(); - submitFormAgain(); -} - -void FrameLoader::started() -{ - for (Frame* frame = m_frame; frame; frame = frame->tree()->parent()) - frame->loader()->m_isComplete = false; -} - -bool FrameLoader::containsPlugins() const -{ - return m_containsPlugIns; -} - -void FrameLoader::prepareForLoadStart() -{ - if (Page* page = m_frame->page()) - page->progress()->progressStarted(m_frame); - m_client->dispatchDidStartProvisionalLoad(); -} - -void FrameLoader::setupForReplace() -{ - setState(FrameStateProvisional); - m_provisionalDocumentLoader = m_documentLoader; - m_documentLoader = 0; - detachChildren(); -} - -void FrameLoader::setupForReplaceByMIMEType(const String& newMIMEType) -{ - activeDocumentLoader()->setupForReplaceByMIMEType(newMIMEType); -} - -void FrameLoader::loadFrameRequestWithFormState(const FrameLoadRequest& request, bool lockHistory, Event* event, PassRefPtr<FormState> prpFormState) -{ - RefPtr<FormState> formState = prpFormState; - KURL url = request.resourceRequest().url(); - - String referrer; - String argsReferrer = request.resourceRequest().httpReferrer(); - if (!argsReferrer.isEmpty()) - referrer = argsReferrer; - else - referrer = m_outgoingReferrer; - - ASSERT(frame()->document()); - if (url.protocolIs("file")) { - if (!canLoad(url, String(), frame()->document()) && !canLoad(url, referrer)) { - FrameLoader::reportLocalLoadFailed(m_frame, url.string()); - return; - } - } - - if (shouldHideReferrer(url, referrer)) - referrer = String(); - - Frame* targetFrame = findFrameForNavigation(request.frameName()); - - if (request.resourceRequest().httpMethod() != "POST") { - FrameLoadType loadType; - if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData) - loadType = FrameLoadTypeReload; - else if (lockHistory) - loadType = FrameLoadTypeRedirectWithLockedHistory; - else - loadType = FrameLoadTypeStandard; - - loadURL(request.resourceRequest().url(), referrer, request.frameName(), loadType, - event, formState.release()); - } else - loadPostRequest(request.resourceRequest(), referrer, request.frameName(), event, formState.release()); - - if (targetFrame && targetFrame != m_frame) - if (Page* page = targetFrame->page()) - page->chrome()->focus(); -} - - -void FrameLoader::loadFrameRequestWithFormAndValues(const FrameLoadRequest& request, bool lockHistory, Event* event, - HTMLFormElement* submitForm, const HashMap<String, String>& formValues) -{ - RefPtr<FormState> formState; - if (submitForm && !formValues.isEmpty()) - formState = FormState::create(submitForm, formValues, m_frame); - - loadFrameRequestWithFormState(request, lockHistory, event, formState.release()); -} - - -void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, FrameLoadType newLoadType, - Event* event, PassRefPtr<FormState> prpFormState) -{ - RefPtr<FormState> formState = prpFormState; - bool isFormSubmission = formState; - - ResourceRequest request(newURL); - if (!referrer.isEmpty()) - request.setHTTPReferrer(referrer); - addExtraFieldsToRequest(request, true, event || isFormSubmission); - if (newLoadType == FrameLoadTypeReload) - request.setCachePolicy(ReloadIgnoringCacheData); - - ASSERT(newLoadType != FrameLoadTypeSame); - - NavigationAction action(newURL, newLoadType, isFormSubmission, event); - - if (!frameName.isEmpty()) { - if (Frame* targetFrame = findFrameForNavigation(frameName)) - targetFrame->loader()->loadURL(newURL, referrer, String(), newLoadType, event, formState); - else - checkNewWindowPolicy(action, request, formState, frameName); - return; - } - - RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader; - - bool sameURL = shouldTreatURLAsSameAsCurrent(newURL); - - // Make sure to do scroll to anchor processing even if the URL is - // exactly the same so pages with '#' links and DHTML side effects - // work properly. - if (shouldScrollToAnchor(isFormSubmission, newLoadType, newURL)) { - oldDocumentLoader->setTriggeringAction(action); - stopPolicyCheck(); - checkNavigationPolicy(request, oldDocumentLoader.get(), formState, - callContinueFragmentScrollAfterNavigationPolicy, this); - } else { - // must grab this now, since this load may stop the previous load and clear this flag - bool isRedirect = m_quickRedirectComing; - loadWithNavigationAction(request, action, newLoadType, formState); - if (isRedirect) { - m_quickRedirectComing = false; - if (m_provisionalDocumentLoader) - m_provisionalDocumentLoader->setIsClientRedirect(true); - } else if (sameURL) - // Example of this case are sites that reload the same URL with a different cookie - // driving the generated content, or a master frame with links that drive a target - // frame, where the user has clicked on the same link repeatedly. - // But if the load type is FrameLoadTypeReloadAllowingStaleData, which means the frame - // is reloaded only because user select one encoding from encoding menu, so we do not - // change the load type. - if (m_loadType != FrameLoadTypeReloadAllowingStaleData) - m_loadType = FrameLoadTypeSame; - } -} - -void FrameLoader::load(const ResourceRequest& request) -{ - load(request, SubstituteData()); -} - -void FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData) -{ - if (m_inStopAllLoaders) - return; - - // FIXME: is this the right place to reset loadType? Perhaps this should be done after loading is finished or aborted. - m_loadType = FrameLoadTypeStandard; - load(m_client->createDocumentLoader(request, substituteData).get()); -} - -void FrameLoader::load(const ResourceRequest& request, const String& frameName) -{ - if (frameName.isEmpty()) { - load(request); - return; - } - - Frame* frame = findFrameForNavigation(frameName); - if (frame) { - frame->loader()->load(request); - return; - } - - checkNewWindowPolicy(NavigationAction(request.url(), NavigationTypeOther), request, 0, frameName); -} - -void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, FrameLoadType type, PassRefPtr<FormState> formState) -{ - RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData()); - - loader->setTriggeringAction(action); - if (m_documentLoader) { - // if the load type is not FrameLoadTypeReloadAllowingStaleData, - // which means we will load page by user action, so we need not - // use original encoding override. - if (type == FrameLoadTypeReloadAllowingStaleData) - loader->setOverrideEncoding(m_documentLoader->overrideEncoding()); - else - loader->setOverrideEncoding(String()); - } - - loadWithDocumentLoader(loader.get(), type, formState); -} - -void FrameLoader::load(DocumentLoader* newDocumentLoader) -{ - ResourceRequest& r = newDocumentLoader->request(); - addExtraFieldsToRequest(r, true, false); - FrameLoadType type; - - if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) { - r.setCachePolicy(ReloadIgnoringCacheData); - type = FrameLoadTypeSame; - } else - type = FrameLoadTypeStandard; - - // Do not use original encoding override since it is not loaded by user - // selecting encoding. - if (m_documentLoader) - newDocumentLoader->setOverrideEncoding(String()); - - // When we loading alternate content for an unreachable URL that we're - // visiting in the history list, we treat it as a reload so the history list - // is appropriately maintained. - // - // FIXME: This seems like a dangerous overloading of the meaning of "FrameLoadTypeReload" ... - // shouldn't a more explicit type of reload be defined, that means roughly - // "load without affecting history" ? - if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) { - ASSERT(type == FrameLoadTypeStandard); - type = FrameLoadTypeReload; - } - - loadWithDocumentLoader(newDocumentLoader, type, 0); -} - -void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState) -{ - ASSERT(m_client->hasWebView()); - - // Unfortunately the view must be non-nil, this is ultimately due - // to parser requiring a FrameView. We should fix this dependency. - - ASSERT(m_client->hasFrameView()); - - m_policyLoadType = type; - RefPtr<FormState> formState = prpFormState; - bool isFormSubmission = formState; - - const KURL& newURL = loader->request().url(); - - if (shouldScrollToAnchor(isFormSubmission, m_policyLoadType, newURL)) { - RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader; - NavigationAction action(newURL, m_policyLoadType, isFormSubmission); - - oldDocumentLoader->setTriggeringAction(action); - stopPolicyCheck(); - checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState, - callContinueFragmentScrollAfterNavigationPolicy, this); - } else { - if (Frame* parent = m_frame->tree()->parent()) { - if (type == FrameLoadTypeReloadAllowingStaleData) - loader->setOverrideEncoding(parent->loader()->documentLoader()->overrideEncoding()); - else - loader->setOverrideEncoding(String()); - } - - stopPolicyCheck(); - setPolicyDocumentLoader(loader); - - checkNavigationPolicy(loader->request(), loader, formState, - callContinueLoadAfterNavigationPolicy, this); - } -} - -bool FrameLoader::canLoad(const KURL& url, const String& referrer, const Document* doc) -{ - // We can always load any URL that isn't considered local (e.g. http URLs) - if (!shouldTreatURLAsLocal(url.string())) - return true; - - // If we were provided a document, we let its local file policy dictate the result, - // otherwise we allow local loads only if the supplied referrer is also local. - if (doc) - return doc->securityOrigin()->canLoadLocalResources(); - else if (!referrer.isEmpty()) - return shouldTreatURLAsLocal(referrer); - else - return false; -} - -void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url) -{ - ASSERT(!url.isEmpty()); - if (!frame) - return; - - frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, "Not allowed to load local resource: " + url, 0, String()); -} - -bool FrameLoader::shouldHideReferrer(const KURL& url, const String& referrer) -{ - bool referrerIsSecureURL = protocolIs(referrer, "https"); - bool referrerIsWebURL = referrerIsSecureURL || protocolIs(referrer, "http"); - - if (!referrerIsWebURL) - return true; - - if (!referrerIsSecureURL) - return false; - - bool URLIsSecureURL = url.protocolIs("https"); - - return !URLIsSecureURL; -} - -const ResourceRequest& FrameLoader::initialRequest() const -{ - return activeDocumentLoader()->originalRequest(); -} - -void FrameLoader::receivedData(const char* data, int length) -{ - activeDocumentLoader()->receivedData(data, length); -} - -void FrameLoader::handleUnimplementablePolicy(const ResourceError& error) -{ - m_delegateIsHandlingUnimplementablePolicy = true; - m_client->dispatchUnableToImplementPolicy(error); - m_delegateIsHandlingUnimplementablePolicy = false; -} - -void FrameLoader::cannotShowMIMEType(const ResourceResponse& response) -{ - handleUnimplementablePolicy(m_client->cannotShowMIMETypeError(response)); -} - -ResourceError FrameLoader::interruptionForPolicyChangeError(const ResourceRequest& request) -{ - return m_client->interruptForPolicyChangeError(request); -} - -void FrameLoader::checkNavigationPolicy(const ResourceRequest& newRequest, NavigationPolicyDecisionFunction function, void* argument) -{ - checkNavigationPolicy(newRequest, activeDocumentLoader(), 0, function, argument); -} - -void FrameLoader::checkContentPolicy(const String& MIMEType, ContentPolicyDecisionFunction function, void* argument) -{ - ASSERT(activeDocumentLoader()); - - // Always show content with valid substitute data. - if (activeDocumentLoader()->substituteData().isValid()) { - function(argument, PolicyUse); - return; - } - -#if ENABLE(FTPDIR) - // Respect the hidden FTP Directory Listing pref so it can be tested even if the policy delegate might otherwise disallow it - Settings* settings = m_frame->settings(); - if (settings && settings->forceFTPDirectoryListings() && MIMEType == "application/x-ftp-directory") { - function(argument, PolicyUse); - return; - } -#endif - - m_policyCheck.set(function, argument); - m_client->dispatchDecidePolicyForMIMEType(&FrameLoader::continueAfterContentPolicy, - MIMEType, activeDocumentLoader()->request()); -} - -bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader) -{ - KURL unreachableURL = docLoader->unreachableURL(); - - if (unreachableURL.isEmpty()) - return false; - - if (!isBackForwardLoadType(m_policyLoadType)) - return false; - - // We only treat unreachableURLs specially during the delegate callbacks - // for provisional load errors and navigation policy decisions. The former - // case handles well-formed URLs that can't be loaded, and the latter - // case handles malformed URLs and unknown schemes. Loading alternate content - // at other times behaves like a standard load. - DocumentLoader* compareDocumentLoader = 0; - if (m_delegateIsDecidingNavigationPolicy || m_delegateIsHandlingUnimplementablePolicy) - compareDocumentLoader = m_policyDocumentLoader.get(); - else if (m_delegateIsHandlingProvisionalLoadError) - compareDocumentLoader = m_provisionalDocumentLoader.get(); - - return compareDocumentLoader && unreachableURL == compareDocumentLoader->request().url(); -} - -void FrameLoader::reloadAllowingStaleData(const String& encoding) -{ - if (!m_documentLoader) - return; - - ResourceRequest request = m_documentLoader->request(); - KURL unreachableURL = m_documentLoader->unreachableURL(); - if (!unreachableURL.isEmpty()) - request.setURL(unreachableURL); - - request.setCachePolicy(ReturnCacheDataElseLoad); - - RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData()); - setPolicyDocumentLoader(loader.get()); - - loader->setOverrideEncoding(encoding); - - loadWithDocumentLoader(loader.get(), FrameLoadTypeReloadAllowingStaleData, 0); -} - -void FrameLoader::reload() -{ - if (!m_documentLoader) - return; - - ResourceRequest& initialRequest = m_documentLoader->request(); - - // If a window is created by javascript, its main frame can have an empty but non-nil URL. - // Reloading in this case will lose the current contents (see 4151001). - if (initialRequest.url().isEmpty()) - return; - - // Replace error-page URL with the URL we were trying to reach. - KURL unreachableURL = m_documentLoader->unreachableURL(); - if (!unreachableURL.isEmpty()) - initialRequest.setURL(unreachableURL); - - // Create a new document loader for the reload, this will become m_documentLoader eventually, - // but first it has to be the "policy" document loader, and then the "provisional" document loader. - RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(initialRequest, SubstituteData()); - - ResourceRequest& request = loader->request(); - - request.setCachePolicy(ReloadIgnoringCacheData); - request.setHTTPHeaderField("Cache-Control", "max-age=0"); - - // If we're about to re-post, set up action so the application can warn the user. - if (request.httpMethod() == "POST") - loader->setTriggeringAction(NavigationAction(request.url(), NavigationTypeFormResubmitted)); - - loader->setOverrideEncoding(String()); - - loadWithDocumentLoader(loader.get(), FrameLoadTypeReload, 0); -} - -bool FrameLoader::shouldAllowNavigation(Frame* targetFrame) const -{ - // The navigation change is safe if the active frame is: - // - in the same security origin as the target or one of the target's ancestors - // Or the target frame is: - // - a top-level frame in the frame hierarchy - - if (!targetFrame) - return true; - - if (m_frame == targetFrame) - return true; - - if (!targetFrame->tree()->parent()) - return true; - - Document* activeDocument = m_frame->document(); - ASSERT(activeDocument); - const SecurityOrigin* activeSecurityOrigin = activeDocument->securityOrigin(); - for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree()->parent()) { - Document* ancestorDocument = ancestorFrame->document(); - if (!ancestorDocument) - return true; - - const SecurityOrigin* ancestorSecurityOrigin = ancestorDocument->securityOrigin(); - if (activeSecurityOrigin->canAccess(ancestorSecurityOrigin)) - return true; - } - - Settings* settings = targetFrame->settings(); - if (settings && !settings->privateBrowsingEnabled()) { - Document* targetDocument = targetFrame->document(); - // FIXME: this error message should contain more specifics of why the navigation change is not allowed. - String message = String::format("Unsafe JavaScript attempt to initiate a navigation change for frame with URL %s from frame with URL %s.\n", - targetDocument->url().string().utf8().data(), activeDocument->url().string().utf8().data()); - - // FIXME: should we print to the console of the activeFrame as well? - targetFrame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, 1, String()); - } - - return false; -} - -void FrameLoader::stopLoadingSubframes() -{ - for (RefPtr<Frame> child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) - child->loader()->stopAllLoaders(); -} - -void FrameLoader::stopAllLoaders() -{ - // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this. - if (m_inStopAllLoaders) - return; - - m_inStopAllLoaders = true; - - stopPolicyCheck(); - - stopLoadingSubframes(); - if (m_provisionalDocumentLoader) - m_provisionalDocumentLoader->stopLoading(); - if (m_documentLoader) - m_documentLoader->stopLoading(); - - setProvisionalDocumentLoader(0); - - if (m_documentLoader) - m_documentLoader->clearArchiveResources(); - - m_inStopAllLoaders = false; -} - -void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete) -{ - stopAllLoaders(); - - if (deferCheckLoadComplete) - scheduleCheckLoadComplete(); - else if (m_frame->page()) - checkLoadComplete(); -} - -DocumentLoader* FrameLoader::activeDocumentLoader() const -{ - if (m_state == FrameStateProvisional) - return m_provisionalDocumentLoader.get(); - return m_documentLoader.get(); -} - -bool FrameLoader::isLoading() const -{ - DocumentLoader* docLoader = activeDocumentLoader(); - if (!docLoader) - return false; - return docLoader->isLoadingMainResource() || docLoader->isLoadingSubresources() || docLoader->isLoadingPlugIns(); -} - -bool FrameLoader::frameHasLoaded() const -{ - return m_committedFirstRealDocumentLoad || (m_provisionalDocumentLoader && !m_creatingInitialEmptyDocument); -} - -void FrameLoader::setDocumentLoader(DocumentLoader* loader) -{ - if (!loader && !m_documentLoader) - return; - - ASSERT(loader != m_documentLoader); - ASSERT(!loader || loader->frameLoader() == this); - - m_client->prepareForDataSourceReplacement(); - detachChildren(); - if (m_documentLoader) - m_documentLoader->detachFromFrame(); - - m_documentLoader = loader; -} - -DocumentLoader* FrameLoader::documentLoader() const -{ - return m_documentLoader.get(); -} - -void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader) -{ - if (m_policyDocumentLoader == loader) - return; - - ASSERT(m_frame); - if (loader) - loader->setFrame(m_frame); - if (m_policyDocumentLoader - && m_policyDocumentLoader != m_provisionalDocumentLoader - && m_policyDocumentLoader != m_documentLoader) - m_policyDocumentLoader->detachFromFrame(); - - m_policyDocumentLoader = loader; -} - -DocumentLoader* FrameLoader::policyDocumentLoader() const -{ - return m_policyDocumentLoader.get(); -} - -DocumentLoader* FrameLoader::provisionalDocumentLoader() const -{ - return m_provisionalDocumentLoader.get(); -} - -DocumentLoader* FrameLoader::policyDocumentLoader() -{ - return m_policyDocumentLoader.get(); -} - -void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader) -{ - ASSERT(!loader || !m_provisionalDocumentLoader); - ASSERT(!loader || loader->frameLoader() == this); - - if (m_provisionalDocumentLoader && m_provisionalDocumentLoader != m_documentLoader) - m_provisionalDocumentLoader->detachFromFrame(); - - m_provisionalDocumentLoader = loader; -} - -FrameState FrameLoader::state() const -{ - return m_state; -} - -double FrameLoader::timeOfLastCompletedLoad() -{ - return storedTimeOfLastCompletedLoad; -} - -void FrameLoader::setState(FrameState newState) -{ - m_state = newState; - - if (newState == FrameStateProvisional) - provisionalLoadStarted(); - else if (newState == FrameStateComplete) { - frameLoadCompleted(); - storedTimeOfLastCompletedLoad = currentTime(); - if (m_documentLoader) - m_documentLoader->stopRecordingResponses(); - } -} - -void FrameLoader::clearProvisionalLoad() -{ - setProvisionalDocumentLoader(0); - if (Page* page = m_frame->page()) - page->progress()->progressCompleted(m_frame); - setState(FrameStateComplete); -} - -void FrameLoader::markLoadComplete() -{ - setState(FrameStateComplete); -} - -void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage) -{ - RefPtr<CachedPage> cachedPage = prpCachedPage; - RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader; - - // Check to see if we need to cache the page we are navigating away from into the back/forward cache. - // We are doing this here because we know for sure that a new page is about to be loaded. - if (canCachePage() && m_client->canCachePage() && !m_currentHistoryItem->isInPageCache()) - cachePageForHistoryItem(m_currentHistoryItem.get()); - - if (m_loadType != FrameLoadTypeReplace) - closeOldDataSources(); - - if (!cachedPage && !m_creatingInitialEmptyDocument) - m_client->makeRepresentation(pdl.get()); - - transitionToCommitted(cachedPage); - - // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's - // status has changed, if there was a redirect. The frame load delegate may have saved some state about - // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are - // just about to commit a new page, there cannot possibly be a pending redirect at this point. - if (m_sentRedirectNotification) - clientRedirectCancelledOrFinished(false); - - if (cachedPage && cachedPage->document()) { - open(*cachedPage); - cachedPage->clear(); - } else { - KURL url = pdl->substituteData().responseURL(); - if (url.isEmpty()) - url = pdl->url(); - if (url.isEmpty()) - url = pdl->responseURL(); - if (url.isEmpty()) - url = blankURL(); - - didOpenURL(url); - } - opened(); -} - -void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage) -{ - ASSERT(m_client->hasWebView()); - ASSERT(m_state == FrameStateProvisional); - - if (m_state != FrameStateProvisional) - return; - - m_client->setCopiesOnScroll(); - updateHistoryForCommit(); - - // The call to closeURL() invokes the unload event handler, which can execute arbitrary - // JavaScript. If the script initiates a new load, we need to abandon the current load, - // or the two will stomp each other. - DocumentLoader* pdl = m_provisionalDocumentLoader.get(); - if (m_documentLoader) - closeURL(); - if (pdl != m_provisionalDocumentLoader) - return; - - // Nothing else can interupt this commit - set the Provisional->Committed transition in stone - if (m_documentLoader) - m_documentLoader->stopLoadingSubresources(); - if (m_documentLoader) - m_documentLoader->stopLoadingPlugIns(); - - setDocumentLoader(m_provisionalDocumentLoader.get()); - setProvisionalDocumentLoader(0); - setState(FrameStateCommittedPage); - - // Handle adding the URL to the back/forward list. - DocumentLoader* dl = m_documentLoader.get(); - String ptitle = dl->title(); - - switch (m_loadType) { - case FrameLoadTypeForward: - case FrameLoadTypeBack: - case FrameLoadTypeIndexedBackForward: - if (Page* page = m_frame->page()) - if (page->backForwardList()) { - updateHistoryForBackForwardNavigation(); - - // Create a document view for this document, or used the cached view. - if (cachedPage) { - DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader(); - ASSERT(cachedDocumentLoader); - cachedDocumentLoader->setFrame(m_frame); - m_client->transitionToCommittedFromCachedPage(cachedPage.get()); - - } else - m_client->transitionToCommittedForNewPage(); - } - break; - - case FrameLoadTypeReload: - case FrameLoadTypeSame: - case FrameLoadTypeReplace: - updateHistoryForReload(); - m_client->transitionToCommittedForNewPage(); - break; - - // FIXME - just get rid of this case, and merge FrameLoadTypeReloadAllowingStaleData with the above case - case FrameLoadTypeReloadAllowingStaleData: - m_client->transitionToCommittedForNewPage(); - break; - - case FrameLoadTypeStandard: - updateHistoryForStandardLoad(); -#ifndef BUILDING_ON_TIGER - // This code was originally added for a Leopard performance imporvement. We decided to - // ifdef it to fix correctness issues on Tiger documented in <rdar://problem/5441823>. - if (m_frame->view()) - m_frame->view()->suppressScrollbars(true); -#endif - m_client->transitionToCommittedForNewPage(); - break; - - case FrameLoadTypeRedirectWithLockedHistory: - updateHistoryForRedirectWithLockedHistory(); - m_client->transitionToCommittedForNewPage(); - break; - - // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is). - // An exception should be thrown if we're in the FrameLoadTypeUninitialized state. - default: - ASSERT_NOT_REACHED(); - } - - m_responseMIMEType = dl->responseMIMEType(); - - // Tell the client we've committed this URL. - ASSERT(m_client->hasFrameView()); - - if (m_creatingInitialEmptyDocument) - return; - - m_committedFirstRealDocumentLoad = true; - - // For non-cached HTML pages, these methods are called in FrameLoader::begin. - if (cachedPage || !m_client->hasHTMLView()) { - dispatchDidCommitLoad(); - - // If we have a title let the WebView know about it. - if (!ptitle.isNull()) - m_client->dispatchDidReceiveTitle(ptitle); - } -} - -void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress) -{ - // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if - // the redirect succeeded. We should either rename this API, or add a new method, like - // -webView:didFinishClientRedirectForFrame: - m_client->dispatchDidCancelClientRedirect(); - - if (!cancelWithLoadInProgress) - m_quickRedirectComing = false; - - m_sentRedirectNotification = false; -} - -void FrameLoader::clientRedirected(const KURL& url, double seconds, double fireDate, bool lockHistory, bool isJavaScriptFormAction) -{ - m_client->dispatchWillPerformClientRedirect(url, seconds, fireDate); - - // Remember that we sent a redirect notification to the frame load delegate so that when we commit - // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame: - m_sentRedirectNotification = true; - - // If a "quick" redirect comes in an, we set a special mode so we treat the next - // load as part of the same navigation. If we don't have a document loader, we have - // no "original" load on which to base a redirect, so we treat the redirect as a normal load. - m_quickRedirectComing = lockHistory && m_documentLoader && !isJavaScriptFormAction; -} - -bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationURL) -{ - // This function implements the rule: "Don't reload if navigating by fragment within - // the same URL, but do reload if going to a new URL or to the same URL with no - // fragment identifier at all." - if (!destinationURL.hasRef()) - return true; - return !equalIgnoringRef(currentURL, destinationURL); -} - -void FrameLoader::closeOldDataSources() -{ - // FIXME: Is it important for this traversal to be postorder instead of preorder? - // If so, add helpers for postorder traversal, and use them. If not, then lets not - // use a recursive algorithm here. - for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) - child->loader()->closeOldDataSources(); - - if (m_documentLoader) - m_client->dispatchWillClose(); - - m_client->setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers -} - -void FrameLoader::open(CachedPage& cachedPage) -{ - ASSERT(m_frame->page()); - ASSERT(m_frame->page()->mainFrame() == m_frame); - - cancelRedirection(); - - // We still have to close the previous part page. - closeURL(); - - m_isComplete = false; - - // Don't re-emit the load event. - m_didCallImplicitClose = true; - - // Delete old status bar messages (if it _was_ activated on last URL). - if (m_frame->script()->isEnabled()) { - m_frame->setJSStatusBarText(String()); - m_frame->setJSDefaultStatusBarText(String()); - } - - KURL url = cachedPage.url(); - - if ((url.protocolIs("http") || url.protocolIs("https")) && !url.host().isEmpty() && url.path().isEmpty()) - url.setPath("/"); - - m_URL = url; - m_workingURL = url; - - started(); - - clear(); - - Document* document = cachedPage.document(); - ASSERT(document); - document->setInPageCache(false); - - m_needsClear = true; - m_isComplete = false; - m_didCallImplicitClose = false; - m_outgoingReferrer = url.string(); - - FrameView* view = cachedPage.view(); - if (view) - view->setWasScrolledByUser(false); - m_frame->setView(view); - - m_frame->setDocument(document); - m_frame->domWindow()->setURL(document->url()); - m_frame->domWindow()->setSecurityOrigin(document->securityOrigin()); - - m_decoder = document->decoder(); - - updatePolicyBaseURL(); - - cachedPage.restore(m_frame->page()); - - checkCompleted(); -} - -bool FrameLoader::isStopping() const -{ - return activeDocumentLoader()->isStopping(); -} - -void FrameLoader::finishedLoading() -{ - // Retain because the stop may release the last reference to it. - RefPtr<Frame> protect(m_frame); - - RefPtr<DocumentLoader> dl = activeDocumentLoader(); - dl->finishedLoading(); - if (!dl->mainDocumentError().isNull() || !dl->frameLoader()) - return; - dl->setPrimaryLoadComplete(true); - m_client->dispatchDidLoadMainResource(dl.get()); - checkLoadComplete(); -} - -bool FrameLoader::isHostedByObjectElement() const -{ - HTMLFrameOwnerElement* owner = m_frame->ownerElement(); - return owner && owner->hasTagName(objectTag); -} - -bool FrameLoader::isLoadingMainFrame() const -{ - Page* page = m_frame->page(); - return page && m_frame == page->mainFrame(); -} - -bool FrameLoader::canShowMIMEType(const String& MIMEType) const -{ - return m_client->canShowMIMEType(MIMEType); -} - -bool FrameLoader::representationExistsForURLScheme(const String& URLScheme) -{ - return m_client->representationExistsForURLScheme(URLScheme); -} - -String FrameLoader::generatedMIMETypeForURLScheme(const String& URLScheme) -{ - return m_client->generatedMIMETypeForURLScheme(URLScheme); -} - -void FrameLoader::cancelContentPolicyCheck() -{ - m_client->cancelPolicyCheck(); - m_policyCheck.clear(); -} - -void FrameLoader::didReceiveServerRedirectForProvisionalLoadForFrame() -{ - m_client->dispatchDidReceiveServerRedirectForProvisionalLoad(); -} - -void FrameLoader::finishedLoadingDocument(DocumentLoader* loader) -{ -#if PLATFORM(WIN) - if (m_creatingInitialEmptyDocument) - return; -#endif - - // If loading a webarchive, run through webarchive machinery - const String& responseMIMEType = loader->responseMIMEType(); - - // FIXME: Mac's FrameLoaderClient::finishedLoading() method does work that is required even with Archive loads - // so we still need to call it. Other platforms should only call finishLoading for non-archive loads - // That work should be factored out so this #ifdef can be removed -#if PLATFORM(MAC) - m_client->finishedLoading(loader); - if (!ArchiveFactory::isArchiveMimeType(responseMIMEType)) - return; -#else - if (!ArchiveFactory::isArchiveMimeType(responseMIMEType)) { - m_client->finishedLoading(loader); - return; - } -#endif - - RefPtr<Archive> archive(ArchiveFactory::create(loader->mainResourceData().get(), responseMIMEType)); - if (!archive) - return; - - loader->addAllArchiveResources(archive.get()); - - ArchiveResource* mainResource = archive->mainResource(); - loader->setParsedArchiveData(mainResource->data()); - continueLoadWithData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), mainResource->url()); -} - -bool FrameLoader::isReplacing() const -{ - return m_loadType == FrameLoadTypeReplace; -} - -void FrameLoader::setReplacing() -{ - m_loadType = FrameLoadTypeReplace; -} - -void FrameLoader::revertToProvisional(DocumentLoader* loader) -{ - m_client->revertToProvisionalState(loader); -} - -bool FrameLoader::subframeIsLoading() const -{ - // It's most likely that the last added frame is the last to load so we walk backwards. - for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree()->previousSibling()) { - FrameLoader* childLoader = child->loader(); - DocumentLoader* documentLoader = childLoader->documentLoader(); - if (documentLoader && documentLoader->isLoadingInAPISense()) - return true; - documentLoader = childLoader->provisionalDocumentLoader(); - if (documentLoader && documentLoader->isLoadingInAPISense()) - return true; - } - return false; -} - -void FrameLoader::willChangeTitle(DocumentLoader* loader) -{ - m_client->willChangeTitle(loader); -} - -FrameLoadType FrameLoader::loadType() const -{ - return m_loadType; -} - -void FrameLoader::stopPolicyCheck() -{ - m_client->cancelPolicyCheck(); - PolicyCheck check = m_policyCheck; - m_policyCheck.clear(); - check.cancel(); -} - -void FrameLoader::checkLoadCompleteForThisFrame() -{ - ASSERT(m_client->hasWebView()); - - switch (m_state) { - case FrameStateProvisional: { - if (m_delegateIsHandlingProvisionalLoadError) - return; - - RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader; - if (!pdl) - return; - - // If we've received any errors we may be stuck in the provisional state and actually complete. - const ResourceError& error = pdl->mainDocumentError(); - if (error.isNull()) - return; - - // Check all children first. - RefPtr<HistoryItem> item; - if (Page* page = m_frame->page()) - if (isBackForwardLoadType(loadType()) && m_frame == page->mainFrame()) - item = m_currentHistoryItem; - - bool shouldReset = true; - if (!pdl->isLoadingInAPISense()) { - m_delegateIsHandlingProvisionalLoadError = true; - m_client->dispatchDidFailProvisionalLoad(error); - m_delegateIsHandlingProvisionalLoadError = false; - - // FIXME: can stopping loading here possibly have any effect, if isLoading is false, - // which it must be to be in this branch of the if? And is it OK to just do a full-on - // stopAllLoaders instead of stopLoadingSubframes? - stopLoadingSubframes(); - pdl->stopLoading(); - - // Finish resetting the load state, but only if another load hasn't been started by the - // delegate callback. - if (pdl == m_provisionalDocumentLoader) - clearProvisionalLoad(); - else if (m_provisionalDocumentLoader) { - KURL unreachableURL = m_provisionalDocumentLoader->unreachableURL(); - if (!unreachableURL.isEmpty() && unreachableURL == pdl->request().url()) - shouldReset = false; - } - } - if (shouldReset && item) - if (Page* page = m_frame->page()) - page->backForwardList()->goToItem(item.get()); - return; - } - - case FrameStateCommittedPage: { - DocumentLoader* dl = m_documentLoader.get(); - if (!dl || dl->isLoadingInAPISense()) - return; - - markLoadComplete(); - - // FIXME: Is this subsequent work important if we already navigated away? - // Maybe there are bugs because of that, or extra work we can skip because - // the new page is ready. - - m_client->forceLayoutForNonHTML(); - - // If the user had a scroll point, scroll to it, overriding the anchor point if any. - if (Page* page = m_frame->page()) - if ((isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload) && page->backForwardList()) - restoreScrollPositionAndViewState(); - - if (m_creatingInitialEmptyDocument || !m_committedFirstRealDocumentLoad) - return; - - const ResourceError& error = dl->mainDocumentError(); -#ifndef NDEBUG - m_didDispatchDidCommitLoad = false; -#endif - if (!error.isNull()) - m_client->dispatchDidFailLoad(error); - else - m_client->dispatchDidFinishLoad(); - - if (Page* page = m_frame->page()) - page->progress()->progressCompleted(m_frame); - return; - } - - case FrameStateComplete: - // Even if already complete, we might have set a previous item on a frame that - // didn't do any data loading on the past transaction. Make sure to clear these out. - m_client->frameLoadCompleted(); - return; - } - - ASSERT_NOT_REACHED(); -} - -void FrameLoader::continueAfterContentPolicy(PolicyAction policy) -{ - PolicyCheck check = m_policyCheck; - m_policyCheck.clear(); - check.call(policy); -} - -void FrameLoader::continueLoadAfterWillSubmitForm(PolicyAction) -{ - if (!m_provisionalDocumentLoader) - return; - - // DocumentLoader calls back to our prepareForLoadStart - m_provisionalDocumentLoader->prepareForLoadStart(); - - // The load might be cancelled inside of prepareForLoadStart(), nulling out the m_provisionalDocumentLoader, - // so we need to null check it again. - if (!m_provisionalDocumentLoader) - return; - - DocumentLoader* activeDocLoader = activeDocumentLoader(); - if (activeDocLoader && activeDocLoader->isLoadingMainResource()) - return; - - m_provisionalDocumentLoader->setLoadingFromCachedPage(false); - - unsigned long identifier = 0; - - if (Page* page = m_frame->page()) { - identifier = page->progress()->createUniqueIdentifier(); - dispatchAssignIdentifierToInitialRequest(identifier, m_provisionalDocumentLoader.get(), m_provisionalDocumentLoader->originalRequest()); - } - - if (!m_provisionalDocumentLoader->startLoadingMainResource(identifier)) - m_provisionalDocumentLoader->updateLoading(); -} - -void FrameLoader::didFirstLayout() -{ - if (Page* page = m_frame->page()) - if (isBackForwardLoadType(m_loadType) && page->backForwardList()) - restoreScrollPositionAndViewState(); - - m_firstLayoutDone = true; - m_client->dispatchDidFirstLayout(); -} - -void FrameLoader::frameLoadCompleted() -{ - m_client->frameLoadCompleted(); - - // After a canceled provisional load, firstLayoutDone is false. - // Reset it to true if we're displaying a page. - if (m_documentLoader) - m_firstLayoutDone = true; -} - -bool FrameLoader::firstLayoutDone() const -{ - return m_firstLayoutDone; -} - -bool FrameLoader::isQuickRedirectComing() const -{ - return m_quickRedirectComing; -} - -void FrameLoader::detachChildren() -{ - // FIXME: Is it really necessary to do this in reverse order? - Frame* previous; - for (Frame* child = m_frame->tree()->lastChild(); child; child = previous) { - previous = child->tree()->previousSibling(); - child->loader()->detachFromParent(); - } -} - -void FrameLoader::recursiveCheckLoadComplete() -{ - Vector<RefPtr<Frame>, 10> frames; - - for (RefPtr<Frame> frame = m_frame->tree()->firstChild(); frame; frame = frame->tree()->nextSibling()) - frames.append(frame); - - unsigned size = frames.size(); - for (unsigned i = 0; i < size; i++) - frames[i]->loader()->recursiveCheckLoadComplete(); - - checkLoadCompleteForThisFrame(); -} - -// Called every time a resource is completely loaded, or an error is received. -void FrameLoader::checkLoadComplete() -{ - ASSERT(m_client->hasWebView()); - - // FIXME: Always traversing the entire frame tree is a bit inefficient, but - // is currently needed in order to null out the previous history item for all frames. - if (Page* page = m_frame->page()) - page->mainFrame()->loader()->recursiveCheckLoadComplete(); -} - -int FrameLoader::numPendingOrLoadingRequests(bool recurse) const -{ - if (!recurse) - return numRequests(m_frame->document()); - - int count = 0; - for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame)) - count += numRequests(frame->document()); - return count; -} - -FrameLoaderClient* FrameLoader::client() const -{ - return m_client; -} - -void FrameLoader::submitForm(const FrameLoadRequest& request, Event* event) -{ - // FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way. - // We do not want to submit more than one form from the same page, - // nor do we want to submit a single form more than once. - // This flag prevents these from happening; not sure how other browsers prevent this. - // The flag is reset in each time we start handle a new mouse or key down event, and - // also in setView since this part may get reused for a page from the back/forward cache. - // The form multi-submit logic here is only needed when we are submitting a form that affects this frame. - // FIXME: Frame targeting is only one of the ways the submission could end up doing something other - // than replacing this frame's content, so this check is flawed. On the other hand, the check is hardly - // needed any more now that we reset m_submittedFormURL on each mouse or key down event. - Frame* target = m_frame->tree()->find(request.frameName()); - if (target && m_frame->tree()->isDescendantOf(target)) { - if (m_submittedFormURL == request.resourceRequest().url()) - return; - m_submittedFormURL = request.resourceRequest().url(); - } - - // FIXME: We should probably call userGestureHint() to tell whether this form submission was the result of a user gesture. - loadFrameRequestWithFormAndValues(request, false, event, m_formAboutToBeSubmitted.get(), m_formValuesAboutToBeSubmitted); - - clearRecordedFormValues(); -} - -String FrameLoader::userAgent(const KURL& url) const -{ - return m_client->userAgent(url); -} - -void FrameLoader::tokenizerProcessedData() -{ -// ASSERT(m_frame->page()); -// ASSERT(m_frame->document()); - - checkCompleted(); -} - -void FrameLoader::didTellClientAboutLoad(const String& url) -{ -#if 0 - // This hash table is unused in our fork. The only reader is - // haveToldClientAboutLoad, and the only caller of that is - // loadedResourceFromMemoryCache. We have commented out that location - // because we want to send every URL to the client for mixed content - // detection. Therefore, this hash table is unused. - // - // The table stores every URL ever loaded, or which has been attempted to be - // loaded by a frame. For some apps like gmail, this can get into the - // thousands after it has been running for a while. With Gmail URLs often - // being more than 100 characters (and 2-bytes per char in a String), this - // can quickly use a lot of memory we don't need. - m_urlsClientKnowsAbout.add(url); -#endif -} - -bool FrameLoader::haveToldClientAboutLoad(const String& url) -{ -#if 0 - // See didTellClientAboutLoad() above for why this is removed in our fork. - // This is commented out for consistency only. All lookups will fail anyway. - return m_urlsClientKnowsAbout.contains(url); -#else - return false; -#endif -} - -void FrameLoader::handledOnloadEvents() -{ - m_client->dispatchDidHandleOnloadEvents(); -} - -void FrameLoader::frameDetached() -{ - stopAllLoaders(); - detachFromParent(); -} - -void FrameLoader::detachFromParent() -{ - RefPtr<Frame> protect(m_frame); - - closeURL(); - stopAllLoaders(); - saveScrollPositionAndViewStateToItem(currentHistoryItem()); - detachChildren(); - - if (Page* page = m_frame->page()) - page->inspectorController()->frameDetachedFromParent(m_frame); - - m_client->detachedFromParent2(); - setDocumentLoader(0); - m_client->detachedFromParent3(); - if (Frame* parent = m_frame->tree()->parent()) { - parent->tree()->removeChild(m_frame); - parent->loader()->scheduleCheckCompleted(); - } else { - m_frame->setView(0); - m_frame->pageDestroyed(); - } - m_client->detachedFromParent4(); -} - -void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, bool mainResource, bool alwaysFromRequest) -{ - applyUserAgent(request); - - if (m_loadType == FrameLoadTypeReload) { - request.setCachePolicy(ReloadIgnoringCacheData); - request.setHTTPHeaderField("Cache-Control", "max-age=0"); - } - - // Don't set the cookie policy URL if it's already been set. - if (request.mainDocumentURL().isEmpty()) { - if (mainResource && (isLoadingMainFrame() || alwaysFromRequest)) - request.setMainDocumentURL(request.url()); - else if (Page* page = m_frame->page()) - request.setMainDocumentURL(page->mainFrame()->loader()->url()); - } - - if (mainResource) - request.setHTTPAccept("application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"); -} - -void FrameLoader::committedLoad(DocumentLoader* loader, const char* data, int length) -{ - if (ArchiveFactory::isArchiveMimeType(loader->response().mimeType())) - return; - m_client->committedLoad(loader, data, length); -} - -void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, - Event* event, PassRefPtr<FormState> prpFormState) -{ - RefPtr<FormState> formState = prpFormState; - - // When posting, use the NSURLRequestReloadIgnoringCacheData load flag. - // This prevents a potential bug which may cause a page with a form that uses itself - // as an action to be returned from the cache without submitting. - - // FIXME: Where's the code that implements what the comment above says? - - // Previously when this method was reached, the original FrameLoadRequest had been deconstructed to build a - // bunch of parameters that would come in here and then be built back up to a ResourceRequest. In case - // any caller depends on the immutability of the original ResourceRequest, I'm rebuilding a ResourceRequest - // from scratch as it did all along. - const KURL& url = inRequest.url(); - RefPtr<FormData> formData = inRequest.httpBody(); - const String& contentType = inRequest.httpContentType(); - - ResourceRequest workingResourceRequest(url); - addExtraFieldsToRequest(workingResourceRequest, true, true); - - if (!referrer.isEmpty()) - workingResourceRequest.setHTTPReferrer(referrer); - workingResourceRequest.setHTTPMethod("POST"); - workingResourceRequest.setHTTPBody(formData); - workingResourceRequest.setHTTPContentType(contentType); - - NavigationAction action(url, FrameLoadTypeStandard, true, event); - - if (!frameName.isEmpty()) { - if (Frame* targetFrame = findFrameForNavigation(frameName)) - targetFrame->loader()->loadWithNavigationAction(workingResourceRequest, action, FrameLoadTypeStandard, formState.release()); - else - checkNewWindowPolicy(action, workingResourceRequest, formState.release(), frameName); - } else - loadWithNavigationAction(workingResourceRequest, action, FrameLoadTypeStandard, formState.release()); -} - -bool FrameLoader::isReloading() const -{ - return documentLoader()->request().cachePolicy() == ReloadIgnoringCacheData; -} - -void FrameLoader::loadEmptyDocumentSynchronously() -{ - ResourceRequest request(KURL("")); - load(request); -} - -unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data) -{ - // Since this is a subresource, we can load any URL (we ignore the return value). - // But we still want to know whether we should hide the referrer or not, so we call the canLoad method. - String referrer = m_outgoingReferrer; - if (shouldHideReferrer(request.url(), referrer)) - referrer = String(); - - ResourceRequest initialRequest = request; - initialRequest.setTimeoutInterval(10); - - if (initialRequest.isConditional()) - initialRequest.setCachePolicy(ReloadIgnoringCacheData); - else - initialRequest.setCachePolicy(documentLoader()->request().cachePolicy()); - - if (!referrer.isEmpty()) - initialRequest.setHTTPReferrer(referrer); - - if (Page* page = m_frame->page()) - initialRequest.setMainDocumentURL(page->mainFrame()->loader()->documentLoader()->request().url()); - initialRequest.setHTTPUserAgent(client()->userAgent(request.url())); - - unsigned long identifier = 0; - ResourceRequest newRequest(initialRequest); - requestFromDelegate(newRequest, identifier, error); - - if (error.isNull()) { - ASSERT(!newRequest.isNull()); - didTellClientAboutLoad(newRequest.url().string()); - -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - ApplicationCacheResource* resource; - if (documentLoader()->shouldLoadResourceFromApplicationCache(newRequest, resource)) { - if (resource) { - response = resource->response(); - data.append(resource->data()->data(), resource->data()->size()); - } else - error = cannotShowURLError(newRequest); - } else -#endif - ResourceHandle::loadResourceSynchronously(newRequest, error, response, data, m_frame); - } - - sendRemainingDelegateMessages(identifier, response, data.size(), error); - return identifier; -} - -void FrameLoader::assignIdentifierToInitialRequest(unsigned long identifier, const ResourceRequest& clientRequest) -{ - return dispatchAssignIdentifierToInitialRequest(identifier, activeDocumentLoader(), clientRequest); -} - -void FrameLoader::willSendRequest(ResourceLoader* loader, ResourceRequest& clientRequest, const ResourceResponse& redirectResponse) -{ - applyUserAgent(clientRequest); - dispatchWillSendRequest(loader->documentLoader(), loader->identifier(), clientRequest, redirectResponse); -} - -void FrameLoader::didReceiveResponse(ResourceLoader* loader, const ResourceResponse& r) -{ - activeDocumentLoader()->addResponse(r); - - if (Page* page = m_frame->page()) - page->progress()->incrementProgress(loader->identifier(), r); - dispatchDidReceiveResponse(loader->documentLoader(), loader->identifier(), r); -} - -void FrameLoader::didReceiveData(ResourceLoader* loader, const char* data, int length, int lengthReceived) -{ - if (Page* page = m_frame->page()) - page->progress()->incrementProgress(loader->identifier(), data, length); - dispatchDidReceiveContentLength(loader->documentLoader(), loader->identifier(), lengthReceived); -} - -void FrameLoader::didFailToLoad(ResourceLoader* loader, const ResourceError& error) -{ - if (Page* page = m_frame->page()) - page->progress()->completeProgress(loader->identifier()); - if (!error.isNull()) - m_client->dispatchDidFailLoading(loader->documentLoader(), loader->identifier(), error); -} - -const ResourceRequest& FrameLoader::originalRequest() const -{ - return activeDocumentLoader()->originalRequestCopy(); -} - -void FrameLoader::receivedMainResourceError(const ResourceError& error, bool isComplete) -{ - // Retain because the stop may release the last reference to it. - RefPtr<Frame> protect(m_frame); - - RefPtr<DocumentLoader> loader = activeDocumentLoader(); - - if (isComplete) { - // FIXME: Don't want to do this if an entirely new load is going, so should check - // that both data sources on the frame are either this or nil. - stop(); - if (m_client->shouldFallBack(error)) - handleFallbackContent(); - } - - if (m_state == FrameStateProvisional && m_provisionalDocumentLoader) { - KURL failedURL = m_provisionalDocumentLoader->originalRequestCopy().url(); - didNotOpenURL(failedURL); - - // We might have made a page cache item, but now we're bailing out due to an error before we ever - // transitioned to the new page (before WebFrameState == commit). The goal here is to restore any state - // so that the existing view (that wenever got far enough to replace) can continue being used. - invalidateCurrentItemCachedPage(); - - // Call clientRedirectCancelledOrFinished here so that the frame load delegate is notified that the redirect's - // status has changed, if there was a redirect. The frame load delegate may have saved some state about - // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely - // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect - // has ended. - if (m_sentRedirectNotification) - clientRedirectCancelledOrFinished(false); - } - - - loader->mainReceivedError(error, isComplete); -} - -void FrameLoader::callContinueFragmentScrollAfterNavigationPolicy(void* argument, - const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue) -{ - FrameLoader* loader = static_cast<FrameLoader*>(argument); - loader->continueFragmentScrollAfterNavigationPolicy(request, shouldContinue); -} - -void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue) -{ - // FIXME: - // some functions check m_quickRedirectComing, and others check for - // FrameLoadTypeRedirectWithLockedHistory. - bool isRedirect = m_quickRedirectComing || m_policyLoadType == FrameLoadTypeRedirectWithLockedHistory; - m_quickRedirectComing = false; - - if (!shouldContinue) - return; - - KURL url = request.url(); - - m_documentLoader->replaceRequestURLForAnchorScroll(url); - if (!isRedirect && !shouldTreatURLAsSameAsCurrent(url)) { - // NB: must happen after _setURL, since we add based on the current request. - // Must also happen before we openURL and displace the scroll position, since - // adding the BF item will save away scroll state. - - // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before - // it was done, currItem is now set the that slow doc, and prevItem is whatever was - // before it. Adding the b/f item will bump the slow doc down to prevItem, even - // though its load is not yet done. I think this all works out OK, for one because - // we have already saved away the scroll and doc state for the long slow load, - // but it's not an obvious case. - - addHistoryItemForFragmentScroll(); - } - - scrollToAnchor(url); - - if (!isRedirect) - // This will clear previousItem from the rest of the frame tree that didn't - // doing any loading. We need to make a pass on this now, since for anchor nav - // we'll not go through a real load and reach Completed state. - checkLoadComplete(); - - m_client->dispatchDidChangeLocationWithinPage(); - m_client->didFinishLoad(); -} - -bool FrameLoader::shouldScrollToAnchor(bool isFormSubmission, FrameLoadType loadType, const KURL& url) -{ - // Should we do anchor navigation within the existing content? - - // We don't do this if we are submitting a form, explicitly reloading, - // currently displaying a frameset, or if the URL does not have a fragment. - // These rules were originally based on what KHTML was doing in KHTMLPart::openURL. - - // FIXME: What about load types other than Standard and Reload? - - return !isFormSubmission - && loadType != FrameLoadTypeReload - && loadType != FrameLoadTypeSame - && !shouldReload(this->url(), url) - // We don't want to just scroll if a link from within a - // frameset is trying to reload the frameset into _top. - && !m_frame->isFrameSet(); -} - -void FrameLoader::opened() -{ - if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect()) - updateHistoryForClientRedirect(); - - if (m_documentLoader->isLoadingFromCachedPage()) { - m_frame->document()->didRestoreFromCache(); - - // Force a layout to update view size and thereby update scrollbars. - m_client->forceLayout(); - - const ResponseVector& responses = m_documentLoader->responses(); - size_t count = responses.size(); - for (size_t i = 0; i < count; i++) { - const ResourceResponse& response = responses[i]; - // FIXME: If the WebKit client changes or cancels the request, this is not respected. - ResourceError error; - unsigned long identifier; - ResourceRequest request(response.url()); - requestFromDelegate(request, identifier, error); - // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing. - // However, with today's computers and networking speeds, this won't happen in practice. - // Could be an issue with a giant local file. - sendRemainingDelegateMessages(identifier, response, static_cast<int>(response.expectedContentLength()), error); - } - - pageCache()->remove(m_currentHistoryItem.get()); - - m_documentLoader->setPrimaryLoadComplete(true); - - // FIXME: Why only this frame and not parent frames? - checkLoadCompleteForThisFrame(); - } -} - -void FrameLoader::checkNewWindowPolicy(const NavigationAction& action, const ResourceRequest& request, - PassRefPtr<FormState> formState, const String& frameName) -{ - m_policyCheck.set(request, formState, frameName, - callContinueLoadAfterNewWindowPolicy, this); - m_client->dispatchDecidePolicyForNewWindowAction(&FrameLoader::continueAfterNewWindowPolicy, - action, request, formState, frameName); -} - -void FrameLoader::continueAfterNewWindowPolicy(PolicyAction policy) -{ - PolicyCheck check = m_policyCheck; - m_policyCheck.clear(); - - switch (policy) { - case PolicyIgnore: - check.clearRequest(); - break; - case PolicyDownload: - m_client->startDownload(check.request()); - check.clearRequest(); - break; - case PolicyUse: - break; - } - - check.call(policy == PolicyUse); -} - -void FrameLoader::checkNavigationPolicy(const ResourceRequest& request, DocumentLoader* loader, - PassRefPtr<FormState> formState, NavigationPolicyDecisionFunction function, void* argument) -{ - NavigationAction action = loader->triggeringAction(); - if (action.isEmpty()) { - action = NavigationAction(request.url(), NavigationTypeOther); - loader->setTriggeringAction(action); - } - - // Don't ask more than once for the same request or if we are loading an empty URL. - // This avoids confusion on the part of the client. - if (equalIgnoringHeaderFields(request, loader->lastCheckedRequest()) || (!request.isNull() && request.url().isEmpty())) { - function(argument, request, 0, true); - loader->setLastCheckedRequest(request); - return; - } - - // We are always willing to show alternate content for unreachable URLs; - // treat it like a reload so it maintains the right state for b/f list. - if (loader->substituteData().isValid() && !loader->substituteData().failingURL().isEmpty()) { - if (isBackForwardLoadType(m_policyLoadType)) - m_policyLoadType = FrameLoadTypeReload; - function(argument, request, 0, true); - return; - } - - loader->setLastCheckedRequest(request); - - m_policyCheck.set(request, formState.get(), function, argument); - - m_delegateIsDecidingNavigationPolicy = true; - m_client->dispatchDecidePolicyForNavigationAction(&FrameLoader::continueAfterNavigationPolicy, - action, request, formState); - m_delegateIsDecidingNavigationPolicy = false; -} - -void FrameLoader::continueAfterNavigationPolicy(PolicyAction policy) -{ - PolicyCheck check = m_policyCheck; - m_policyCheck.clear(); - - bool shouldContinue = policy == PolicyUse; - - switch (policy) { - case PolicyIgnore: - check.clearRequest(); - break; - case PolicyDownload: - m_client->startDownload(check.request()); - check.clearRequest(); - break; - case PolicyUse: { - ResourceRequest request(check.request()); - - if (!m_client->canHandleRequest(request)) { - handleUnimplementablePolicy(m_client->cannotShowURLError(check.request())); - check.clearRequest(); - shouldContinue = false; - } - break; - } - } - - check.call(shouldContinue); -} - -void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument, - const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue) -{ - FrameLoader* loader = static_cast<FrameLoader*>(argument); - loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue); -} - -void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue) -{ - // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a - // nil policyDataSource because loading the alternate page will have passed - // through this method already, nested; otherwise, policyDataSource should still be set. - ASSERT(m_policyDocumentLoader || !m_provisionalDocumentLoader->unreachableURL().isEmpty()); - - bool isTargetItem = m_provisionalHistoryItem ? m_provisionalHistoryItem->isTargetItem() : false; - - // Two reasons we can't continue: - // 1) Navigation policy delegate said we can't so request is nil. A primary case of this - // is the user responding Cancel to the form repost nag sheet. - // 2) User responded Cancel to an alert popped up by the before unload event handler. - // The "before unload" event handler runs only for the main frame. - bool canContinue = shouldContinue && (!isLoadingMainFrame() || m_frame->shouldClose()); - - if (!canContinue) { - // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we - // need to report that the client redirect was cancelled. - if (m_quickRedirectComing) - clientRedirectCancelledOrFinished(false); - - setPolicyDocumentLoader(0); - - // If the navigation request came from the back/forward menu, and we punt on it, we have the - // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity, - // we only do this when punting a navigation for the target frame or top-level frame. - if ((isTargetItem || isLoadingMainFrame()) && isBackForwardLoadType(m_policyLoadType)) - if (Page* page = m_frame->page()) { - Frame* mainFrame = page->mainFrame(); - if (HistoryItem* resetItem = mainFrame->loader()->m_currentHistoryItem.get()) - page->backForwardList()->goToItem(resetItem); - } - return; - } - - FrameLoadType type = m_policyLoadType; - stopAllLoaders(); - setProvisionalDocumentLoader(m_policyDocumentLoader.get()); - m_loadType = type; - setState(FrameStateProvisional); - - setPolicyDocumentLoader(0); - - if (isBackForwardLoadType(type) && loadProvisionalItemFromCachedPage()) - return; - - if (formState) - m_client->dispatchWillSubmitForm(&FrameLoader::continueLoadAfterWillSubmitForm, formState); - else - continueLoadAfterWillSubmitForm(); -} - - -void FrameLoader::callContinueLoadAfterNewWindowPolicy(void* argument, - const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, bool shouldContinue) -{ - FrameLoader* loader = static_cast<FrameLoader*>(argument); - loader->continueLoadAfterNewWindowPolicy(request, formState, frameName, shouldContinue); -} - -void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& request, - PassRefPtr<FormState> formState, const String& frameName, bool shouldContinue) -{ - if (!shouldContinue) - return; - - RefPtr<Frame> frame = m_frame; - RefPtr<Frame> mainFrame = m_client->dispatchCreatePage(); - if (!mainFrame) - return; - - if (frameName != "_blank") - mainFrame->tree()->setName(frameName); - - mainFrame->loader()->setOpenedByDOM(); - mainFrame->loader()->m_client->dispatchShow(); - mainFrame->loader()->setOpener(frame.get()); - mainFrame->loader()->loadWithNavigationAction(request, NavigationAction(), FrameLoadTypeStandard, formState); -} - -void FrameLoader::sendRemainingDelegateMessages(unsigned long identifier, const ResourceResponse& response, int length, const ResourceError& error) -{ - if (!response.isNull()) - dispatchDidReceiveResponse(m_documentLoader.get(), identifier, response); - - if (length > 0) - dispatchDidReceiveContentLength(m_documentLoader.get(), identifier, length); - - if (error.isNull()) - dispatchDidFinishLoading(m_documentLoader.get(), identifier); - else - m_client->dispatchDidFailLoading(m_documentLoader.get(), identifier, error); -} - -void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& identifier, ResourceError& error) -{ - ASSERT(!request.isNull()); - - identifier = 0; - if (Page* page = m_frame->page()) { - identifier = page->progress()->createUniqueIdentifier(); - dispatchAssignIdentifierToInitialRequest(identifier, m_documentLoader.get(), request); - } - - ResourceRequest newRequest(request); - dispatchWillSendRequest(m_documentLoader.get(), identifier, newRequest, ResourceResponse()); - - if (newRequest.isNull()) - error = cancelledError(request); - else - error = ResourceError(); - - request = newRequest; -} - -void FrameLoader::loadedResourceFromMemoryCache(const CachedResource* resource) -{ - ResourceRequest request(resource->url()); - const ResourceResponse& response = resource->response(); - int length = resource->encodedSize(); - - if (Page* page = m_frame->page()) - page->inspectorController()->didLoadResourceFromMemoryCache(m_documentLoader.get(), request, response, length); - - -#if 0 - // The following test prevents reporting a resource has been loaded from - // the cache as CachedResource.m_sendResourceLoadCallbacks is always false. - // Also, haveToldClientAboutLoad() and didTellClientAboutLoad() would cause - // dispatchDidLoadResourceFromMemoryCache() to be invoked only the first - // time the resource is loaded from the cache. - // We want to be notified every time a resource is loaded from the cache - // (this is needed to detect mixed-contents), so we removed it. - - if (!resource->sendResourceLoadCallbacks() || haveToldClientAboutLoad(resource->url())) - return; -#endif - - if (m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, response, length)) { - didTellClientAboutLoad(resource->url()); - return; - } - - unsigned long identifier; - ResourceError error; - ResourceRequest r(request); - requestFromDelegate(r, identifier, error); - sendRemainingDelegateMessages(identifier, response, length, error); - - didTellClientAboutLoad(resource->url()); -} - -void FrameLoader::applyUserAgent(ResourceRequest& request) -{ - String userAgent = client()->userAgent(request.url()); - ASSERT(!userAgent.isNull()); - request.setHTTPUserAgent(userAgent); -} - -bool FrameLoader::canGoBackOrForward(int distance) const -{ - if (Page* page = m_frame->page()) { - if (distance == 0) - return true; - if (distance > 0 && distance <= page->backForwardList()->forwardListCount()) - return true; - if (distance < 0 && -distance <= page->backForwardList()->backListCount()) - return true; - } - return false; -} - -int FrameLoader::getHistoryLength() -{ - if (Page* page = m_frame->page()) - return page->backForwardList()->backListCount() + 1; - return 0; -} - -KURL FrameLoader::historyURL(int distance) -{ - if (Page* page = m_frame->page()) { - BackForwardList* list = page->backForwardList(); - HistoryItem* item = list->itemAtIndex(distance); - if (!item) { - if (distance > 0) { - int forwardListCount = list->forwardListCount(); - if (forwardListCount > 0) - item = list->itemAtIndex(forwardListCount); - } else { - int backListCount = list->backListCount(); - if (backListCount > 0) - item = list->itemAtIndex(-backListCount); - } - } - if (item) - return item->url(); - } - return KURL(); -} - -void FrameLoader::addHistoryItemForFragmentScroll() -{ - addBackForwardItemClippedAtTarget(false); -} - -bool FrameLoader::loadProvisionalItemFromCachedPage() -{ - RefPtr<CachedPage> cachedPage = pageCache()->get(m_provisionalHistoryItem.get()); - if (!cachedPage || !cachedPage->document()) - return false; - provisionalDocumentLoader()->loadFromCachedPage(cachedPage.release()); - return true; -} - -void FrameLoader::cachePageForHistoryItem(HistoryItem* item) -{ - if (Page* page = m_frame->page()) { - RefPtr<CachedPage> cachedPage = CachedPage::create(page); - cachedPage->setTimeStampToNow(); - cachedPage->setDocumentLoader(documentLoader()); - m_client->savePlatformDataToCachedPage(cachedPage.get()); - - pageCache()->add(item, cachedPage.release()); - } -} - -bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& url) const -{ - if (!m_currentHistoryItem) - return false; - return url == m_currentHistoryItem->url() || url == m_currentHistoryItem->originalURL(); -} - -PassRefPtr<HistoryItem> FrameLoader::createHistoryItem(bool useOriginal) -{ - DocumentLoader* docLoader = documentLoader(); - - KURL unreachableURL = docLoader ? docLoader->unreachableURL() : KURL(); - - KURL url; - KURL originalURL; - - if (!unreachableURL.isEmpty()) { - url = unreachableURL; - originalURL = unreachableURL; - } else { - originalURL = docLoader ? docLoader->originalURL() : KURL(); - if (useOriginal) - url = originalURL; - else if (docLoader) - url = docLoader->requestURL(); - } - - LOG(History, "WebCoreHistory: Creating item for %s", url.string().ascii().data()); - - // Frames that have never successfully loaded any content - // may have no URL at all. Currently our history code can't - // deal with such things, so we nip that in the bud here. - // Later we may want to learn to live with nil for URL. - // See bug 3368236 and related bugs for more information. - if (url.isEmpty()) - url = blankURL(); - if (originalURL.isEmpty()) - originalURL = blankURL(); - - Frame* parentFrame = m_frame->tree()->parent(); - String parent = parentFrame ? parentFrame->tree()->name() : ""; - String title = docLoader ? docLoader->title() : ""; - - RefPtr<HistoryItem> item = HistoryItem::create(url, m_frame->tree()->name(), parent, title); - item->setOriginalURLString(originalURL.string()); - - // Save form state if this is a POST - if (docLoader) { - if (useOriginal) - item->setFormInfoFromRequest(docLoader->originalRequest()); - else - item->setFormInfoFromRequest(docLoader->request()); - } - - // Set the item for which we will save document state - m_previousHistoryItem = m_currentHistoryItem; - m_currentHistoryItem = item; - - return item.release(); -} - -void FrameLoader::addBackForwardItemClippedAtTarget(bool doClip) -{ - Page* page = m_frame->page(); - if (!page) - return; - - if (documentLoader()->urlForHistory().isEmpty()) - return; - - Frame* mainFrame = page->mainFrame(); - ASSERT(mainFrame); - FrameLoader* frameLoader = mainFrame->loader(); - - if (!frameLoader->m_didPerformFirstNavigation && page->backForwardList()->entries().size() == 1) { - frameLoader->m_didPerformFirstNavigation = true; - m_client->didPerformFirstNavigation(); - } - - RefPtr<HistoryItem> item = frameLoader->createHistoryItemTree(m_frame, doClip); - LOG(BackForward, "WebCoreBackForward - Adding backforward item %p for frame %s", item.get(), documentLoader()->url().string().ascii().data()); - page->backForwardList()->addItem(item); -} - -PassRefPtr<HistoryItem> FrameLoader::createHistoryItemTree(Frame* targetFrame, bool clipAtTarget) -{ - RefPtr<HistoryItem> bfItem = createHistoryItem(m_frame->tree()->parent() ? true : false); - if (m_previousHistoryItem) - saveScrollPositionAndViewStateToItem(m_previousHistoryItem.get()); - if (!(clipAtTarget && m_frame == targetFrame)) { - // save frame state for items that aren't loading (khtml doesn't save those) - saveDocumentState(); - for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) { - FrameLoader* childLoader = child->loader(); - bool hasChildLoaded = childLoader->frameHasLoaded(); - - // If the child is a frame corresponding to an <object> element that never loaded, - // we don't want to create a history item, because that causes fallback content - // to be ignored on reload. - - if (!(!hasChildLoaded && childLoader->isHostedByObjectElement())) - bfItem->addChildItem(childLoader->createHistoryItemTree(targetFrame, clipAtTarget)); - } - } - if (m_frame == targetFrame) - bfItem->setIsTargetItem(true); - return bfItem; -} - -Frame* FrameLoader::findFrameForNavigation(const AtomicString& name) -{ - Frame* frame = m_frame->tree()->find(name); - if (shouldAllowNavigation(frame)) - return frame; - return 0; -} - -void FrameLoader::saveScrollPositionAndViewStateToItem(HistoryItem* item) -{ - if (!item || !m_frame->view()) - return; - - item->setScrollPoint(IntPoint(m_frame->view()->contentsX(), m_frame->view()->contentsY())); - // FIXME: It would be great to work out a way to put this code in WebCore instead of calling through to the client. - m_client->saveViewStateToItem(item); -} - -/* - There is a race condition between the layout and load completion that affects restoring the scroll position. - We try to restore the scroll position at both the first layout and upon load completion. - - 1) If first layout happens before the load completes, we want to restore the scroll position then so that the - first time we draw the page is already scrolled to the right place, instead of starting at the top and later - jumping down. It is possible that the old scroll position is past the part of the doc laid out so far, in - which case the restore silent fails and we will fix it in when we try to restore on doc completion. - 2) If the layout happens after the load completes, the attempt to restore at load completion time silently - fails. We then successfully restore it when the layout happens. -*/ -void FrameLoader::restoreScrollPositionAndViewState() -{ - if (!m_committedFirstRealDocumentLoad) - return; - - ASSERT(m_currentHistoryItem); - - // FIXME: As the ASSERT attests, it seems we should always have a currentItem here. - // One counterexample is <rdar://problem/4917290> - // For now, to cover this issue in release builds, there is no technical harm to returning - // early and from a user standpoint - as in the above radar - the previous page load failed - // so there *is* no scroll or view state to restore! - if (!m_currentHistoryItem) - return; - - // FIXME: It would be great to work out a way to put this code in WebCore instead of calling - // through to the client. It's currently used only for the PDF view on Mac. - m_client->restoreViewState(); - - if (FrameView* view = m_frame->view()) - if (!view->wasScrolledByUser()) { - const IntPoint& scrollPoint = m_currentHistoryItem->scrollPoint(); - view->setContentsPos(scrollPoint.x(), scrollPoint.y()); - } -} - -void FrameLoader::invalidateCurrentItemCachedPage() -{ - // When we are pre-commit, the currentItem is where the pageCache data resides - CachedPage* cachedPage = pageCache()->get(m_currentHistoryItem.get()); - - // FIXME: This is a grotesque hack to fix <rdar://problem/4059059> Crash in RenderFlow::detach - // Somehow the PageState object is not properly updated, and is holding onto a stale document. - // Both Xcode and FileMaker see this crash, Safari does not. - - ASSERT(!cachedPage || cachedPage->document() == m_frame->document()); - if (cachedPage && cachedPage->document() == m_frame->document()) { - cachedPage->document()->setInPageCache(false); - cachedPage->clear(); - } - - if (cachedPage) - pageCache()->remove(m_currentHistoryItem.get()); -} - -void FrameLoader::saveDocumentState() -{ - if (m_creatingInitialEmptyDocument) - return; - - // For a standard page load, we will have a previous item set, which will be used to - // store the form state. However, in some cases we will have no previous item, and - // the current item is the right place to save the state. One example is when we - // detach a bunch of frames because we are navigating from a site with frames to - // another site. Another is when saving the frame state of a frame that is not the - // target of the current navigation (if we even decide to save with that granularity). - - // Because of previousItem's "masking" of currentItem for this purpose, it's important - // that previousItem be cleared at the end of a page transition. We leverage the - // checkLoadComplete recursion to achieve this goal. - - HistoryItem* item = m_previousHistoryItem ? m_previousHistoryItem.get() : m_currentHistoryItem.get(); - if (!item) - return; - - Document* document = m_frame->document(); - ASSERT(document); - - if (document && item->isCurrentDocument(document)) { - LOG(Loading, "WebCoreLoading %s: saving form state to %p", m_frame->tree()->name().string().utf8().data(), item); - item->setDocumentState(document->formElementsState()); - } -} - -// Loads content into this frame, as specified by history item -void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType) -{ - if (!m_frame->page()) - return; - - KURL itemURL = item->url(); - KURL itemOriginalURL = item->originalURL(); - KURL currentURL; - if (documentLoader()) - currentURL = documentLoader()->url(); - RefPtr<FormData> formData = item->formData(); - - // Are we navigating to an anchor within the page? - // Note if we have child frames we do a real reload, since the child frames might not - // match our current frame structure, or they might not have the right content. We could - // check for all that as an additional optimization. - // We also do not do anchor-style navigation if we're posting a form. - - if (!formData && urlsMatchItem(item)) { - // Must do this maintenance here, since we don't go through a real page reload - saveScrollPositionAndViewStateToItem(m_currentHistoryItem.get()); - - if (FrameView* view = m_frame->view()) - view->setWasScrolledByUser(false); - - m_currentHistoryItem = item; - - // FIXME: Form state might need to be saved here too. - - // We always call scrollToAnchor here, even if the URL doesn't have an - // anchor fragment. This is so we'll keep the WebCore Frame's URL up-to-date. - scrollToAnchor(item->url()); - - // must do this maintenance here, since we don't go through a real page reload - restoreScrollPositionAndViewState(); - - // Fake the URL change by updating the data source's request. This will no longer - // be necessary if we do the better fix described above. - documentLoader()->replaceRequestURLForAnchorScroll(itemURL); - - m_client->dispatchDidChangeLocationWithinPage(); - - // FrameLoaderClient::didFinishLoad() tells the internal load delegate the load finished with no error - m_client->didFinishLoad(); - } else { - // Remember this item so we can traverse any child items as child frames load - m_provisionalHistoryItem = item; - - bool inPageCache = false; - - // Check if we'll be using the page cache. We only use the page cache - // if one exists and it is less than _backForwardCacheExpirationInterval - // seconds old. If the cache is expired it gets flushed here. - if (RefPtr<CachedPage> cachedPage = pageCache()->get(item)) { - double interval = currentTime() - cachedPage->timeStamp(); - - // FIXME: 1800 should not be hardcoded, it should come from - // WebKitBackForwardCacheExpirationIntervalKey in WebKit. - // Or we should remove WebKitBackForwardCacheExpirationIntervalKey. - if (interval <= 1800) { - loadWithDocumentLoader(cachedPage->documentLoader(), loadType, 0); - inPageCache = true; - } else { - LOG(PageCache, "Not restoring page for %s from back/forward cache because cache entry has expired", m_provisionalHistoryItem->url().string().ascii().data()); - pageCache()->remove(item); - } - } - - if (!inPageCache) { - ResourceRequest request(itemURL); - - addExtraFieldsToRequest(request, true, formData); - - // If this was a repost that failed the page cache, we might try to repost the form. - NavigationAction action; - if (formData) { - - formData->generateFiles(m_frame->page()->chrome()->client()); - - request.setHTTPMethod("POST"); - request.setHTTPReferrer(item->formReferrer()); - request.setHTTPBody(formData); - request.setHTTPContentType(item->formContentType()); - - // FIXME: Slight hack to test if the NSURL cache contains the page we're going to. - // We want to know this before talking to the policy delegate, since it affects whether - // we show the DoYouReallyWantToRepost nag. - // - // This trick has a small bug (3123893) where we might find a cache hit, but then - // have the item vanish when we try to use it in the ensuing nav. This should be - // extremely rare, but in that case the user will get an error on the navigation. - - if (ResourceHandle::willLoadFromCache(request)) - action = NavigationAction(itemURL, loadType, false); - else { - request.setCachePolicy(ReloadIgnoringCacheData); - action = NavigationAction(itemURL, NavigationTypeFormResubmitted); - } - } else { - switch (loadType) { - case FrameLoadTypeReload: - request.setCachePolicy(ReloadIgnoringCacheData); - break; - case FrameLoadTypeBack: - case FrameLoadTypeForward: - case FrameLoadTypeIndexedBackForward: - if (itemURL.protocol() != "https") - request.setCachePolicy(ReturnCacheDataElseLoad); - break; - case FrameLoadTypeStandard: - case FrameLoadTypeRedirectWithLockedHistory: - // no-op: leave as protocol default - // FIXME: I wonder if we ever hit this case - break; - case FrameLoadTypeSame: - case FrameLoadTypeReloadAllowingStaleData: - default: - ASSERT_NOT_REACHED(); - } - - action = NavigationAction(itemOriginalURL, loadType, false); - } - - loadWithNavigationAction(request, action, loadType, 0); - } - } -} - -// Walk the frame tree and ensure that the URLs match the URLs in the item. -bool FrameLoader::urlsMatchItem(HistoryItem* item) const -{ - const KURL& currentURL = documentLoader()->url(); - if (!equalIgnoringRef(currentURL, item->url())) - return false; - - const HistoryItemVector& childItems = item->children(); - - unsigned size = childItems.size(); - for (unsigned i = 0; i < size; ++i) { - Frame* childFrame = m_frame->tree()->child(childItems[i]->target()); - if (childFrame && !childFrame->loader()->urlsMatchItem(childItems[i].get())) - return false; - } - - return true; -} - -// Main funnel for navigating to a previous location (back/forward, non-search snap-back) -// This includes recursion to handle loading into framesets properly -void FrameLoader::goToItem(HistoryItem* targetItem, FrameLoadType type) -{ - ASSERT(!m_frame->tree()->parent()); - - // shouldGoToHistoryItem is a private delegate method. This is needed to fix: - // <rdar://problem/3951283> can view pages from the back/forward cache that should be disallowed by Parental Controls - // Ultimately, history item navigations should go through the policy delegate. That's covered in: - // <rdar://problem/3979539> back/forward cache navigations should consult policy delegate - Page* page = m_frame->page(); - if (!page) - return; - if (!m_client->shouldGoToHistoryItem(targetItem)) - return; - - // Set the BF cursor before commit, which lets the user quickly click back/forward again. - // - plus, it only makes sense for the top level of the operation through the frametree, - // as opposed to happening for some/one of the page commits that might happen soon - BackForwardList* bfList = page->backForwardList(); - HistoryItem* currentItem = bfList->currentItem(); - bfList->goToItem(targetItem); - recursiveGoToItem(targetItem, currentItem, type); -} - -// The general idea here is to traverse the frame tree and the item tree in parallel, -// tracking whether each frame already has the content the item requests. If there is -// a match (by URL), we just restore scroll position and recurse. Otherwise we must -// reload that frame, and all its kids. -void FrameLoader::recursiveGoToItem(HistoryItem* item, HistoryItem* fromItem, FrameLoadType type) -{ - ASSERT(item); - ASSERT(fromItem); - - KURL itemURL = item->url(); - KURL currentURL; - if (documentLoader()) - currentURL = documentLoader()->url(); - - // Always reload the target frame of the item we're going to. This ensures that we will - // do -some- load for the transition, which means a proper notification will be posted - // to the app. - // The exact URL has to match, including fragment. We want to go through the _load - // method, even if to do a within-page navigation. - // The current frame tree and the frame tree snapshot in the item have to match. - if (!item->isTargetItem() && - itemURL == currentURL && - ((m_frame->tree()->name().isEmpty() && item->target().isEmpty()) || m_frame->tree()->name() == item->target()) && - childFramesMatchItem(item)) - { - // This content is good, so leave it alone and look for children that need reloading - // Save form state (works from currentItem, since prevItem is nil) - ASSERT(!m_previousHistoryItem); - saveDocumentState(); - saveScrollPositionAndViewStateToItem(m_currentHistoryItem.get()); - - if (FrameView* view = m_frame->view()) - view->setWasScrolledByUser(false); - - m_currentHistoryItem = item; - - // Restore form state (works from currentItem) - restoreDocumentState(); - - // Restore the scroll position (we choose to do this rather than going back to the anchor point) - restoreScrollPositionAndViewState(); - - const HistoryItemVector& childItems = item->children(); - - int size = childItems.size(); - for (int i = 0; i < size; ++i) { - String childName = childItems[i]->target(); - HistoryItem* fromChildItem = fromItem->childItemWithName(childName); - ASSERT(fromChildItem || fromItem->isTargetItem()); - Frame* childFrame = m_frame->tree()->child(childName); - ASSERT(childFrame); - childFrame->loader()->recursiveGoToItem(childItems[i].get(), fromChildItem, type); - } - } else { - loadItem(item, type); - } -} - -// helper method that determines whether the subframes described by the item's subitems -// match our own current frameset -bool FrameLoader::childFramesMatchItem(HistoryItem* item) const -{ - const HistoryItemVector& childItems = item->children(); - if (childItems.size() != m_frame->tree()->childCount()) - return false; - - unsigned size = childItems.size(); - for (unsigned i = 0; i < size; ++i) - if (!m_frame->tree()->child(childItems[i]->target())) - return false; - - // Found matches for all item targets - return true; -} - -// There are 3 things you might think of as "history", all of which are handled by these functions. -// -// 1) Back/forward: The m_currentHistoryItem is part of this mechanism. -// 2) Global history: Handled by the client. -// 3) Visited links: Handled by the PageGroup. - -void FrameLoader::updateHistoryForStandardLoad() -{ - LOG(History, "WebCoreHistory: Updating History for Standard Load in frame %s", documentLoader()->url().string().ascii().data()); - - Settings* settings = m_frame->settings(); - bool needPrivacy = !settings || settings->privateBrowsingEnabled(); - const KURL& historyURL = documentLoader()->urlForHistory(); - - // If the navigation occured during load and this is a subframe, update the current - // back/forward item rather than adding a new one and don't add the new URL to global - // history at all. But do add it to visited links. <rdar://problem/5333496> - bool frameNavigationDuringLoad = false; - if (m_navigationDuringLoad) { - HTMLFrameOwnerElement* owner = m_frame->ownerElement(); - frameNavigationDuringLoad = owner && !owner->createdByParser(); - m_navigationDuringLoad = false; - } - - if (!frameNavigationDuringLoad && !documentLoader()->isClientRedirect()) { - if (!historyURL.isEmpty()) { - addBackForwardItemClippedAtTarget(true); - if (!needPrivacy) - m_client->updateGlobalHistory(historyURL); - } - } else if (documentLoader()->unreachableURL().isEmpty() && m_currentHistoryItem) { - m_currentHistoryItem->setURL(documentLoader()->url()); - m_currentHistoryItem->setFormInfoFromRequest(documentLoader()->request()); - } - - if (!historyURL.isEmpty() && !needPrivacy) { - if (Page* page = m_frame->page()) - page->group().addVisitedLink(historyURL); - } -} - -void FrameLoader::updateHistoryForClientRedirect() -{ -#if !LOG_DISABLED - if (documentLoader()) - LOG(History, "WebCoreHistory: Updating History for client redirect in frame %s", documentLoader()->title().utf8().data()); -#endif - - // Clear out form data so we don't try to restore it into the incoming page. Must happen after - // webcore has closed the URL and saved away the form state. - if (m_currentHistoryItem) { - m_currentHistoryItem->clearDocumentState(); - m_currentHistoryItem->clearScrollPoint(); - } - - Settings* settings = m_frame->settings(); - bool needPrivacy = !settings || settings->privateBrowsingEnabled(); - const KURL& historyURL = documentLoader()->urlForHistory(); - - if (!historyURL.isEmpty() && !needPrivacy) { - if (Page* page = m_frame->page()) - page->group().addVisitedLink(historyURL); - } -} - -void FrameLoader::updateHistoryForBackForwardNavigation() -{ -#if !LOG_DISABLED - if (documentLoader()) - LOG(History, "WebCoreHistory: Updating History for back/forward navigation in frame %s", documentLoader()->title().utf8().data()); -#endif - - // Must grab the current scroll position before disturbing it - saveScrollPositionAndViewStateToItem(m_previousHistoryItem.get()); -} - -void FrameLoader::updateHistoryForReload() -{ -#if !LOG_DISABLED - if (documentLoader()) - LOG(History, "WebCoreHistory: Updating History for reload in frame %s", documentLoader()->title().utf8().data()); -#endif - - if (m_currentHistoryItem) { - pageCache()->remove(m_currentHistoryItem.get()); - - if (loadType() == FrameLoadTypeReload) - saveScrollPositionAndViewStateToItem(m_currentHistoryItem.get()); - - // Sometimes loading a page again leads to a different result because of cookies. Bugzilla 4072 - if (documentLoader()->unreachableURL().isEmpty()) - m_currentHistoryItem->setURL(documentLoader()->requestURL()); - } -} - -void FrameLoader::updateHistoryForRedirectWithLockedHistory() -{ -#if !LOG_DISABLED - if (documentLoader()) - LOG(History, "WebCoreHistory: Updating History for internal load in frame %s", documentLoader()->title().utf8().data()); -#endif - - Settings* settings = m_frame->settings(); - bool needPrivacy = !settings || settings->privateBrowsingEnabled(); - const KURL& historyURL = documentLoader()->urlForHistory(); - - if (documentLoader()->isClientRedirect()) { - if (!m_currentHistoryItem && !m_frame->tree()->parent()) { - addBackForwardItemClippedAtTarget(true); - if (!needPrivacy && !historyURL.isEmpty()) - m_client->updateGlobalHistory(historyURL); - } - if (m_currentHistoryItem) { - m_currentHistoryItem->setURL(documentLoader()->url()); - m_currentHistoryItem->setFormInfoFromRequest(documentLoader()->request()); - } - } else { - Frame* parentFrame = m_frame->tree()->parent(); - if (parentFrame && parentFrame->loader()->m_currentHistoryItem) - parentFrame->loader()->m_currentHistoryItem->addChildItem(createHistoryItem(true)); - } - - if (!historyURL.isEmpty() && !needPrivacy) { - if (Page* page = m_frame->page()) - page->group().addVisitedLink(historyURL); - } -} - -void FrameLoader::updateHistoryForCommit() -{ -#if !LOG_DISABLED - if (documentLoader()) - LOG(History, "WebCoreHistory: Updating History for commit in frame %s", documentLoader()->title().utf8().data()); -#endif - FrameLoadType type = loadType(); - if (isBackForwardLoadType(type) || - (type == FrameLoadTypeReload && !provisionalDocumentLoader()->unreachableURL().isEmpty())) { - // Once committed, we want to use current item for saving DocState, and - // the provisional item for restoring state. - // Note previousItem must be set before we close the URL, which will - // happen when the data source is made non-provisional below - m_previousHistoryItem = m_currentHistoryItem; - ASSERT(m_provisionalHistoryItem); - m_currentHistoryItem = m_provisionalHistoryItem; - m_provisionalHistoryItem = 0; - } -} - -void FrameLoader::updateHistoryForAnchorScroll() -{ - if (m_URL.isEmpty()) - return; - - Settings* settings = m_frame->settings(); - if (!settings || settings->privateBrowsingEnabled()) - return; - - Page* page = m_frame->page(); - if (!page) - return; - - page->group().addVisitedLink(m_URL); -} - -// Walk the frame tree, telling all frames to save their form state into their current -// history item. -void FrameLoader::saveDocumentAndScrollState() -{ - for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame)) { - frame->loader()->saveDocumentState(); - frame->loader()->saveScrollPositionAndViewStateToItem(frame->loader()->currentHistoryItem()); - } -} - -// FIXME: These 6 setter/getters are here for a dwindling number of users in WebKit, WebFrame -// being the primary one. After they're no longer needed there, they can be removed! -HistoryItem* FrameLoader::currentHistoryItem() -{ - return m_currentHistoryItem.get(); -} - -HistoryItem* FrameLoader::previousHistoryItem() -{ - return m_previousHistoryItem.get(); -} - -HistoryItem* FrameLoader::provisionalHistoryItem() -{ - return m_provisionalHistoryItem.get(); -} - -void FrameLoader::setCurrentHistoryItem(PassRefPtr<HistoryItem> item) -{ - m_currentHistoryItem = item; -} - -void FrameLoader::setPreviousHistoryItem(PassRefPtr<HistoryItem> item) -{ - m_previousHistoryItem = item; -} - -void FrameLoader::setProvisionalHistoryItem(PassRefPtr<HistoryItem> item) -{ - m_provisionalHistoryItem = item; -} - -void FrameLoader::setMainDocumentError(DocumentLoader* loader, const ResourceError& error) -{ - m_client->setMainDocumentError(loader, error); -} - -void FrameLoader::mainReceivedCompleteError(DocumentLoader* loader, const ResourceError& error) -{ - loader->setPrimaryLoadComplete(true); - m_client->dispatchDidLoadMainResource(activeDocumentLoader()); - checkCompleted(); - if (m_frame->page()) - checkLoadComplete(); -} - -void FrameLoader::mainReceivedError(const ResourceError& error, bool isComplete) -{ - activeDocumentLoader()->mainReceivedError(error, isComplete); -} - -ResourceError FrameLoader::cancelledError(const ResourceRequest& request) const -{ - ResourceError error = m_client->cancelledError(request); - error.setIsCancellation(true); - return error; -} - -ResourceError FrameLoader::blockedError(const ResourceRequest& request) const -{ - return m_client->blockedError(request); -} - -ResourceError FrameLoader::cannotShowURLError(const ResourceRequest& request) const -{ - return m_client->cannotShowURLError(request); -} - -ResourceError FrameLoader::fileDoesNotExistError(const ResourceResponse& response) const -{ - return m_client->fileDoesNotExistError(response); -} - -void FrameLoader::didFinishLoad(ResourceLoader* loader) -{ - if (Page* page = m_frame->page()) - page->progress()->completeProgress(loader->identifier()); - dispatchDidFinishLoading(loader->documentLoader(), loader->identifier()); -} - -void FrameLoader::didReceiveAuthenticationChallenge(ResourceLoader* loader, const AuthenticationChallenge& currentWebChallenge) -{ - m_client->dispatchDidReceiveAuthenticationChallenge(loader->documentLoader(), loader->identifier(), currentWebChallenge); -} - -void FrameLoader::didCancelAuthenticationChallenge(ResourceLoader* loader, const AuthenticationChallenge& currentWebChallenge) -{ - m_client->dispatchDidCancelAuthenticationChallenge(loader->documentLoader(), loader->identifier(), currentWebChallenge); -} - -PolicyCheck::PolicyCheck() - : m_navigationFunction(0) - , m_newWindowFunction(0) - , m_contentFunction(0) -{ -} - -void PolicyCheck::clear() -{ - clearRequest(); - m_navigationFunction = 0; - m_newWindowFunction = 0; - m_contentFunction = 0; -} - -void PolicyCheck::set(const ResourceRequest& request, PassRefPtr<FormState> formState, - NavigationPolicyDecisionFunction function, void* argument) -{ - m_request = request; - m_formState = formState; - m_frameName = String(); - - m_navigationFunction = function; - m_newWindowFunction = 0; - m_contentFunction = 0; - m_argument = argument; -} - -void PolicyCheck::set(const ResourceRequest& request, PassRefPtr<FormState> formState, - const String& frameName, NewWindowPolicyDecisionFunction function, void* argument) -{ - m_request = request; - m_formState = formState; - m_frameName = frameName; - - m_navigationFunction = 0; - m_newWindowFunction = function; - m_contentFunction = 0; - m_argument = argument; -} - -void PolicyCheck::set(ContentPolicyDecisionFunction function, void* argument) -{ - m_request = ResourceRequest(); - m_formState = 0; - m_frameName = String(); - - m_navigationFunction = 0; - m_newWindowFunction = 0; - m_contentFunction = function; - m_argument = argument; -} - -void PolicyCheck::call(bool shouldContinue) -{ - if (m_navigationFunction) - m_navigationFunction(m_argument, m_request, m_formState.get(), shouldContinue); - if (m_newWindowFunction) - m_newWindowFunction(m_argument, m_request, m_formState.get(), m_frameName, shouldContinue); - ASSERT(!m_contentFunction); -} - -void PolicyCheck::call(PolicyAction action) -{ - ASSERT(!m_navigationFunction); - ASSERT(!m_newWindowFunction); - ASSERT(m_contentFunction); - m_contentFunction(m_argument, action); -} - -void PolicyCheck::clearRequest() -{ - m_request = ResourceRequest(); - m_formState = 0; - m_frameName = String(); -} - -void PolicyCheck::cancel() -{ - clearRequest(); - if (m_navigationFunction) - m_navigationFunction(m_argument, m_request, m_formState.get(), false); - if (m_newWindowFunction) - m_newWindowFunction(m_argument, m_request, m_formState.get(), m_frameName, false); - if (m_contentFunction) - m_contentFunction(m_argument, PolicyIgnore); -} - -void FrameLoader::setTitle(const String& title) -{ - documentLoader()->setTitle(title); -} - -KURL FrameLoader::originalRequestURL() const -{ - return activeDocumentLoader()->originalRequest().url(); -} - -String FrameLoader::referrer() const -{ - return documentLoader()->request().httpReferrer(); -} - -void FrameLoader::dispatchWindowObjectAvailable() -{ - // TODO(tc): We should also return early if we have no window shell. - // But we can't check that until we refactor ScriptController. - if (!m_frame->script()->isEnabled()) - return; - - m_client->windowObjectCleared(); - - if (Page* page = m_frame->page()) { - if (InspectorController* inspector = page->inspectorController()) - inspector->inspectedWindowScriptObjectCleared(m_frame); - if (InspectorController* inspector = page->parentInspectorController()) - inspector->windowScriptObjectAvailable(); - } -} - -Widget* FrameLoader::createJavaAppletWidget(const IntSize& size, Element* element, const HashMap<String, String>& args) -{ - String baseURLString; - Vector<String> paramNames; - Vector<String> paramValues; - HashMap<String, String>::const_iterator end = args.end(); - for (HashMap<String, String>::const_iterator it = args.begin(); it != end; ++it) { - if (equalIgnoringCase(it->first, "baseurl")) - baseURLString = it->second; - paramNames.append(it->first); - paramValues.append(it->second); - } - - if (baseURLString.isEmpty()) - baseURLString = m_frame->document()->baseURL().string(); - KURL baseURL = completeURL(baseURLString); - - Widget* widget = m_client->createJavaAppletWidget(size, element, baseURL, paramNames, paramValues); - if (widget) - m_containsPlugIns = true; - - return widget; -} - -void FrameLoader::didChangeTitle(DocumentLoader* loader) -{ - m_client->didChangeTitle(loader); - - // The title doesn't get communicated to the WebView until we are committed. - if (loader->isCommitted()) { - // Must update the entries in the back-forward list too. - if (m_currentHistoryItem) - m_currentHistoryItem->setTitle(loader->title()); - // This must go through the WebFrame because it has the right notion of the current b/f item. - m_client->setTitle(loader->title(), loader->urlForHistory()); - m_client->setMainFrameDocumentReady(true); // update observers with new DOMDocument - m_client->dispatchDidReceiveTitle(loader->title()); - } -} - -void FrameLoader::continueLoadWithData(SharedBuffer* buffer, const String& mimeType, const String& textEncoding, const KURL& url) -{ - m_responseMIMEType = mimeType; - didOpenURL(url); - - String encoding; - if (m_frame) - encoding = documentLoader()->overrideEncoding(); - bool userChosen = !encoding.isNull(); - if (encoding.isNull()) - encoding = textEncoding; - setEncoding(encoding, userChosen); - - ASSERT(m_frame->document()); - - addData(buffer->data(), buffer->size()); -} - -void FrameLoader::registerURLSchemeAsLocal(const String& scheme) -{ - localSchemes().add(scheme); -} - -bool FrameLoader::shouldTreatURLAsLocal(const String& url) -{ - // This avoids an allocation of another String and the HashSet contains() - // call for the file: and http: schemes. - if (url.length() >= 5) { - const UChar* s = url.characters(); - if (s[0] == 'h' && s[1] == 't' && s[2] == 't' && s[3] == 'p' && s[4] == ':') - return false; - if (s[0] == 'f' && s[1] == 'i' && s[2] == 'l' && s[3] == 'e' && s[4] == ':') - return true; - } - - int loc = url.find(':'); - if (loc == -1) - return false; - - String scheme = url.left(loc); - return localSchemes().contains(scheme); -} - -bool FrameLoader::shouldTreatSchemeAsLocal(const String& scheme) -{ - // This avoids an allocation of another String and the HashSet contains() - // call for the file: and http: schemes. - if (scheme.length() == 4) { - const UChar* s = scheme.characters(); - if (s[0] == 'h' && s[1] == 't' && s[2] == 't' && s[3] == 'p') - return false; - if (s[0] == 'f' && s[1] == 'i' && s[2] == 'l' && s[3] == 'e') - return true; - } - - if (scheme.isEmpty()) - return false; - - return localSchemes().contains(scheme); -} - -void FrameLoader::dispatchDidCommitLoad() -{ - if (m_creatingInitialEmptyDocument) - return; - -#ifndef NDEBUG - m_didDispatchDidCommitLoad = true; -#endif - - m_client->dispatchDidCommitLoad(); - - if (Page* page = m_frame->page()) - page->inspectorController()->didCommitLoad(m_documentLoader.get()); -} - -void FrameLoader::dispatchAssignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request) -{ - m_client->assignIdentifierToInitialRequest(identifier, loader, request); - - if (Page* page = m_frame->page()) - page->inspectorController()->identifierForInitialRequest(identifier, loader, request); -} - -void FrameLoader::dispatchWillSendRequest(DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse) -{ - m_client->dispatchWillSendRequest(loader, identifier, request, redirectResponse); - - if (Page* page = m_frame->page()) - page->inspectorController()->willSendRequest(loader, identifier, request, redirectResponse); -} - -void FrameLoader::dispatchDidReceiveResponse(DocumentLoader* loader, unsigned long identifier, const ResourceResponse& r) -{ - m_client->dispatchDidReceiveResponse(loader, identifier, r); - - if (Page* page = m_frame->page()) - page->inspectorController()->didReceiveResponse(loader, identifier, r); -} - -void FrameLoader::dispatchDidReceiveContentLength(DocumentLoader* loader, unsigned long identifier, int length) -{ - m_client->dispatchDidReceiveContentLength(loader, identifier, length); - - if (Page* page = m_frame->page()) - page->inspectorController()->didReceiveContentLength(loader, identifier, length); -} - -void FrameLoader::dispatchDidFinishLoading(DocumentLoader* loader, unsigned long identifier) -{ - m_client->dispatchDidFinishLoading(loader, identifier); - - if (Page* page = m_frame->page()) - page->inspectorController()->didFinishLoading(loader, identifier); -} - -#if USE(LOW_BANDWIDTH_DISPLAY) - -bool FrameLoader::addLowBandwidthDisplayRequest(CachedResource* cache) -{ - if (m_frame->document()->inLowBandwidthDisplay() == false) - return false; - - // if cache is loaded, don't add to the list, where notifyFinished() is expected. - if (cache->isLoaded()) - return false; - - switch (cache->type()) { - case CachedResource::CSSStyleSheet: - case CachedResource::Script: - m_needToSwitchOutLowBandwidthDisplay = true; - m_externalRequestsInLowBandwidthDisplay.add(cache); - cache->addClient(this); - return true; - case CachedResource::ImageResource: - case CachedResource::FontResource: -#if ENABLE(XSLT) - case CachedResource::XSLStyleSheet: -#endif -#if ENABLE(XBL) - case CachedResource::XBLStyleSheet: -#endif - return false; - } - - ASSERT_NOT_REACHED(); - return false; -} - -void FrameLoader::removeAllLowBandwidthDisplayRequests() -{ - HashSet<CachedResource*>::iterator end = m_externalRequestsInLowBandwidthDisplay.end(); - for (HashSet<CachedResource*>::iterator it = m_externalRequestsInLowBandwidthDisplay.begin(); it != end; ++it) - (*it)->removeClient(this); - m_externalRequestsInLowBandwidthDisplay.clear(); -} - -void FrameLoader::notifyFinished(CachedResource* script) -{ - HashSet<CachedResource*>::iterator it = m_externalRequestsInLowBandwidthDisplay.find(script); - if (it != m_externalRequestsInLowBandwidthDisplay.end()) { - (*it)->removeClient(this); - m_externalRequestsInLowBandwidthDisplay.remove(it); - switchOutLowBandwidthDisplayIfReady(); - } -} - -void FrameLoader::switchOutLowBandwidthDisplayIfReady() -{ - RefPtr<Document> oldDoc = m_frame->document(); - if (oldDoc->inLowBandwidthDisplay()) { - if (!m_needToSwitchOutLowBandwidthDisplay) { - // no need to switch, just reset state - oldDoc->setLowBandwidthDisplay(false); - removeAllLowBandwidthDisplayRequests(); - m_pendingSourceInLowBandwidthDisplay = String(); - m_finishedParsingDuringLowBandwidthDisplay = false; - return; - } else if (m_externalRequestsInLowBandwidthDisplay.isEmpty() || - m_pendingSourceInLowBandwidthDisplay.length() > cMaxPendingSourceLengthInLowBandwidthDisplay) { - // clear the flag first - oldDoc->setLowBandwidthDisplay(false); - - // similar to clear(), should be refactored to share more code - oldDoc->cancelParsing(); - oldDoc->detach(); - if (m_frame->script()->isEnabled()) - m_frame->script()->clearWindowShell(); - if (m_frame->view()) - m_frame->view()->clear(); - - // similar to begin(), should be refactored to share more code - RefPtr<Document> newDoc = DOMImplementation::createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode()); - m_frame->setDocument(newDoc); - newDoc->setURL(m_URL); - if (m_decoder) - newDoc->setDecoder(m_decoder.get()); - restoreDocumentState(); - dispatchWindowObjectAvailable(); - newDoc->implicitOpen(); - - // swap DocLoader ownership - DocLoader* docLoader = newDoc->docLoader(); - newDoc->setDocLoader(oldDoc->docLoader()); - newDoc->docLoader()->replaceDocument(newDoc.get()); - docLoader->replaceDocument(oldDoc.get()); - oldDoc->setDocLoader(docLoader); - - // drop the old doc - oldDoc = 0; - - // write decoded data to the new doc, similar to write() - if (m_pendingSourceInLowBandwidthDisplay.length()) { - // set cachePolicy to Cache to use the loaded resource - newDoc->docLoader()->setCachePolicy(CachePolicyCache); - if (m_decoder->encoding().usesVisualOrdering()) - newDoc->setVisuallyOrdered(); - newDoc->recalcStyle(Node::Force); - newDoc->tokenizer()->write(m_pendingSourceInLowBandwidthDisplay, true); - - if (m_finishedParsingDuringLowBandwidthDisplay) - newDoc->finishParsing(); - } - - // update rendering - newDoc->updateRendering(); - - // reset states - removeAllLowBandwidthDisplayRequests(); - m_pendingSourceInLowBandwidthDisplay = String(); - m_finishedParsingDuringLowBandwidthDisplay = false; - m_needToSwitchOutLowBandwidthDisplay = false; - } - } -} - -#endif - -void FrameLoader::unloadListenerChanged() { - m_client->unloadListenerChanged(); -} - -} // namespace WebCore diff --git a/webkit/pending/FrameLoader.h b/webkit/pending/FrameLoader.h deleted file mode 100644 index d90a30f..0000000 --- a/webkit/pending/FrameLoader.h +++ /dev/null @@ -1,702 +0,0 @@ -/* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 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 FrameLoader_h -#define FrameLoader_h - -#include "CachedResource.h" -#include "CachePolicy.h" -#include "FormState.h" -#include "FrameLoaderTypes.h" -#include "KURL.h" -#include "StringHash.h" -#include "Timer.h" -#include <wtf/Forward.h> -#include <wtf/HashSet.h> -#include <wtf/HashMap.h> -#include <wtf/Noncopyable.h> -#include <wtf/OwnPtr.h> -#include <wtf/RefPtr.h> -#include "ResourceRequest.h" -#if USE(LOW_BANDWIDTH_DISPLAY) -#include "CachedResourceClient.h" -#endif - -namespace WebCore { - - class Archive; - class ArchiveResource; - class AuthenticationChallenge; - class CachedPage; - class Document; - class DocumentLoader; - class Element; - class Event; - class FormData; - class Frame; - class FrameLoaderClient; - class HistoryItem; - class HTMLFormElement; - class HTMLFrameOwnerElement; - class IconLoader; - class IntSize; - class NavigationAction; - class Node; - class Page; - class RenderPart; - class ResourceError; - class ResourceLoader; - class ResourceRequest; - class ResourceResponse; - class SecurityOrigin; - class SharedBuffer; - class SubstituteData; - class TextResourceDecoder; - class Widget; - - struct FormSubmission; - struct FrameLoadRequest; - struct ScheduledRedirection; - struct WindowFeatures; - - bool isBackForwardLoadType(FrameLoadType); - - typedef void (*NavigationPolicyDecisionFunction)(void* argument, - const ResourceRequest&, PassRefPtr<FormState>, bool shouldContinue); - typedef void (*NewWindowPolicyDecisionFunction)(void* argument, - const ResourceRequest&, PassRefPtr<FormState>, const String& frameName, bool shouldContinue); - typedef void (*ContentPolicyDecisionFunction)(void* argument, PolicyAction); - - class PolicyCheck { - public: - PolicyCheck(); - - void clear(); - void set(const ResourceRequest&, PassRefPtr<FormState>, - NavigationPolicyDecisionFunction, void* argument); - void set(const ResourceRequest&, PassRefPtr<FormState>, const String& frameName, - NewWindowPolicyDecisionFunction, void* argument); - void set(ContentPolicyDecisionFunction, void* argument); - - const ResourceRequest& request() const { return m_request; } - void clearRequest(); - - void call(bool shouldContinue); - void call(PolicyAction); - void cancel(); - - private: - ResourceRequest m_request; - RefPtr<FormState> m_formState; - String m_frameName; - - NavigationPolicyDecisionFunction m_navigationFunction; - NewWindowPolicyDecisionFunction m_newWindowFunction; - ContentPolicyDecisionFunction m_contentFunction; - void* m_argument; - }; - - class FrameLoader : Noncopyable -#if USE(LOW_BANDWIDTH_DISPLAY) - , private CachedResourceClient -#endif - { - public: - FrameLoader(Frame*, FrameLoaderClient*); - ~FrameLoader(); - - void init(); - - Frame* frame() const { return m_frame; } - - // FIXME: This is not cool, people. We should aim to consolidate these variety of loading related methods into a smaller set, - // and try to reuse more of the same logic by extracting common code paths. - void prepareForLoadStart(); - void setupForReplace(); - void setupForReplaceByMIMEType(const String& newMIMEType); - - void loadWithDocumentLoader(DocumentLoader*, FrameLoadType, PassRefPtr<FormState>); // Calls continueLoadAfterNavigationPolicy - void load(DocumentLoader*); // Calls loadWithDocumentLoader - - void loadWithNavigationAction(const ResourceRequest&, const NavigationAction&, // Calls loadWithDocumentLoader() - FrameLoadType, PassRefPtr<FormState>); - - void loadPostRequest(const ResourceRequest& inRequest, const String& referrer, // Called by loadFrameRequestWithFormAndValues(), calls loadWithNavigationAction - const String& frameName, Event* event, PassRefPtr<FormState> prpFormState); - - void loadURL(const KURL& newURL, const String& referrer, const String& frameName, // Called by loadFrameRequestWithFormAndValues(), calls loadWithNavigationAction or else dispatches to navigation policy delegate - FrameLoadType, Event* event, PassRefPtr<FormState> prpFormState); - void loadURLIntoChildFrame(const KURL&, const String& referer, Frame*); - - void loadFrameRequestWithFormState(const FrameLoadRequest&, bool lockHistory, Event*, PassRefPtr<FormState>); - void loadFrameRequestWithFormAndValues(const FrameLoadRequest&, bool lockHistory, // Called by submitForm, calls loadPostRequest() - Event*, HTMLFormElement*, const HashMap<String, String>& formValues); - - void load(const ResourceRequest&); // Called by WebFrame, calls (ResourceRequest, SubstituteData) - void load(const ResourceRequest&, const SubstituteData&); // Called both by WebFrame and internally, calls (DocumentLoader*) - void load(const ResourceRequest&, const String& frameName); // Called by WebPluginController - - void loadArchive(PassRefPtr<Archive> archive); - - // Returns true for any non-local URL. If Document parameter is supplied, its local load policy dictates, - // otherwise if referrer is non-empty and represents a local file, then the local load is allowed. - static bool canLoad(const KURL&, const String& referrer, const Document* theDocument = 0); - static void reportLocalLoadFailed(Frame*, const String& url); - - static bool shouldHideReferrer(const KURL& url, const String& referrer); - - // Called by createWindow in JSDOMWindowBase.cpp, e.g. to fulfill a modal dialog creation - Frame* createWindow(FrameLoader* frameLoaderForFrameLookup, const FrameLoadRequest&, const WindowFeatures&, bool& created); - - unsigned long loadResourceSynchronously(const ResourceRequest&, ResourceError&, ResourceResponse&, Vector<char>& data); - - bool canHandleRequest(const ResourceRequest&); - - // Also not cool. - void stopAllLoaders(); - void stopForUserCancel(bool deferCheckLoadComplete = false); - - bool isLoadingMainResource() const { return m_isLoadingMainResource; } - bool isLoading() const; - bool frameHasLoaded() const; - - int numPendingOrLoadingRequests(bool recurse) const; - bool isReloading() const; - String referrer() const; - String outgoingReferrer() const; - void loadEmptyDocumentSynchronously(); - - DocumentLoader* activeDocumentLoader() const; - DocumentLoader* documentLoader() const; - DocumentLoader* policyDocumentLoader() const; - DocumentLoader* provisionalDocumentLoader() const; - DocumentLoader* policyDocumentLoader(); - FrameState state() const; - static double timeOfLastCompletedLoad(); - - void didReceiveAuthenticationChallenge(ResourceLoader*, const AuthenticationChallenge&); - void didCancelAuthenticationChallenge(ResourceLoader*, const AuthenticationChallenge&); - - void assignIdentifierToInitialRequest(unsigned long identifier, const ResourceRequest&); - void willSendRequest(ResourceLoader*, ResourceRequest&, const ResourceResponse& redirectResponse); - void didReceiveResponse(ResourceLoader*, const ResourceResponse&); - void didReceiveData(ResourceLoader*, const char*, int, int lengthReceived); - void didFinishLoad(ResourceLoader*); - void didFailToLoad(ResourceLoader*, const ResourceError&); - const ResourceRequest& originalRequest() const; - const ResourceRequest& initialRequest() const; - void receivedMainResourceError(const ResourceError&, bool isComplete); - void receivedData(const char*, int); - - void handleFallbackContent(); - bool isStopping() const; - - void finishedLoading(); - - ResourceError cancelledError(const ResourceRequest&) const; - ResourceError fileDoesNotExistError(const ResourceResponse&) const; - ResourceError blockedError(const ResourceRequest&) const; - ResourceError cannotShowURLError(const ResourceRequest&) const; - - void cannotShowMIMEType(const ResourceResponse&); - ResourceError interruptionForPolicyChangeError(const ResourceRequest&); - - bool isHostedByObjectElement() const; - bool isLoadingMainFrame() const; - bool canShowMIMEType(const String& MIMEType) const; - bool representationExistsForURLScheme(const String& URLScheme); - String generatedMIMETypeForURLScheme(const String& URLScheme); - - void notifyIconChanged(); - - void checkNavigationPolicy(const ResourceRequest&, NavigationPolicyDecisionFunction function, void* argument); - void checkContentPolicy(const String& MIMEType, ContentPolicyDecisionFunction, void* argument); - void cancelContentPolicyCheck(); - - void reload(); - void reloadAllowingStaleData(const String& overrideEncoding); - - void didReceiveServerRedirectForProvisionalLoadForFrame(); - void finishedLoadingDocument(DocumentLoader*); - void committedLoad(DocumentLoader*, const char*, int); - bool isReplacing() const; - void setReplacing(); - void revertToProvisional(DocumentLoader*); - void setMainDocumentError(DocumentLoader*, const ResourceError&); - void mainReceivedCompleteError(DocumentLoader*, const ResourceError&); - bool subframeIsLoading() const; - void willChangeTitle(DocumentLoader*); - void didChangeTitle(DocumentLoader*); - - FrameLoadType loadType() const; - FrameLoadType policyLoadType() const { return m_policyLoadType; } - - void didFirstLayout(); - bool firstLayoutDone() const; - - void clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress); - void clientRedirected(const KURL&, double delay, double fireDate, bool lockHistory, bool isJavaScriptFormAction); - bool shouldReload(const KURL& currentURL, const KURL& destinationURL); - - bool isQuickRedirectComing() const; - - void sendRemainingDelegateMessages(unsigned long identifier, const ResourceResponse&, int length, const ResourceError&); - void requestFromDelegate(ResourceRequest&, unsigned long& identifier, ResourceError&); - void loadedResourceFromMemoryCache(const CachedResource*); - - void recursiveCheckLoadComplete(); - void checkLoadComplete(); - void detachFromParent(); - void detachChildren(); - - void addExtraFieldsToRequest(ResourceRequest&, bool isMainResource, bool alwaysFromRequest); - - FrameLoaderClient* client() const; - - void setDefersLoading(bool); - - void changeLocation(const String& url, const String& referrer, bool lockHistory = true, bool userGesture = false); - void changeLocation(const KURL&, const String& referrer, bool lockHistory = true, bool userGesture = false); - void urlSelected(const ResourceRequest&, const String& target, Event*, bool lockHistory, bool userGesture); - void urlSelected(const FrameLoadRequest&, Event*, bool lockHistory); - - bool requestFrame(HTMLFrameOwnerElement*, const String& url, const AtomicString& frameName); - Frame* loadSubframe(HTMLFrameOwnerElement*, const KURL&, const String& name, const String& referrer); - - void submitForm(const char* action, const String& url, PassRefPtr<FormData>, const String& target, const String& contentType, const String& boundary, Event*); - void submitFormAgain(); - void submitForm(const FrameLoadRequest&, Event*); - - void stop(); - void stopLoading(bool sendUnload); - bool closeURL(); - - void didExplicitOpen(); - - KURL iconURL(); - void commitIconURLToIconDatabase(const KURL&); - - KURL baseURL() const; - String baseTarget() const; - KURL dataURLBaseFromRequest(const ResourceRequest& request) const; - - bool isScheduledLocationChangePending() const { return m_scheduledRedirection && isLocationChange(*m_scheduledRedirection); } - void scheduleHTTPRedirection(double delay, const String& url); - void scheduleLocationChange(const String& url, const String& referrer, bool lockHistory = true, bool userGesture = false); - void scheduleRefresh(bool userGesture = false); - void scheduleHistoryNavigation(int steps); - - bool canGoBackOrForward(int distance) const; - void goBackOrForward(int distance); - void goToHistoryItem(HistoryItem* item); - int getHistoryLength(); - KURL historyURL(int distance); - - void begin(); - void begin(const KURL&, bool dispatchWindowObjectAvailable = true, SecurityOrigin* forcedSecurityOrigin = 0); - - void write(const char* str, int len = -1, bool flush = false); - void write(const String&); - void end(); - void endIfNotLoadingMainResource(); - - void setEncoding(const String& encoding, bool userChosen); - String encoding() const; - - // Returns true if url is a JavaScript URL. - bool executeIfJavaScriptURL(const KURL& url, bool userGesture = false, bool replaceDocument = true); - - // Executes a script, ignore the result. For back compability. - void executeScript(const String& url, int baseLine, const String& script); - void executeScript(const String& script, bool forceUserGesture = false); - - // Executes a script, returns results as a string, and sets succ - // to true if no errors. - String executeScript(const String& url, int baseLine, const String& script, bool* succ); - String executeScript(const String& script, bool* succ, bool forceUserGesture = false); - - void gotoAnchor(); - bool gotoAnchor(const String& name); // returns true if the anchor was found - void scrollToAnchor(const KURL&); - - void tokenizerProcessedData(); - - void handledOnloadEvents(); - String userAgent(const KURL&) const; - - Widget* createJavaAppletWidget(const IntSize&, Element*, const HashMap<String, String>& args); - - void dispatchWindowObjectAvailable(); - void restoreDocumentState(); - - Frame* opener(); - void setOpener(Frame*); - bool openedByDOM() const; - void setOpenedByDOM(); - - void provisionalLoadStarted(); - - bool userGestureHint(); - - void resetMultipleFormSubmissionProtection(); - void didNotOpenURL(const KURL&); - - void addData(const char* bytes, int length); - - bool canCachePage(); - - void checkCallImplicitClose(); - bool didOpenURL(const KURL&); - - void frameDetached(); - - const KURL& url() const { return m_URL; } - - void updateBaseURLForEmptyDocument(); - - void setResponseMIMEType(const String&); - const String& responseMIMEType() const; - - bool containsPlugins() const; - - void loadDone(); - void finishedParsing(); - void checkCompleted(); - void scheduleCheckCompleted(); - void scheduleCheckLoadComplete(); - - void clearRecordedFormValues(); - void setFormAboutToBeSubmitted(PassRefPtr<HTMLFormElement> element); - void recordFormValue(const String& name, const String& value); - - bool isComplete() const; - - bool requestObject(RenderPart* frame, const String& url, const AtomicString& frameName, - const String& serviceType, const Vector<String>& paramNames, const Vector<String>& paramValues); - - KURL completeURL(const String& url); - - void didTellClientAboutLoad(const String& url); - bool haveToldClientAboutLoad(const String& url); - - KURL originalRequestURL() const; - - void cancelAndClear(); - - void setTitle(const String&); - - bool shouldTreatURLAsSameAsCurrent(const KURL&) const; - - void commitProvisionalLoad(PassRefPtr<CachedPage>); - - void goToItem(HistoryItem*, FrameLoadType); - void saveDocumentAndScrollState(); - void saveScrollPositionAndViewStateToItem(HistoryItem*); - - // FIXME: These accessors are here for a dwindling number of users in WebKit, WebFrame - // being the primary one. After they're no longer needed there, they can be removed! - HistoryItem* currentHistoryItem(); - HistoryItem* previousHistoryItem(); - HistoryItem* provisionalHistoryItem(); - void setCurrentHistoryItem(PassRefPtr<HistoryItem>); - void setPreviousHistoryItem(PassRefPtr<HistoryItem>); - void setProvisionalHistoryItem(PassRefPtr<HistoryItem>); - - void continueLoadWithData(SharedBuffer*, const String& mimeType, const String& textEncoding, const KURL&); - - enum LocalLoadPolicy { - AllowLocalLoadsForAll, // No restriction on local loads. - AllowLocalLoadsForLocalAndSubstituteData, - AllowLocalLoadsForLocalOnly, - }; - static void setLocalLoadPolicy(LocalLoadPolicy); - static bool restrictAccessToLocal(); - static bool allowSubstituteDataAccessToLocal(); - - static void registerURLSchemeAsLocal(const String& scheme); - static bool shouldTreatURLAsLocal(const String&); - static bool shouldTreatSchemeAsLocal(const String&); - -#if USE(LOW_BANDWIDTH_DISPLAY) - bool addLowBandwidthDisplayRequest(CachedResource*); - void needToSwitchOutLowBandwidthDisplay() { m_needToSwitchOutLowBandwidthDisplay = true; } - - // Client can control whether to use low bandwidth display on a per frame basis. - // However, this should only be used for the top frame, not sub-frame. - void setUseLowBandwidthDisplay(bool lowBandwidth) { m_useLowBandwidthDisplay = lowBandwidth; } - bool useLowBandwidthDisplay() const { return m_useLowBandwidthDisplay; } -#endif - - bool committingFirstRealLoad() const { return !m_creatingInitialEmptyDocument && !m_committedFirstRealDocumentLoad; } - - void iconLoadDecisionAvailable(); - - bool shouldAllowNavigation(Frame* targetFrame) const; - Frame* findFrameForNavigation(const AtomicString& name); - - void startIconLoader(); - - void applyUserAgent(ResourceRequest& request); - - bool firingUnloadEvents() { return m_firingUnloadEvents; } - void setFiringUnloadEvents(bool value) { m_firingUnloadEvents = value; } - - void unloadListenerChanged(); - - private: - PassRefPtr<HistoryItem> createHistoryItem(bool useOriginal); - PassRefPtr<HistoryItem> createHistoryItemTree(Frame* targetFrame, bool clipAtTarget); - - void addBackForwardItemClippedAtTarget(bool doClip); - void restoreScrollPositionAndViewState(); - void saveDocumentState(); - void loadItem(HistoryItem*, FrameLoadType); - bool urlsMatchItem(HistoryItem*) const; - void invalidateCurrentItemCachedPage(); - void recursiveGoToItem(HistoryItem*, HistoryItem*, FrameLoadType); - bool childFramesMatchItem(HistoryItem*) const; - - void updateHistoryForBackForwardNavigation(); - void updateHistoryForReload(); - void updateHistoryForStandardLoad(); - void updateHistoryForRedirectWithLockedHistory(); - void updateHistoryForClientRedirect(); - void updateHistoryForCommit(); - void updateHistoryForAnchorScroll(); - - void redirectionTimerFired(Timer<FrameLoader>*); - void checkCompletedTimerFired(Timer<FrameLoader>*); - void checkLoadCompleteTimerFired(Timer<FrameLoader>*); - - void cancelRedirection(bool newLoadInProgress = false); - - void started(); - - void completed(); - void parentCompleted(); - - bool shouldUsePlugin(const KURL&, const String& mimeType, bool hasFallback, bool& useFallback); - bool loadPlugin(RenderPart*, const KURL&, const String& mimeType, - const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback); - - bool loadProvisionalItemFromCachedPage(); - void cachePageForHistoryItem(HistoryItem*); - - void receivedFirstData(); - - void updatePolicyBaseURL(); - void setPolicyBaseURL(const KURL&); - - // Also not cool. - void stopLoadingSubframes(); - - void clearProvisionalLoad(); - void markLoadComplete(); - void transitionToCommitted(PassRefPtr<CachedPage>); - void frameLoadCompleted(); - - void mainReceivedError(const ResourceError&, bool isComplete); - - void setLoadType(FrameLoadType); - - void checkNavigationPolicy(const ResourceRequest&, DocumentLoader*, PassRefPtr<FormState>, - NavigationPolicyDecisionFunction, void* argument); - void checkNewWindowPolicy(const NavigationAction&, const ResourceRequest&, - PassRefPtr<FormState>, const String& frameName); - - void continueAfterNavigationPolicy(PolicyAction); - void continueAfterNewWindowPolicy(PolicyAction); - void continueAfterContentPolicy(PolicyAction); - void continueLoadAfterWillSubmitForm(PolicyAction = PolicyUse); - - static void callContinueLoadAfterNavigationPolicy(void*, const ResourceRequest&, PassRefPtr<FormState>, bool shouldContinue); - void continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState>, bool shouldContinue); - static void callContinueLoadAfterNewWindowPolicy(void*, const ResourceRequest&, PassRefPtr<FormState>, const String& frameName, bool shouldContinue); - void continueLoadAfterNewWindowPolicy(const ResourceRequest&, PassRefPtr<FormState>, const String& frameName, bool shouldContinue); - static void callContinueFragmentScrollAfterNavigationPolicy(void*, const ResourceRequest&, PassRefPtr<FormState>, bool shouldContinue); - void continueFragmentScrollAfterNavigationPolicy(const ResourceRequest&, bool shouldContinue); - bool shouldScrollToAnchor(bool isFormSubmission, FrameLoadType loadType, const KURL& url); - void addHistoryItemForFragmentScroll(); - - void stopPolicyCheck(); - - void closeDocument(); - - void checkLoadCompleteForThisFrame(); - - void setDocumentLoader(DocumentLoader*); - void setPolicyDocumentLoader(DocumentLoader*); - void setProvisionalDocumentLoader(DocumentLoader*); - - void setState(FrameState); - - void closeOldDataSources(); - void open(CachedPage&); - void opened(); - void updateHistoryAfterClientRedirect(); - - void clear(bool clearWindowProperties = true, bool clearScriptObjects = true); - - bool shouldReloadToHandleUnreachableURL(DocumentLoader*); - void handleUnimplementablePolicy(const ResourceError&); - - void scheduleRedirection(ScheduledRedirection*); - void startRedirectionTimer(); - void stopRedirectionTimer(); - -#if USE(LOW_BANDWIDTH_DISPLAY) - // implementation of CachedResourceClient - virtual void notifyFinished(CachedResource*); - - void removeAllLowBandwidthDisplayRequests(); - void switchOutLowBandwidthDisplayIfReady(); -#endif - - void dispatchDidCommitLoad(); - void dispatchAssignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader*, const ResourceRequest&); - void dispatchWillSendRequest(DocumentLoader*, unsigned long identifier, ResourceRequest&, const ResourceResponse& redirectResponse); - void dispatchDidReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse&); - void dispatchDidReceiveContentLength(DocumentLoader*, unsigned long identifier, int length); - void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier); - - static bool isLocationChange(const ScheduledRedirection&); - - Frame* m_frame; - FrameLoaderClient* m_client; - - FrameState m_state; - FrameLoadType m_loadType; - - // Document loaders for the three phases of frame loading. Note that while - // a new request is being loaded, the old document loader may still be referenced. - // E.g. while a new request is in the "policy" state, the old document loader may - // be consulted in particular as it makes sense to imply certain settings on the new loader. - RefPtr<DocumentLoader> m_documentLoader; - RefPtr<DocumentLoader> m_provisionalDocumentLoader; - RefPtr<DocumentLoader> m_policyDocumentLoader; - - // This identifies the type of navigation action which prompted this load. Note - // that WebKit conveys this value as the WebActionNavigationTypeKey value - // on navigation action delegate callbacks. - FrameLoadType m_policyLoadType; - PolicyCheck m_policyCheck; - - bool m_delegateIsHandlingProvisionalLoadError; - bool m_delegateIsDecidingNavigationPolicy; - bool m_delegateIsHandlingUnimplementablePolicy; - - bool m_firstLayoutDone; - bool m_quickRedirectComing; - bool m_sentRedirectNotification; - bool m_inStopAllLoaders; - bool m_navigationDuringLoad; - - String m_outgoingReferrer; - - CachePolicy m_cachePolicy; - - HashSet<String> m_urlsClientKnowsAbout; - - OwnPtr<FormSubmission> m_deferredFormSubmission; - - bool m_isExecutingJavaScriptFormAction; - bool m_isRunningScript; - - String m_responseMIMEType; - - bool m_didCallImplicitClose; - bool m_wasUnloadEventEmitted; - bool m_isComplete; - bool m_isLoadingMainResource; - bool m_firingUnloadEvents; // frame or loader is firing unload or beforeUnload events. - - KURL m_URL; - KURL m_workingURL; - - OwnPtr<IconLoader> m_iconLoader; - bool m_mayLoadIconLater; - - bool m_cancellingWithLoadInProgress; - - OwnPtr<ScheduledRedirection> m_scheduledRedirection; - - bool m_needsClear; - bool m_receivedData; - - bool m_encodingWasChosenByUser; - String m_encoding; - RefPtr<TextResourceDecoder> m_decoder; - - bool m_containsPlugIns; - - RefPtr<HTMLFormElement> m_formAboutToBeSubmitted; - HashMap<String, String> m_formValuesAboutToBeSubmitted; - KURL m_submittedFormURL; - - Timer<FrameLoader> m_redirectionTimer; - Timer<FrameLoader> m_checkCompletedTimer; - Timer<FrameLoader> m_checkLoadCompleteTimer; - - Frame* m_opener; - HashSet<Frame*> m_openedFrames; - - bool m_openedByDOM; - - bool m_creatingInitialEmptyDocument; - bool m_isDisplayingInitialEmptyDocument; - bool m_committedFirstRealDocumentLoad; - - RefPtr<HistoryItem> m_currentHistoryItem; - RefPtr<HistoryItem> m_previousHistoryItem; - RefPtr<HistoryItem> m_provisionalHistoryItem; - - bool m_didPerformFirstNavigation; - -#ifndef NDEBUG - bool m_didDispatchDidCommitLoad; -#endif - -#if USE(LOW_BANDWIDTH_DISPLAY) - // whether to use low bandwidth dislay, set by client - bool m_useLowBandwidthDisplay; - - // whether to call finishParsing() in switchOutLowBandwidthDisplayIfReady() - bool m_finishedParsingDuringLowBandwidthDisplay; - - // whether to call switchOutLowBandwidthDisplayIfReady; - // true if there is external css, javascript, or subframe/plugin - bool m_needToSwitchOutLowBandwidthDisplay; - - String m_pendingSourceInLowBandwidthDisplay; - HashSet<CachedResource*> m_externalRequestsInLowBandwidthDisplay; -#endif - }; - -} - -#endif diff --git a/webkit/pending/FrameLoaderClient.h b/webkit/pending/FrameLoaderClient.h deleted file mode 100644 index 0c2ee59..0000000 --- a/webkit/pending/FrameLoaderClient.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 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 FrameLoaderClient_h -#define FrameLoaderClient_h - -#include "FrameLoaderTypes.h" -#include <wtf/Forward.h> -#include <wtf/Platform.h> -#include <wtf/Vector.h> - -typedef class _jobject* jobject; - -#if PLATFORM(MAC) && !defined(__OBJC__) -class NSCachedURLResponse; -class NSView; -#endif - -namespace WebCore { - - class AuthenticationChallenge; - class CachedPage; - class DocumentLoader; - class Element; - class FormState; - class Frame; - class FrameLoader; - class HistoryItem; - class HTMLFrameOwnerElement; - class IntSize; - class KURL; - class NavigationAction; - class ResourceError; - class ResourceHandle; - class ResourceLoader; - class ResourceResponse; - class SharedBuffer; - class SubstituteData; - class String; - class Widget; - - class ResourceRequest; - - typedef void (FrameLoader::*FramePolicyFunction)(PolicyAction); - - class FrameLoaderClient { - public: - virtual ~FrameLoaderClient() { } - virtual void frameLoaderDestroyed() = 0; - - virtual bool hasWebView() const = 0; // mainly for assertions - virtual bool hasFrameView() const = 0; // ditto - - virtual bool hasHTMLView() const { return true; } - - virtual void makeRepresentation(DocumentLoader*) = 0; - virtual void forceLayout() = 0; - virtual void forceLayoutForNonHTML() = 0; - - virtual void setCopiesOnScroll() = 0; - - virtual void detachedFromParent2() = 0; - virtual void detachedFromParent3() = 0; - virtual void detachedFromParent4() = 0; - - virtual void assignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader*, const ResourceRequest&) = 0; - - virtual void dispatchWillSendRequest(DocumentLoader*, unsigned long identifier, ResourceRequest&, const ResourceResponse& redirectResponse) = 0; - virtual void dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) = 0; - virtual void dispatchDidCancelAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) = 0; - virtual void dispatchDidReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse&) = 0; - virtual void dispatchDidReceiveContentLength(DocumentLoader*, unsigned long identifier, int lengthReceived) = 0; - virtual void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier) = 0; - virtual void dispatchDidFailLoading(DocumentLoader*, unsigned long identifier, const ResourceError&) = 0; - virtual bool dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int length) = 0; - - virtual void dispatchDidHandleOnloadEvents() = 0; - virtual void dispatchDidReceiveServerRedirectForProvisionalLoad() = 0; - virtual void dispatchDidCancelClientRedirect() = 0; - virtual void dispatchWillPerformClientRedirect(const KURL&, double interval, double fireDate) = 0; - virtual void dispatchDidChangeLocationWithinPage() = 0; - virtual void dispatchWillClose() = 0; - virtual void dispatchDidReceiveIcon() = 0; - virtual void dispatchDidStartProvisionalLoad() = 0; - virtual void dispatchDidReceiveTitle(const String& title) = 0; - virtual void dispatchDidCommitLoad() = 0; - virtual void dispatchDidFailProvisionalLoad(const ResourceError&) = 0; - virtual void dispatchDidFailLoad(const ResourceError&) = 0; - virtual void dispatchDidFinishDocumentLoad() = 0; - virtual void dispatchDidFinishLoad() = 0; - virtual void dispatchDidFirstLayout() = 0; - - virtual Frame* dispatchCreatePage() = 0; - virtual void dispatchShow() = 0; - - virtual void dispatchDecidePolicyForMIMEType(FramePolicyFunction, const String& MIMEType, const ResourceRequest&) = 0; - virtual void dispatchDecidePolicyForNewWindowAction(FramePolicyFunction, const NavigationAction&, const ResourceRequest&, PassRefPtr<FormState>, const String& frameName) = 0; - virtual void dispatchDecidePolicyForNavigationAction(FramePolicyFunction, const NavigationAction&, const ResourceRequest&, PassRefPtr<FormState>) = 0; - virtual void cancelPolicyCheck() = 0; - - virtual void dispatchUnableToImplementPolicy(const ResourceError&) = 0; - - virtual void dispatchWillSubmitForm(FramePolicyFunction, PassRefPtr<FormState>) = 0; - - virtual void dispatchDidLoadMainResource(DocumentLoader*) = 0; - virtual void revertToProvisionalState(DocumentLoader*) = 0; - virtual void setMainDocumentError(DocumentLoader*, const ResourceError&) = 0; - - // Maybe these should go into a ProgressTrackerClient some day - virtual void willChangeEstimatedProgress() { } - virtual void didChangeEstimatedProgress() { } - virtual void postProgressStartedNotification() = 0; - virtual void postProgressEstimateChangedNotification() = 0; - virtual void postProgressFinishedNotification() = 0; - - virtual void setMainFrameDocumentReady(bool) = 0; - - virtual void startDownload(const ResourceRequest&) = 0; - - virtual void willChangeTitle(DocumentLoader*) = 0; - virtual void didChangeTitle(DocumentLoader*) = 0; - - virtual void committedLoad(DocumentLoader*, const char*, int) = 0; - virtual void finishedLoading(DocumentLoader*) = 0; - - virtual void updateGlobalHistory(const KURL&) = 0; - virtual bool shouldGoToHistoryItem(HistoryItem*) const = 0; - - virtual ResourceError cancelledError(const ResourceRequest&) = 0; - virtual ResourceError blockedError(const ResourceRequest&) = 0; - virtual ResourceError cannotShowURLError(const ResourceRequest&) = 0; - virtual ResourceError interruptForPolicyChangeError(const ResourceRequest&) = 0; - - virtual ResourceError cannotShowMIMETypeError(const ResourceResponse&) = 0; - virtual ResourceError fileDoesNotExistError(const ResourceResponse&) = 0; - virtual ResourceError pluginWillHandleLoadError(const ResourceResponse&) = 0; - - virtual bool shouldFallBack(const ResourceError&) = 0; - - virtual bool canHandleRequest(const ResourceRequest&) const = 0; - virtual bool canShowMIMEType(const String& MIMEType) const = 0; - virtual bool representationExistsForURLScheme(const String& URLScheme) const = 0; - virtual String generatedMIMETypeForURLScheme(const String& URLScheme) const = 0; - - virtual void frameLoadCompleted() = 0; - virtual void saveViewStateToItem(HistoryItem*) = 0; - virtual void restoreViewState() = 0; - virtual void provisionalLoadStarted() = 0; - virtual void didFinishLoad() = 0; - virtual void prepareForDataSourceReplacement() = 0; - - virtual PassRefPtr<DocumentLoader> createDocumentLoader(const ResourceRequest&, const SubstituteData&) = 0; - virtual void setTitle(const String& title, const KURL&) = 0; - - virtual String userAgent(const KURL&) = 0; - - virtual void savePlatformDataToCachedPage(CachedPage*) = 0; - virtual void transitionToCommittedFromCachedPage(CachedPage*) = 0; - virtual void transitionToCommittedForNewPage() = 0; - - virtual bool canCachePage() const = 0; - virtual void download(ResourceHandle*, const ResourceRequest&, const ResourceRequest&, const ResourceResponse&) = 0; - - virtual PassRefPtr<Frame> createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement, - const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight) = 0; - virtual Widget* createPlugin(const IntSize&, Element*, const KURL&, const Vector<String>&, const Vector<String>&, const String&, bool loadManually) = 0; - virtual void redirectDataToPlugin(Widget* pluginWidget) = 0; - - virtual Widget* createJavaAppletWidget(const IntSize&, Element*, const KURL& baseURL, const Vector<String>& paramNames, const Vector<String>& paramValues) = 0; - - virtual ObjectContentType objectContentType(const KURL& url, const String& mimeType) = 0; - virtual String overrideMediaType() const = 0; - - virtual void windowObjectCleared() = 0; - virtual void didPerformFirstNavigation() const = 0; // "Navigation" here means a transition from one page to another that ends up in the back/forward list. - - virtual void registerForIconNotification(bool listen = true) = 0; - - virtual void unloadListenerChanged() = 0; - -#if PLATFORM(MAC) -#if ENABLE(MAC_JAVA_BRIDGE) - virtual jobject javaApplet(NSView*) { return 0; } -#endif - virtual NSCachedURLResponse* willCacheResponse(DocumentLoader*, unsigned long identifier, NSCachedURLResponse*) const = 0; -#endif - }; - -} // namespace WebCore - -#endif // FrameLoaderClient_h |