diff options
author | Feng Qian <fqian@google.com> | 2009-06-18 18:20:56 -0700 |
---|---|---|
committer | Feng Qian <fqian@google.com> | 2009-06-18 18:20:56 -0700 |
commit | 1edef79f87f9c52c21d69c87c19f8e2b140a9119 (patch) | |
tree | cad337ef493b0d9710bf3ae478cb87cb534f598d /WebCore/html | |
parent | b83fc086000e27bc227580bd0e35b9d7bee1179a (diff) | |
parent | c9c4d65c1547996ed3748026904d6e7f09aec2b4 (diff) | |
download | external_webkit-1edef79f87f9c52c21d69c87c19f8e2b140a9119.zip external_webkit-1edef79f87f9c52c21d69c87c19f8e2b140a9119.tar.gz external_webkit-1edef79f87f9c52c21d69c87c19f8e2b140a9119.tar.bz2 |
Merge commit 'goog/master-webkit-merge' into webkit-merge-44544
Diffstat (limited to 'WebCore/html')
127 files changed, 1814 insertions, 1609 deletions
diff --git a/WebCore/html/CanvasPixelArray.idl b/WebCore/html/CanvasPixelArray.idl index 9b333e4..c815788 100644 --- a/WebCore/html/CanvasPixelArray.idl +++ b/WebCore/html/CanvasPixelArray.idl @@ -27,7 +27,7 @@ */ module html { -#if !defined(LANGUAGE_JAVASCRIPT) || defined(V8_BINDING) +#if !defined(LANGUAGE_JAVASCRIPT) || !LANGUAGE_JAVASCRIPT || defined(V8_BINDING) && V8_BINDING interface [ CustomHeader, HasCustomIndexGetter, diff --git a/WebCore/html/CanvasRenderingContext2D.cpp b/WebCore/html/CanvasRenderingContext2D.cpp index 82680bd..f2541ed 100644 --- a/WebCore/html/CanvasRenderingContext2D.cpp +++ b/WebCore/html/CanvasRenderingContext2D.cpp @@ -36,6 +36,7 @@ #include "CanvasGradient.h" #include "CanvasPattern.h" #include "CanvasStyle.h" +#include "CSSMutableStyleDeclaration.h" #include "CSSPropertyNames.h" #include "CSSStyleSelector.h" #include "Document.h" @@ -49,7 +50,6 @@ #include "ImageBuffer.h" #include "ImageData.h" #include "KURL.h" -#include "NotImplemented.h" #include "Page.h" #include "RenderHTMLCanvas.h" #include "SecurityOrigin.h" @@ -60,6 +60,7 @@ #include <wtf/ByteArray.h> #include <wtf/MathExtras.h> +#include <wtf/OwnPtr.h> using namespace std; @@ -95,6 +96,9 @@ CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas) : m_canvas(canvas) , m_stateStack(1) { + // Make sure that even if the drawingContext() has a different default + // thickness, it is in sync with the canvas thickness. + setLineWidth(lineWidth()); } void CanvasRenderingContext2D::ref() @@ -1442,8 +1446,8 @@ void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, flo // FIXME: The rect is not big enough for miters on stroked text. IntRect maskRect = enclosingIntRect(textRect); - auto_ptr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size(), false); - + OwnPtr<ImageBuffer> maskImage = ImageBuffer::create(maskRect.size(), false); + GraphicsContext* maskImageContext = maskImage->context(); if (fill) diff --git a/WebCore/html/CanvasStyle.cpp b/WebCore/html/CanvasStyle.cpp index 0aaaab2..37308ad 100644 --- a/WebCore/html/CanvasStyle.cpp +++ b/WebCore/html/CanvasStyle.cpp @@ -44,8 +44,6 @@ #include <QBrush> #include <QPen> #include <QColor> -#elif PLATFORM(CAIRO) -#include "NotImplemented.h" #endif namespace WebCore { diff --git a/WebCore/html/CollectionCache.cpp b/WebCore/html/CollectionCache.cpp new file mode 100644 index 0000000..feecd96 --- /dev/null +++ b/WebCore/html/CollectionCache.cpp @@ -0,0 +1,88 @@ +/* + * 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 "CollectionCache.h" + +namespace WebCore { + +CollectionCache::CollectionCache() + : version(0) +{ + reset(); +} + +inline void CollectionCache::copyCacheMap(NodeCacheMap& dest, const NodeCacheMap& src) +{ + ASSERT(dest.isEmpty()); + NodeCacheMap::const_iterator end = src.end(); + for (NodeCacheMap::const_iterator it = src.begin(); it != end; ++it) + dest.add(it->first, new Vector<Element*>(*it->second)); +} + +CollectionCache::CollectionCache(const CollectionCache& other) + : version(other.version) + , current(other.current) + , position(other.position) + , length(other.length) + , elementsArrayPosition(other.elementsArrayPosition) + , hasLength(other.hasLength) + , hasNameCache(other.hasNameCache) +{ + copyCacheMap(idCache, other.idCache); + copyCacheMap(nameCache, other.nameCache); +} + +void CollectionCache::swap(CollectionCache& other) +{ + std::swap(version, other.version); + std::swap(current, other.current); + std::swap(position, other.position); + std::swap(length, other.length); + std::swap(elementsArrayPosition, other.elementsArrayPosition); + + idCache.swap(other.idCache); + nameCache.swap(other.nameCache); + + std::swap(hasLength, other.hasLength); + std::swap(hasNameCache, other.hasNameCache); +} + +CollectionCache::~CollectionCache() +{ + deleteAllValues(idCache); + deleteAllValues(nameCache); +} + +void CollectionCache::reset() +{ + current = 0; + position = 0; + length = 0; + hasLength = false; + elementsArrayPosition = 0; + deleteAllValues(idCache); + idCache.clear(); + deleteAllValues(nameCache); + nameCache.clear(); + hasNameCache = false; +} + +} // namespace WebCore diff --git a/WebCore/html/CollectionCache.h b/WebCore/html/CollectionCache.h new file mode 100644 index 0000000..7cdcdd5 --- /dev/null +++ b/WebCore/html/CollectionCache.h @@ -0,0 +1,64 @@ +/* + * 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 CollectionCache_h +#define CollectionCache_h + +#include <wtf/HashMap.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class AtomicStringImpl; +class Element; + +struct CollectionCache { + CollectionCache(); + CollectionCache(const CollectionCache&); + CollectionCache& operator=(const CollectionCache& other) + { + CollectionCache tmp(other); + swap(tmp); + return *this; + } + ~CollectionCache(); + + void reset(); + void swap(CollectionCache&); + + typedef HashMap<AtomicStringImpl*, Vector<Element*>*> NodeCacheMap; + + unsigned version; + Element* current; + unsigned position; + unsigned length; + int elementsArrayPosition; + NodeCacheMap idCache; + NodeCacheMap nameCache; + bool hasLength; + bool hasNameCache; + +private: + static void copyCacheMap(NodeCacheMap&, const NodeCacheMap&); +}; + +} // namespace + +#endif diff --git a/WebCore/html/CollectionType.h b/WebCore/html/CollectionType.h new file mode 100644 index 0000000..e5973a3 --- /dev/null +++ b/WebCore/html/CollectionType.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2003, 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 CollectionType_h +#define CollectionType_h + +namespace WebCore { + +enum CollectionType { + // unnamed collection types cached in the document + + DocImages, // all <img> elements in the document + DocApplets, // all <object> and <applet> elements + DocEmbeds, // all <embed> elements + DocObjects, // all <object> elements + DocForms, // all <form> elements + DocLinks, // all <a> _and_ <area> elements with a value for href + DocAnchors, // all <a> elements with a value for name + DocScripts, // all <script> elements + + DocAll, // "all" elements (IE) + NodeChildren, // first-level children (IE) + + // named collection types cached in the document + + WindowNamedItems, + DocumentNamedItems, + + // types not cached in the document; these are types that can't be used on a document + + TableTBodies, // all <tbody> elements in this table + TSectionRows, // all row elements in this table section + TRCells, // all cells in this row + SelectOptions, + MapAreas, + + OtherCollection +}; + +static const CollectionType FirstUnnamedDocumentCachedType = DocImages; +static const unsigned NumUnnamedDocumentCachedTypes = NodeChildren - DocImages + 1; + +static const CollectionType FirstNamedDocumentCachedType = WindowNamedItems; +static const unsigned NumNamedDocumentCachedTypes = DocumentNamedItems - WindowNamedItems + 1; + +} // namespace + +#endif diff --git a/WebCore/html/HTMLAnchorElement.cpp b/WebCore/html/HTMLAnchorElement.cpp index c6b2a95..354f9f0 100644 --- a/WebCore/html/HTMLAnchorElement.cpp +++ b/WebCore/html/HTMLAnchorElement.cpp @@ -36,6 +36,7 @@ #include "HTMLImageElement.h" #include "HTMLNames.h" #include "KeyboardEvent.h" +#include "MappedAttribute.h" #include "MouseEvent.h" #include "MutationEvent.h" #include "Page.h" @@ -280,11 +281,17 @@ void HTMLAnchorElement::parseMappedAttribute(MappedAttribute *attr) bool wasLink = isLink(); setIsLink(!attr->isNull()); if (wasLink != isLink()) - setChanged(); - if (isLink() && document()->isDNSPrefetchEnabled()) { - String value = attr->value(); - if (protocolIs(value, "http") || protocolIs(value, "https") || value.startsWith("//")) - prefetchDNS(document()->completeURL(value).host()); + setNeedsStyleRecalc(); + if (isLink()) { + String parsedURL = parseURL(attr->value()); + if (document()->isDNSPrefetchEnabled()) { + if (protocolIs(parsedURL, "http") || protocolIs(parsedURL, "https") || parsedURL.startsWith("//")) + prefetchDNS(document()->completeURL(parsedURL).host()); + } + if (document()->page() && !document()->page()->javaScriptURLsAreAllowed() && protocolIsJavaScript(parsedURL)) { + setIsLink(false); + attr->setValue(nullAtom); + } } } else if (attr->name() == nameAttr || attr->name() == titleAttr || diff --git a/WebCore/html/HTMLAnchorElement.idl b/WebCore/html/HTMLAnchorElement.idl index f3a15ee..c2dda3d 100644 --- a/WebCore/html/HTMLAnchorElement.idl +++ b/WebCore/html/HTMLAnchorElement.idl @@ -47,11 +47,11 @@ module html { readonly attribute DOMString search; readonly attribute DOMString text; -#if defined(LANGUAGE_JAVASCRIPT) +#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT [DontEnum] DOMString toString(); #endif -#if defined(LANGUAGE_OBJECTIVE_C) +#if defined(LANGUAGE_OBJECTIVE_C) && LANGUAGE_OBJECTIVE_C // Objective-C extension: readonly attribute URL absoluteLinkURL; #endif diff --git a/WebCore/html/HTMLAppletElement.cpp b/WebCore/html/HTMLAppletElement.cpp index de8e1cf..13dd911 100644 --- a/WebCore/html/HTMLAppletElement.cpp +++ b/WebCore/html/HTMLAppletElement.cpp @@ -27,6 +27,7 @@ #include "Frame.h" #include "HTMLDocument.h" #include "HTMLNames.h" +#include "MappedAttribute.h" #include "RenderApplet.h" #include "RenderInline.h" #include "Settings.h" @@ -119,8 +120,6 @@ RenderObject* HTMLAppletElement::createRenderer(RenderArena*, RenderStyle* style const AtomicString& codeBase = getAttribute(codebaseAttr); if (!codeBase.isNull()) args.set("codeBase", codeBase); - else - args.set("codeBase", document()->baseURL().baseAsString()); const AtomicString& name = getAttribute(document()->isHTMLDocument() ? nameAttr : idAttr); if (!name.isNull()) diff --git a/WebCore/html/HTMLAppletElement.idl b/WebCore/html/HTMLAppletElement.idl index 794f000..95f03a7 100644 --- a/WebCore/html/HTMLAppletElement.idl +++ b/WebCore/html/HTMLAppletElement.idl @@ -35,14 +35,14 @@ module html { attribute [ConvertNullToNullString] DOMString code; attribute [ConvertNullToNullString] DOMString codeBase; attribute [ConvertNullToNullString] DOMString height; -#if defined(LANGUAGE_JAVASCRIPT) +#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT attribute [ConvertNullToNullString] DOMString hspace; #else attribute [ConvertFromString] long hspace; #endif attribute [ConvertNullToNullString] DOMString name; attribute [ConvertNullToNullString] DOMString object; -#if defined(LANGUAGE_JAVASCRIPT) +#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT attribute [ConvertNullToNullString] DOMString vspace; #else attribute [ConvertFromString] long vspace; diff --git a/WebCore/html/HTMLAreaElement.cpp b/WebCore/html/HTMLAreaElement.cpp index 9db50b7..2f7c1a5 100644 --- a/WebCore/html/HTMLAreaElement.cpp +++ b/WebCore/html/HTMLAreaElement.cpp @@ -27,6 +27,7 @@ #include "HTMLNames.h" #include "HitTestResult.h" #include "Length.h" +#include "MappedAttribute.h" #include "Path.h" #include "RenderObject.h" diff --git a/WebCore/html/HTMLAreaElement.idl b/WebCore/html/HTMLAreaElement.idl index 39cc719..d80ebed 100644 --- a/WebCore/html/HTMLAreaElement.idl +++ b/WebCore/html/HTMLAreaElement.idl @@ -42,7 +42,7 @@ module html { readonly attribute DOMString protocol; readonly attribute DOMString search; -#if defined(LANGUAGE_OBJECTIVE_C) +#if defined(LANGUAGE_OBJECTIVE_C) && LANGUAGE_OBJECTIVE_C // Objective-C extension: readonly attribute URL absoluteLinkURL; #endif diff --git a/WebCore/html/HTMLAttributeNames.in b/WebCore/html/HTMLAttributeNames.in index 5cb556e..7caf0e5 100644 --- a/WebCore/html/HTMLAttributeNames.in +++ b/WebCore/html/HTMLAttributeNames.in @@ -22,6 +22,7 @@ aria-pressed aria-valuemax aria-valuemin aria-valuenow +autobuffer autocomplete autofocus autoplay @@ -140,6 +141,8 @@ onmouseout onmouseover onmouseup onmousewheel +ononline +onoffline onpaste onreset onresize @@ -183,6 +186,7 @@ selected shape size span +spellcheck src standby start diff --git a/WebCore/html/HTMLBRElement.cpp b/WebCore/html/HTMLBRElement.cpp index e98f8d1..6f86e6a 100644 --- a/WebCore/html/HTMLBRElement.cpp +++ b/WebCore/html/HTMLBRElement.cpp @@ -19,11 +19,13 @@ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ + #include "config.h" #include "HTMLBRElement.h" #include "CSSPropertyNames.h" #include "HTMLNames.h" +#include "MappedAttribute.h" #include "RenderBR.h" namespace WebCore { diff --git a/WebCore/html/HTMLBaseElement.cpp b/WebCore/html/HTMLBaseElement.cpp index dd4f7b3..a278908 100644 --- a/WebCore/html/HTMLBaseElement.cpp +++ b/WebCore/html/HTMLBaseElement.cpp @@ -29,6 +29,7 @@ #include "FrameLoader.h" #include "HTMLNames.h" #include "KURL.h" +#include "MappedAttribute.h" namespace WebCore { diff --git a/WebCore/html/HTMLBaseFontElement.idl b/WebCore/html/HTMLBaseFontElement.idl index a94f3ab..f09c9d7 100644 --- a/WebCore/html/HTMLBaseFontElement.idl +++ b/WebCore/html/HTMLBaseFontElement.idl @@ -26,7 +26,7 @@ module html { ] HTMLBaseFontElement : HTMLElement { attribute [ConvertNullToNullString] DOMString color; attribute [ConvertNullToNullString] DOMString face; -#if defined(LANGUAGE_OBJECTIVE_C) +#if defined(LANGUAGE_OBJECTIVE_C) && LANGUAGE_OBJECTIVE_C attribute [ConvertToString] DOMString size; // this changed to a long, but our existing API is a string #else attribute long size; diff --git a/WebCore/html/HTMLBodyElement.cpp b/WebCore/html/HTMLBodyElement.cpp index a23f9be..9828dab 100644 --- a/WebCore/html/HTMLBodyElement.cpp +++ b/WebCore/html/HTMLBodyElement.cpp @@ -32,9 +32,12 @@ #include "CSSValueKeywords.h" #include "Document.h" #include "EventNames.h" +#include "Frame.h" #include "FrameView.h" #include "HTMLFrameElementBase.h" #include "HTMLNames.h" +#include "MappedAttribute.h" +#include "ScriptEventListener.h" namespace WebCore { @@ -131,25 +134,26 @@ void HTMLBodyElement::parseMappedAttribute(MappedAttribute *attr) if (attached()) document()->recalcStyle(Force); } else if (attr->name() == onloadAttr) - document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().loadEvent, attr); + document()->setWindowAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(document()->frame(), attr)); else if (attr->name() == onbeforeunloadAttr) - document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().beforeunloadEvent, attr); + document()->setWindowAttributeEventListener(eventNames().beforeunloadEvent, createAttributeEventListener(document()->frame(), attr)); else if (attr->name() == onunloadAttr) - document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().unloadEvent, attr); + document()->setWindowAttributeEventListener(eventNames().unloadEvent, createAttributeEventListener(document()->frame(), attr)); else if (attr->name() == onblurAttr) - document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().blurEvent, attr); + document()->setWindowAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(document()->frame(), attr)); else if (attr->name() == onfocusAttr) - document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().focusEvent, attr); + document()->setWindowAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(document()->frame(), attr)); else if (attr->name() == onresizeAttr) - document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().resizeEvent, attr); + document()->setWindowAttributeEventListener(eventNames().resizeEvent, createAttributeEventListener(document()->frame(), attr)); else if (attr->name() == onscrollAttr) - document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().scrollEvent, attr); - else if (attr->name() == onstorageAttr) { - // The HTML5 spec currently specifies that storage events are fired only at the body element of - // an HTMLDocument, which is why the onstorage attribute differs from the ones before it. - // The spec might change on this, and then so should we! - setInlineEventListenerForTypeAndAttribute(eventNames().storageEvent, attr); - } else + document()->setWindowAttributeEventListener(eventNames().scrollEvent, createAttributeEventListener(document()->frame(), attr)); + else if (attr->name() == onstorageAttr) + document()->setWindowAttributeEventListener(eventNames().storageEvent, createAttributeEventListener(document()->frame(), attr)); + else if (attr->name() == ononlineAttr) + document()->setWindowAttributeEventListener(eventNames().onlineEvent, createAttributeEventListener(document()->frame(), attr)); + else if (attr->name() == onofflineAttr) + document()->setWindowAttributeEventListener(eventNames().offlineEvent, createAttributeEventListener(document()->frame(), attr)); + else HTMLElement::parseMappedAttribute(attr); } @@ -240,13 +244,24 @@ void HTMLBodyElement::setVLink(const String& value) setAttribute(vlinkAttr, value); } +static int adjustForZoom(int value, FrameView* frameView) +{ + float zoomFactor = frameView->frame()->zoomFactor(); + if (zoomFactor == 1) + return value; + // Needed because of truncation (rather than rounding) when scaling up. + if (zoomFactor > 1) + value++; + return static_cast<int>(value / zoomFactor); +} + int HTMLBodyElement::scrollLeft() const { // Update the document's layout. Document* doc = document(); doc->updateLayoutIgnorePendingStylesheets(); FrameView* view = doc->view(); - return view ? view->scrollX() : 0; + return view ? adjustForZoom(view->scrollX(), view) : 0; } void HTMLBodyElement::setScrollLeft(int scrollLeft) @@ -255,7 +270,7 @@ void HTMLBodyElement::setScrollLeft(int scrollLeft) if (sview) { // Update the document's layout document()->updateLayoutIgnorePendingStylesheets(); - sview->setScrollPosition(IntPoint(scrollLeft, sview->scrollY())); + sview->setScrollPosition(IntPoint(static_cast<int>(scrollLeft * sview->frame()->zoomFactor()), sview->scrollY())); } } @@ -265,7 +280,7 @@ int HTMLBodyElement::scrollTop() const Document* doc = document(); doc->updateLayoutIgnorePendingStylesheets(); FrameView* view = doc->view(); - return view ? view->scrollY() : 0; + return view ? adjustForZoom(view->scrollY(), view) : 0; } void HTMLBodyElement::setScrollTop(int scrollTop) @@ -274,7 +289,7 @@ void HTMLBodyElement::setScrollTop(int scrollTop) if (sview) { // Update the document's layout document()->updateLayoutIgnorePendingStylesheets(); - sview->setScrollPosition(IntPoint(sview->scrollX(), scrollTop)); + sview->setScrollPosition(IntPoint(sview->scrollX(), static_cast<int>(scrollTop * sview->frame()->zoomFactor()))); } } @@ -284,7 +299,7 @@ int HTMLBodyElement::scrollHeight() const Document* doc = document(); doc->updateLayoutIgnorePendingStylesheets(); FrameView* view = doc->view(); - return view ? view->contentsHeight() : 0; + return view ? adjustForZoom(view->contentsHeight(), view) : 0; } int HTMLBodyElement::scrollWidth() const @@ -293,7 +308,7 @@ int HTMLBodyElement::scrollWidth() const Document* doc = document(); doc->updateLayoutIgnorePendingStylesheets(); FrameView* view = doc->view(); - return view ? view->contentsWidth() : 0; + return view ? adjustForZoom(view->contentsWidth(), view) : 0; } void HTMLBodyElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const @@ -303,4 +318,16 @@ void HTMLBodyElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const addSubresourceURL(urls, document()->completeURL(background())); } +void HTMLBodyElement::didMoveToNewOwnerDocument() +{ + // When moving body elements between documents, we should have to reset the parent sheet for any + // link style declarations. If we don't we might crash later. + // In practice I can't reproduce this theoretical problem. + // webarchive/adopt-attribute-styled-body-webarchive.html tries to make sure this crash won't surface. + if (m_linkDecl) + m_linkDecl->setParent(document()->elementSheet()); + + HTMLElement::didMoveToNewOwnerDocument(); +} + } diff --git a/WebCore/html/HTMLBodyElement.h b/WebCore/html/HTMLBodyElement.h index a72e668..8e434be 100644 --- a/WebCore/html/HTMLBodyElement.h +++ b/WebCore/html/HTMLBodyElement.h @@ -61,19 +61,22 @@ public: String vLink() const; void setVLink(const String&); - int scrollLeft() const; - void setScrollLeft(int scrollLeft); + virtual int scrollLeft() const; + virtual void setScrollLeft(int scrollLeft); - int scrollTop() const; - void setScrollTop(int scrollTop); + virtual int scrollTop() const; + virtual void setScrollTop(int scrollTop); - int scrollHeight() const; - int scrollWidth() const; + virtual int scrollHeight() const; + virtual int scrollWidth() const; virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const; protected: RefPtr<CSSMutableStyleDeclaration> m_linkDecl; + +private: + virtual void didMoveToNewOwnerDocument(); }; } //namespace diff --git a/WebCore/html/HTMLBodyElement.idl b/WebCore/html/HTMLBodyElement.idl index 41d20d6..c639183 100644 --- a/WebCore/html/HTMLBodyElement.idl +++ b/WebCore/html/HTMLBodyElement.idl @@ -31,12 +31,6 @@ module html { attribute [ConvertNullToNullString] DOMString link; attribute [ConvertNullToNullString] DOMString text; attribute [ConvertNullToNullString] DOMString vLink; - - // IE Extensions - attribute long scrollLeft; - attribute long scrollTop; - readonly attribute long scrollWidth; - readonly attribute long scrollHeight; }; } diff --git a/WebCore/html/HTMLButtonElement.cpp b/WebCore/html/HTMLButtonElement.cpp index 571f30c..3987859 100644 --- a/WebCore/html/HTMLButtonElement.cpp +++ b/WebCore/html/HTMLButtonElement.cpp @@ -30,7 +30,9 @@ #include "FormDataList.h" #include "HTMLFormElement.h" #include "HTMLNames.h" +#include "ScriptEventListener.h" #include "KeyboardEvent.h" +#include "MappedAttribute.h" #include "RenderButton.h" #include <wtf/StdLibExtras.h> @@ -55,7 +57,7 @@ RenderObject* HTMLButtonElement::createRenderer(RenderArena* arena, RenderStyle* return new (arena) RenderButton(this); } -const AtomicString& HTMLButtonElement::type() const +const AtomicString& HTMLButtonElement::formControlType() const { switch (m_type) { case SUBMIT: { @@ -89,9 +91,9 @@ void HTMLButtonElement::parseMappedAttribute(MappedAttribute* attr) // Don't map 'align' attribute. This matches what Firefox and IE do, but not Opera. // See http://bugs.webkit.org/show_bug.cgi?id=12071 } else if (attr->name() == onfocusAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().focusEvent, attr); + setAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onblurAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().blurEvent, attr); + setAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(this, attr)); } else HTMLFormControlElement::parseMappedAttribute(attr); } diff --git a/WebCore/html/HTMLButtonElement.h b/WebCore/html/HTMLButtonElement.h index c8f51cb..b1d744c 100644 --- a/WebCore/html/HTMLButtonElement.h +++ b/WebCore/html/HTMLButtonElement.h @@ -33,7 +33,7 @@ public: HTMLButtonElement(const QualifiedName&, Document*, HTMLFormElement* = 0); virtual ~HTMLButtonElement(); - virtual const AtomicString& type() const; + virtual const AtomicString& formControlType() const; virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); diff --git a/WebCore/html/HTMLCanvasElement.cpp b/WebCore/html/HTMLCanvasElement.cpp index 1cd2796..9e635e7 100644 --- a/WebCore/html/HTMLCanvasElement.cpp +++ b/WebCore/html/HTMLCanvasElement.cpp @@ -39,6 +39,7 @@ #include "HTMLNames.h" #include "ImageBuffer.h" #include "MIMETypeRegistry.h" +#include "MappedAttribute.h" #include "Page.h" #include "RenderHTMLCanvas.h" #include "Settings.h" @@ -71,6 +72,8 @@ HTMLCanvasElement::HTMLCanvasElement(const QualifiedName& tagName, Document* doc HTMLCanvasElement::~HTMLCanvasElement() { + if (m_observer) + m_observer->canvasDestroyed(this); } #if ENABLE(DASHBOARD_SUPPORT) @@ -256,7 +259,11 @@ void HTMLCanvasElement::createImageBuffer() const if (!size.width() || !size.height()) return; - m_imageBuffer.set(ImageBuffer::create(size, false).release()); + m_imageBuffer = ImageBuffer::create(size, false); + // The convertLogicalToDevice MaxCanvasArea check should prevent common cases + // where ImageBuffer::create() returns NULL, however we could still be low on memory. + if (!m_imageBuffer) + return; m_imageBuffer->context()->scale(FloatSize(size.width() / unscaledSize.width(), size.height() / unscaledSize.height())); m_imageBuffer->context()->setShadowsIgnoreTransforms(true); } diff --git a/WebCore/html/HTMLCanvasElement.h b/WebCore/html/HTMLCanvasElement.h index 12b3cb2..bba1f2d 100644 --- a/WebCore/html/HTMLCanvasElement.h +++ b/WebCore/html/HTMLCanvasElement.h @@ -49,8 +49,9 @@ class CanvasObserver { public: virtual ~CanvasObserver() {}; - virtual void canvasChanged(HTMLCanvasElement* element, const FloatRect& changedRect) = 0; - virtual void canvasResized(HTMLCanvasElement* element) = 0; + virtual void canvasChanged(HTMLCanvasElement*, const FloatRect& changedRect) = 0; + virtual void canvasResized(HTMLCanvasElement*) = 0; + virtual void canvasDestroyed(HTMLCanvasElement*) = 0; }; class HTMLCanvasElement : public HTMLElement { diff --git a/WebCore/html/HTMLCanvasElement.idl b/WebCore/html/HTMLCanvasElement.idl index bf69ac0..13fc623 100644 --- a/WebCore/html/HTMLCanvasElement.idl +++ b/WebCore/html/HTMLCanvasElement.idl @@ -37,7 +37,7 @@ module html { DOMString toDataURL(in [ConvertUndefinedOrNullToNullString] DOMString type) raises(DOMException); -#if !defined(LANGUAGE_OBJECTIVE_C) +#if !defined(LANGUAGE_OBJECTIVE_C) || !LANGUAGE_OBJECTIVE_C [V8Custom] DOMObject getContext(in DOMString contextId); #endif diff --git a/WebCore/html/HTMLCollection.cpp b/WebCore/html/HTMLCollection.cpp index fd588dd..de4c424 100644 --- a/WebCore/html/HTMLCollection.cpp +++ b/WebCore/html/HTMLCollection.cpp @@ -35,7 +35,7 @@ namespace WebCore { using namespace HTMLNames; -HTMLCollection::HTMLCollection(PassRefPtr<Node> base, Type type) +HTMLCollection::HTMLCollection(PassRefPtr<Node> base, CollectionType type) : m_idsDone(false) , m_base(base) , m_type(type) @@ -44,7 +44,7 @@ HTMLCollection::HTMLCollection(PassRefPtr<Node> base, Type type) { } -HTMLCollection::HTMLCollection(PassRefPtr<Node> base, Type type, CollectionInfo* info) +HTMLCollection::HTMLCollection(PassRefPtr<Node> base, CollectionType type, CollectionCache* info) : m_idsDone(false) , m_base(base) , m_type(type) @@ -53,7 +53,7 @@ HTMLCollection::HTMLCollection(PassRefPtr<Node> base, Type type, CollectionInfo* { } -PassRefPtr<HTMLCollection> HTMLCollection::create(PassRefPtr<Node> base, Type type) +PassRefPtr<HTMLCollection> HTMLCollection::create(PassRefPtr<Node> base, CollectionType type) { return adoptRef(new HTMLCollection(base, type)); } @@ -64,74 +64,12 @@ HTMLCollection::~HTMLCollection() delete m_info; } -HTMLCollection::CollectionInfo::CollectionInfo() - : version(0) -{ - reset(); -} - -inline void HTMLCollection::CollectionInfo::copyCacheMap(NodeCacheMap& dest, const NodeCacheMap& src) -{ - ASSERT(dest.isEmpty()); - NodeCacheMap::const_iterator end = src.end(); - for (NodeCacheMap::const_iterator it = src.begin(); it != end; ++it) - dest.add(it->first, new Vector<Element*>(*it->second)); -} - -HTMLCollection::CollectionInfo::CollectionInfo(const CollectionInfo& other) - : version(other.version) - , current(other.current) - , position(other.position) - , length(other.length) - , elementsArrayPosition(other.elementsArrayPosition) - , hasLength(other.hasLength) - , hasNameCache(other.hasNameCache) -{ - copyCacheMap(idCache, other.idCache); - copyCacheMap(nameCache, other.nameCache); -} - -void HTMLCollection::CollectionInfo::swap(CollectionInfo& other) -{ - std::swap(version, other.version); - std::swap(current, other.current); - std::swap(position, other.position); - std::swap(length, other.length); - std::swap(elementsArrayPosition, other.elementsArrayPosition); - - idCache.swap(other.idCache); - nameCache.swap(other.nameCache); - - std::swap(hasLength, other.hasLength); - std::swap(hasNameCache, other.hasNameCache); -} - -HTMLCollection::CollectionInfo::~CollectionInfo() -{ - deleteAllValues(idCache); - deleteAllValues(nameCache); -} - -void HTMLCollection::CollectionInfo::reset() -{ - current = 0; - position = 0; - length = 0; - hasLength = false; - elementsArrayPosition = 0; - deleteAllValues(idCache); - idCache.clear(); - deleteAllValues(nameCache); - nameCache.clear(); - hasNameCache = false; -} - void HTMLCollection::resetCollectionInfo() const { unsigned docversion = static_cast<HTMLDocument*>(m_base->document())->domTreeVersion(); if (!m_info) { - m_info = new CollectionInfo; + m_info = new CollectionCache; m_ownsInfo = true; m_info->version = docversion; return; @@ -164,7 +102,7 @@ Element* HTMLCollection::itemAfter(Element* previous) const case DocScripts: case DocumentNamedItems: case MapAreas: - case Other: + case OtherCollection: case SelectOptions: case WindowNamedItems: break; @@ -245,7 +183,7 @@ Element* HTMLCollection::itemAfter(Element* previous) const case NodeChildren: return e; case DocumentNamedItems: - case Other: + case OtherCollection: case WindowNamedItems: ASSERT_NOT_REACHED(); break; diff --git a/WebCore/html/HTMLCollection.h b/WebCore/html/HTMLCollection.h index 083ec05..b04bcbc 100644 --- a/WebCore/html/HTMLCollection.h +++ b/WebCore/html/HTMLCollection.h @@ -23,6 +23,7 @@ #ifndef HTMLCollection_h #define HTMLCollection_h +#include "CollectionType.h" #include <wtf/RefCounted.h> #include <wtf/Forward.h> #include <wtf/HashMap.h> @@ -37,46 +38,11 @@ class Node; class NodeList; class String; +struct CollectionCache; + class HTMLCollection : public RefCounted<HTMLCollection> { public: - enum Type { - // unnamed collection types cached in the document - - DocImages, // all <img> elements in the document - DocApplets, // all <object> and <applet> elements - DocEmbeds, // all <embed> elements - DocObjects, // all <object> elements - DocForms, // all <form> elements - DocLinks, // all <a> _and_ <area> elements with a value for href - DocAnchors, // all <a> elements with a value for name - DocScripts, // all <script> elements - - DocAll, // "all" elements (IE) - NodeChildren, // first-level children (IE) - - // named collection types cached in the document - - WindowNamedItems, - DocumentNamedItems, - - // types not cached in the document; these are types that can't be used on a document - - TableTBodies, // all <tbody> elements in this table - TSectionRows, // all row elements in this table section - TRCells, // all cells in this row - SelectOptions, - MapAreas, - - Other - }; - - static const Type FirstUnnamedDocumentCachedType = DocImages; - static const unsigned NumUnnamedDocumentCachedTypes = NodeChildren - DocImages + 1; - - static const Type FirstNamedDocumentCachedType = WindowNamedItems; - static const unsigned NumNamedDocumentCachedTypes = DocumentNamedItems - WindowNamedItems + 1; - - static PassRefPtr<HTMLCollection> create(PassRefPtr<Node> base, Type); + static PassRefPtr<HTMLCollection> create(PassRefPtr<Node> base, CollectionType); virtual ~HTMLCollection(); unsigned length() const; @@ -94,52 +60,18 @@ public: PassRefPtr<NodeList> tags(const String&); Node* base() const { return m_base.get(); } - Type type() const { return m_type; } - - // FIXME: This class name is a bad in two ways. First, "info" is much too vague, - // and doesn't convey the job of this class (caching collection state). - // Second, since this is a member of HTMLCollection, it doesn't need "collection" - // in its name. - struct CollectionInfo { - CollectionInfo(); - CollectionInfo(const CollectionInfo&); - CollectionInfo& operator=(const CollectionInfo& other) - { - CollectionInfo tmp(other); - swap(tmp); - return *this; - } - ~CollectionInfo(); - - void reset(); - void swap(CollectionInfo&); - - typedef HashMap<AtomicStringImpl*, Vector<Element*>*> NodeCacheMap; - - unsigned version; - Element* current; - unsigned position; - unsigned length; - int elementsArrayPosition; - NodeCacheMap idCache; - NodeCacheMap nameCache; - bool hasLength; - bool hasNameCache; - - private: - static void copyCacheMap(NodeCacheMap&, const NodeCacheMap&); - }; + CollectionType type() const { return m_type; } protected: - HTMLCollection(PassRefPtr<Node> base, Type, CollectionInfo*); + HTMLCollection(PassRefPtr<Node> base, CollectionType, CollectionCache*); - CollectionInfo* info() const { return m_info; } - virtual void resetCollectionInfo() const; + CollectionCache* info() const { return m_info; } + void resetCollectionInfo() const; mutable bool m_idsDone; // for nextNamedItem() private: - HTMLCollection(PassRefPtr<Node> base, Type); + HTMLCollection(PassRefPtr<Node> base, CollectionType); virtual Element* itemAfter(Element*) const; virtual unsigned calcLength() const; @@ -148,9 +80,9 @@ private: bool checkForNameMatch(Element*, bool checkName, const AtomicString& name) const; RefPtr<Node> m_base; - Type m_type; + CollectionType m_type; - mutable CollectionInfo* m_info; + mutable CollectionCache* m_info; mutable bool m_ownsInfo; }; diff --git a/WebCore/html/HTMLCollection.idl b/WebCore/html/HTMLCollection.idl index 8290e1a..1ba5ec7 100644 --- a/WebCore/html/HTMLCollection.idl +++ b/WebCore/html/HTMLCollection.idl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved. * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> * * This library is free software; you can redistribute it and/or @@ -26,6 +26,7 @@ module html { HasNameGetter, CustomCall, CustomToJS, + Polymorphic, InterfaceUUID=b0d215ff-6f9c-4d1f-86c3-f200a65a5134, ImplementationUUID=8e81b17f-7f74-4121-8f2f-a339a7e66447 ] HTMLCollection { diff --git a/WebCore/html/HTMLDivElement.cpp b/WebCore/html/HTMLDivElement.cpp index 7ffccd7..bd7195e 100644 --- a/WebCore/html/HTMLDivElement.cpp +++ b/WebCore/html/HTMLDivElement.cpp @@ -19,12 +19,14 @@ * Boston, MA 02110-1301, USA. * */ + #include "config.h" #include "HTMLDivElement.h" #include "CSSPropertyNames.h" #include "CSSValueKeywords.h" #include "HTMLNames.h" +#include "MappedAttribute.h" namespace WebCore { diff --git a/WebCore/html/HTMLDocument.idl b/WebCore/html/HTMLDocument.idl index 4345195..3dd7a07 100644 --- a/WebCore/html/HTMLDocument.idl +++ b/WebCore/html/HTMLDocument.idl @@ -37,7 +37,7 @@ module html { // Extensions -#if defined(LANGUAGE_JAVASCRIPT) +#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT // FIXME: This should eventually be available (if they are wanted) for all languages. attribute [Custom, Deletable] HTMLCollection all; #endif diff --git a/WebCore/html/HTMLElement.cpp b/WebCore/html/HTMLElement.cpp index 906f847..c50e6ba 100644 --- a/WebCore/html/HTMLElement.cpp +++ b/WebCore/html/HTMLElement.cpp @@ -2,6 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -32,12 +33,15 @@ #include "ExceptionCode.h" #include "Frame.h" #include "HTMLBRElement.h" +#include "HTMLCollection.h" #include "HTMLDocument.h" #include "HTMLElementFactory.h" #include "HTMLFormElement.h" #include "HTMLNames.h" -#include "HTMLTokenizer.h" // parseHTMLDocumentFragment +#include "HTMLTokenizer.h" +#include "MappedAttribute.h" #include "RenderWordBreak.h" +#include "ScriptEventListener.h" #include "Settings.h" #include "Text.h" #include "TextIterator.h" @@ -65,7 +69,8 @@ String HTMLElement::nodeName() const { // FIXME: Would be nice to have an atomicstring lookup based off uppercase chars that does not have to copy // the string on a hit in the hash. - if (document()->isHTMLDocument()) + // FIXME: We should have a way to detect XHTML elements and replace the hasPrefix() check with it. + if (document()->isHTMLDocument() && !tagQName().hasPrefix()) return tagQName().localName().string().upper(); return Element::nodeName(); } @@ -141,84 +146,84 @@ void HTMLElement::parseMappedAttribute(MappedAttribute *attr) } // standard events else if (attr->name() == onclickAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().clickEvent, attr); + setAttributeEventListener(eventNames().clickEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == oncontextmenuAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().contextmenuEvent, attr); + setAttributeEventListener(eventNames().contextmenuEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == ondblclickAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().dblclickEvent, attr); + setAttributeEventListener(eventNames().dblclickEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onmousedownAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().mousedownEvent, attr); + setAttributeEventListener(eventNames().mousedownEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onmousemoveAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().mousemoveEvent, attr); + setAttributeEventListener(eventNames().mousemoveEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onmouseoutAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().mouseoutEvent, attr); + setAttributeEventListener(eventNames().mouseoutEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onmouseoverAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().mouseoverEvent, attr); + setAttributeEventListener(eventNames().mouseoverEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onmouseupAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().mouseupEvent, attr); + setAttributeEventListener(eventNames().mouseupEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onmousewheelAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().mousewheelEvent, attr); + setAttributeEventListener(eventNames().mousewheelEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onfocusAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().focusEvent, attr); + setAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onblurAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().blurEvent, attr); + setAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onkeydownAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().keydownEvent, attr); + setAttributeEventListener(eventNames().keydownEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onkeypressAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().keypressEvent, attr); + setAttributeEventListener(eventNames().keypressEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onkeyupAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().keyupEvent, attr); + setAttributeEventListener(eventNames().keyupEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onscrollAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().scrollEvent, attr); + setAttributeEventListener(eventNames().scrollEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onbeforecutAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().beforecutEvent, attr); + setAttributeEventListener(eventNames().beforecutEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == oncutAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().cutEvent, attr); + setAttributeEventListener(eventNames().cutEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onbeforecopyAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().beforecopyEvent, attr); + setAttributeEventListener(eventNames().beforecopyEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == oncopyAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().copyEvent, attr); + setAttributeEventListener(eventNames().copyEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onbeforepasteAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().beforepasteEvent, attr); + setAttributeEventListener(eventNames().beforepasteEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onpasteAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().pasteEvent, attr); + setAttributeEventListener(eventNames().pasteEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == ondragenterAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().dragenterEvent, attr); + setAttributeEventListener(eventNames().dragenterEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == ondragoverAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().dragoverEvent, attr); + setAttributeEventListener(eventNames().dragoverEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == ondragleaveAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().dragleaveEvent, attr); + setAttributeEventListener(eventNames().dragleaveEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == ondropAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().dropEvent, attr); + setAttributeEventListener(eventNames().dropEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == ondragstartAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().dragstartEvent, attr); + setAttributeEventListener(eventNames().dragstartEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == ondragAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().dragEvent, attr); + setAttributeEventListener(eventNames().dragEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == ondragendAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().dragendEvent, attr); + setAttributeEventListener(eventNames().dragendEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onselectstartAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().selectstartEvent, attr); + setAttributeEventListener(eventNames().selectstartEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onsubmitAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().submitEvent, attr); + setAttributeEventListener(eventNames().submitEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onerrorAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().errorEvent, attr); + setAttributeEventListener(eventNames().errorEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onwebkitanimationstartAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().webkitAnimationStartEvent, attr); + setAttributeEventListener(eventNames().webkitAnimationStartEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onwebkitanimationiterationAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().webkitAnimationIterationEvent, attr); + setAttributeEventListener(eventNames().webkitAnimationIterationEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onwebkitanimationendAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().webkitAnimationEndEvent, attr); + setAttributeEventListener(eventNames().webkitAnimationEndEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onwebkittransitionendAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().webkitTransitionEndEvent, attr); + setAttributeEventListener(eventNames().webkitTransitionEndEvent, createAttributeEventListener(this, attr)); #if ENABLE(TOUCH_EVENTS) // Android } else if (attr->name() == ontouchstartAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().touchstartEvent, attr); + setAttributeEventListener(eventNames().touchstartEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == ontouchendAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().touchendEvent, attr); + setAttributeEventListener(eventNames().touchendEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == ontouchmoveAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().touchmoveEvent, attr); + setAttributeEventListener(eventNames().touchmoveEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == ontouchcancelAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().touchcancelEvent, attr); + setAttributeEventListener(eventNames().touchcancelEvent, createAttributeEventListener(this, attr)); #endif } } @@ -394,7 +399,7 @@ void HTMLElement::setInnerText(const String& text, ExceptionCode& ec) } // FIXME: Do we need to be able to detect preserveNewline style even when there's no renderer? - // FIXME: Can the renderer be out of date here? Do we need to call updateRendering? + // FIXME: Can the renderer be out of date here? Do we need to call updateStyleIfNeeded? // For example, for the contents of textarea elements that are display:none? RenderObject* r = renderer(); if (r && r->style()->preserveNewline()) { @@ -611,7 +616,7 @@ bool HTMLElement::isContentEditable() const // FIXME: this is a terrible thing to do here: // https://bugs.webkit.org/show_bug.cgi?id=21834 - document()->updateRendering(); + document()->updateStyleIfNeeded(); if (!renderer()) { if (parentNode()) @@ -628,7 +633,7 @@ bool HTMLElement::isContentRichlyEditable() const if (document()->frame() && document()->frame()->isContentEditable()) return true; - document()->updateRendering(); + document()->updateStyleIfNeeded(); if (!renderer()) { if (parentNode()) @@ -642,7 +647,7 @@ bool HTMLElement::isContentRichlyEditable() const String HTMLElement::contentEditable() const { - document()->updateRendering(); + document()->updateStyleIfNeeded(); if (!renderer()) return "false"; @@ -777,7 +782,7 @@ void HTMLElement::setTabIndex(int value) PassRefPtr<HTMLCollection> HTMLElement::children() { - return HTMLCollection::create(this, HTMLCollection::NodeChildren); + return HTMLCollection::create(this, NodeChildren); } // DOM Section 1.1.1 @@ -987,11 +992,13 @@ bool HTMLElement::checkDTD(const Node* newChild) bool HTMLElement::rendererIsNeeded(RenderStyle *style) { +#if !ENABLE(XHTMLMP) if (hasLocalName(noscriptTag)) { Settings* settings = document()->settings(); if (settings && settings->isJavaScriptEnabled()) return false; } +#endif return StyledElement::rendererIsNeeded(style); } diff --git a/WebCore/html/HTMLElement.idl b/WebCore/html/HTMLElement.idl index 8ce5542..ed21628 100644 --- a/WebCore/html/HTMLElement.idl +++ b/WebCore/html/HTMLElement.idl @@ -36,8 +36,6 @@ module html { attribute [ConvertNullToNullString] DOMString className; attribute long tabIndex; - void blur(); - void focus(); // Extensions attribute [ConvertNullToNullString] DOMString innerHTML @@ -64,7 +62,7 @@ module html { attribute [ConvertNullToNullString] DOMString contentEditable; readonly attribute boolean isContentEditable; -#if defined(LANGUAGE_OBJECTIVE_C) +#if defined(LANGUAGE_OBJECTIVE_C) && LANGUAGE_OBJECTIVE_C readonly attribute DOMString titleDisplayString; #endif }; diff --git a/WebCore/html/HTMLElementsAllInOne.cpp b/WebCore/html/HTMLElementsAllInOne.cpp new file mode 100644 index 0000000..dad548c --- /dev/null +++ b/WebCore/html/HTMLElementsAllInOne.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2009, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This source file coalesces the HTML elements into a single object file to +// reduce bloat and allow us to link release builds on 32-bit Windows. + +#include "HTMLAnchorElement.cpp" +#include "HTMLAppletElement.cpp" +#include "HTMLAreaElement.cpp" +#include "HTMLAudioElement.cpp" +#include "HTMLBRElement.cpp" +#include "HTMLBaseElement.cpp" +#include "HTMLBaseFontElement.cpp" +#include "HTMLBlockquoteElement.cpp" +#include "HTMLBodyElement.cpp" +#include "HTMLButtonElement.cpp" +#include "HTMLCanvasElement.cpp" +#include "HTMLDListElement.cpp" +#include "HTMLDirectoryElement.cpp" +#include "HTMLDivElement.cpp" +#include "HTMLElement.cpp" +#include "HTMLEmbedElement.cpp" +#include "HTMLFieldSetElement.cpp" +#include "HTMLFontElement.cpp" +#include "HTMLFormControlElement.cpp" +#include "HTMLFormElement.cpp" +#include "HTMLFrameElement.cpp" +#include "HTMLFrameElementBase.cpp" +#include "HTMLFrameOwnerElement.cpp" +#include "HTMLFrameSetElement.cpp" +#include "HTMLHRElement.cpp" +#include "HTMLHeadElement.cpp" +#include "HTMLHeadingElement.cpp" +#include "HTMLHtmlElement.cpp" +#include "HTMLIFrameElement.cpp" +#include "HTMLImageElement.cpp" +#include "HTMLInputElement.cpp" +#include "HTMLIsIndexElement.cpp" +#include "HTMLKeygenElement.cpp" +#include "HTMLLIElement.cpp" +#include "HTMLLabelElement.cpp" +#include "HTMLLegendElement.cpp" +#include "HTMLLinkElement.cpp" +#include "HTMLMapElement.cpp" +#include "HTMLMarqueeElement.cpp" +#include "HTMLMediaElement.cpp" +#include "HTMLMenuElement.cpp" +#include "HTMLMetaElement.cpp" +#include "HTMLModElement.cpp" +#include "HTMLOListElement.cpp" +#include "HTMLObjectElement.cpp" +#include "HTMLOptGroupElement.cpp" +#include "HTMLOptionElement.cpp" +#include "HTMLParagraphElement.cpp" +#include "HTMLParamElement.cpp" +#include "HTMLPlugInElement.cpp" +#include "HTMLPlugInImageElement.cpp" +#include "HTMLPreElement.cpp" +#include "HTMLQuoteElement.cpp" +#include "HTMLScriptElement.cpp" +#include "HTMLSelectElement.cpp" +#include "HTMLSourceElement.cpp" +#include "HTMLStyleElement.cpp" +#include "HTMLTableCaptionElement.cpp" +#include "HTMLTableCellElement.cpp" +#include "HTMLTableColElement.cpp" +#include "HTMLTableElement.cpp" +#include "HTMLTablePartElement.cpp" +#include "HTMLTableRowElement.cpp" +#include "HTMLTableSectionElement.cpp" +#include "HTMLTextAreaElement.cpp" +#include "HTMLTitleElement.cpp" +#include "HTMLUListElement.cpp" +#include "HTMLVideoElement.cpp" diff --git a/WebCore/html/HTMLEmbedElement.cpp b/WebCore/html/HTMLEmbedElement.cpp index f467849..2500dd6 100644 --- a/WebCore/html/HTMLEmbedElement.cpp +++ b/WebCore/html/HTMLEmbedElement.cpp @@ -31,10 +31,12 @@ #include "HTMLImageLoader.h" #include "HTMLNames.h" #include "HTMLObjectElement.h" +#include "MappedAttribute.h" #include "RenderImage.h" #include "RenderPartObject.h" #include "RenderWidget.h" #include "ScriptController.h" +#include "Settings.h" namespace WebCore { @@ -137,6 +139,14 @@ bool HTMLEmbedElement::rendererIsNeeded(RenderStyle* style) return false; } +#if ENABLE(DASHBOARD_SUPPORT) + // Workaround for <rdar://problem/6642221>. + if (Settings* settings = frame->settings()) { + if (settings->usesDashboardBackwardCompatibilityMode()) + return true; + } +#endif + return HTMLPlugInElement::rendererIsNeeded(style); } @@ -170,7 +180,7 @@ void HTMLEmbedElement::attach() void HTMLEmbedElement::updateWidget() { - document()->updateRendering(); + document()->updateStyleIfNeeded(); if (m_needWidgetUpdate && renderer() && !isImageType()) static_cast<RenderPartObject*>(renderer())->updateWidget(true); } diff --git a/WebCore/html/HTMLEmbedElement.idl b/WebCore/html/HTMLEmbedElement.idl index 10c3007..ecf8a96 100644 --- a/WebCore/html/HTMLEmbedElement.idl +++ b/WebCore/html/HTMLEmbedElement.idl @@ -30,7 +30,7 @@ module html { ImplementationUUID=93e0407a-8380-4ff0-978d-f773f2dee6a3 ] HTMLEmbedElement : HTMLElement { attribute [ConvertNullToNullString] DOMString align; -#if defined(LANGUAGE_JAVASCRIPT) +#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT attribute [ConvertNullToNullString] DOMString height; #else attribute [ConvertFromString] long height; @@ -38,18 +38,20 @@ module html { attribute [ConvertNullToNullString] DOMString name; attribute [ConvertNullToNullString] DOMString src; attribute [ConvertNullToNullString] DOMString type; -#if defined(LANGUAGE_JAVASCRIPT) +#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT attribute [ConvertNullToNullString] DOMString width; #else attribute [ConvertFromString] long width; #endif -#if !defined(LANGUAGE_COM) -#if ENABLE_SVG +#if !defined(LANGUAGE_COM) || !LANGUAGE_COM +#if defined(ENABLE_SVG) && ENABLE_SVG +#if !defined(LANGUAGE_OBJECTIVE_C) || !LANGUAGE_OBJECTIVE_C || defined(ENABLE_SVG_DOM_OBJC_BINDINGS) && ENABLE_SVG_DOM_OBJC_BINDINGS [SVGCheckSecurityDocument] SVGDocument getSVGDocument() raises(DOMException); #endif #endif +#endif }; } diff --git a/WebCore/html/HTMLFieldSetElement.cpp b/WebCore/html/HTMLFieldSetElement.cpp index d90550d..eb8d4ed 100644 --- a/WebCore/html/HTMLFieldSetElement.cpp +++ b/WebCore/html/HTMLFieldSetElement.cpp @@ -53,7 +53,7 @@ bool HTMLFieldSetElement::isFocusable() const return HTMLElement::isFocusable(); } -const AtomicString& HTMLFieldSetElement::type() const +const AtomicString& HTMLFieldSetElement::formControlType() const { DEFINE_STATIC_LOCAL(const AtomicString, fieldset, ("fieldset")); return fieldset; diff --git a/WebCore/html/HTMLFieldSetElement.h b/WebCore/html/HTMLFieldSetElement.h index 9a6cff1..e79f2c5 100644 --- a/WebCore/html/HTMLFieldSetElement.h +++ b/WebCore/html/HTMLFieldSetElement.h @@ -46,7 +46,7 @@ public: virtual bool isFocusable() const; virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); - virtual const AtomicString& type() const; + virtual const AtomicString& formControlType() const; virtual bool willValidate() const { return false; } }; diff --git a/WebCore/html/HTMLFontElement.cpp b/WebCore/html/HTMLFontElement.cpp index 91b6448..d19032a 100644 --- a/WebCore/html/HTMLFontElement.cpp +++ b/WebCore/html/HTMLFontElement.cpp @@ -26,6 +26,7 @@ #include "CSSPropertyNames.h" #include "CSSValueKeywords.h" #include "HTMLNames.h" +#include "MappedAttribute.h" using namespace WTF; diff --git a/WebCore/html/HTMLFormCollection.cpp b/WebCore/html/HTMLFormCollection.cpp index 03796d6..812d98a 100644 --- a/WebCore/html/HTMLFormCollection.cpp +++ b/WebCore/html/HTMLFormCollection.cpp @@ -23,6 +23,7 @@ #include "config.h" #include "HTMLFormCollection.h" +#include "CollectionCache.h" #include "HTMLFormControlElement.h" #include "HTMLFormElement.h" #include "HTMLImageElement.h" @@ -35,15 +36,15 @@ using namespace HTMLNames; // Since the collections are to be "live", we have to do the // calculation every time if anything has changed. -inline HTMLCollection::CollectionInfo* HTMLFormCollection::formCollectionInfo(HTMLFormElement* form) +inline CollectionCache* HTMLFormCollection::formCollectionInfo(HTMLFormElement* form) { if (!form->collectionInfo) - form->collectionInfo = new CollectionInfo; + form->collectionInfo = new CollectionCache; return form->collectionInfo; } HTMLFormCollection::HTMLFormCollection(PassRefPtr<HTMLFormElement> form) - : HTMLCollection(form.get(), Other, formCollectionInfo(form.get())) + : HTMLCollection(form.get(), OtherCollection, formCollectionInfo(form.get())) { } diff --git a/WebCore/html/HTMLFormCollection.h b/WebCore/html/HTMLFormCollection.h index 524a59b..a204446 100644 --- a/WebCore/html/HTMLFormCollection.h +++ b/WebCore/html/HTMLFormCollection.h @@ -51,7 +51,7 @@ private: virtual void updateNameCache() const; virtual unsigned calcLength() const; - static CollectionInfo* formCollectionInfo(HTMLFormElement*); + static CollectionCache* formCollectionInfo(HTMLFormElement*); Element* getNamedItem(const QualifiedName& attrName, const AtomicString& name) const; Element* nextNamedItemInternal(const String& name) const; diff --git a/WebCore/html/HTMLFormControlElement.cpp b/WebCore/html/HTMLFormControlElement.cpp index 5238ad5..36d20ac 100644 --- a/WebCore/html/HTMLFormControlElement.cpp +++ b/WebCore/html/HTMLFormControlElement.cpp @@ -34,6 +34,7 @@ #include "HTMLNames.h" #include "HTMLParser.h" #include "HTMLTokenizer.h" +#include "MappedAttribute.h" #include "RenderBox.h" #include "RenderTheme.h" @@ -68,7 +69,7 @@ void HTMLFormControlElement::parseMappedAttribute(MappedAttribute *attr) bool oldDisabled = m_disabled; m_disabled = !attr->isNull(); if (oldDisabled != m_disabled) { - setChanged(); + setNeedsStyleRecalc(); if (renderer() && renderer()->style()->hasAppearance()) theme()->stateChanged(renderer(), EnabledState); } @@ -76,7 +77,7 @@ void HTMLFormControlElement::parseMappedAttribute(MappedAttribute *attr) bool oldReadOnly = m_readOnly; m_readOnly = !attr->isNull(); if (oldReadOnly != m_readOnly) { - setChanged(); + setNeedsStyleRecalc(); if (renderer() && renderer()->style()->hasAppearance()) theme()->stateChanged(renderer(), ReadOnlyState); } @@ -103,7 +104,7 @@ void HTMLFormControlElement::attach() if (hasTagName(inputTag)) isInputTypeHidden = static_cast<HTMLInputElement*>(this)->isInputTypeHidden(); - if (autofocus() && renderer() && !document()->ignoreAutofocus() && !isReadOnlyControl() && + if (autofocus() && renderer() && !document()->ignoreAutofocus() && !isReadOnlyFormControl() && ((hasTagName(inputTag) && !isInputTypeHidden) || hasTagName(selectTag) || hasTagName(buttonTag) || hasTagName(textareaTag))) focus(); @@ -151,7 +152,7 @@ void HTMLFormControlElement::removedFromTree(bool deep) HTMLElement::removedFromTree(deep); } -const AtomicString& HTMLFormControlElement::name() const +const AtomicString& HTMLFormControlElement::formControlName() const { const AtomicString& n = getAttribute(nameAttr); return n.isNull() ? emptyAtom : n; @@ -162,9 +163,9 @@ void HTMLFormControlElement::setName(const AtomicString &value) setAttribute(nameAttr, value); } -void HTMLFormControlElement::onChange() +void HTMLFormControlElement::dispatchFormControlChangeEvent() { - dispatchEventForType(eventNames().changeEvent, true, false); + dispatchEvent(eventNames().changeEvent, true, false); } bool HTMLFormControlElement::disabled() const @@ -238,7 +239,7 @@ bool HTMLFormControlElement::willValidate() const // The control does not have a repetition template as an ancestor. // The control does not have a datalist element as an ancestor. // The control is not an output element. - return form() && name().length() && !disabled() && !isReadOnlyControl(); + return form() && name().length() && !disabled() && !isReadOnlyFormControl(); } bool HTMLFormControlElement::supportsFocus() const @@ -262,23 +263,23 @@ void HTMLFormControlElement::removeFromForm() HTMLFormControlElementWithState::HTMLFormControlElementWithState(const QualifiedName& tagName, Document* doc, HTMLFormElement* f) : HTMLFormControlElement(tagName, doc, f) { - FormControlElementWithState::registerFormControlElementWithState(this, document()); + document()->registerFormElementWithState(this); } HTMLFormControlElementWithState::~HTMLFormControlElementWithState() { - FormControlElementWithState::unregisterFormControlElementWithState(this, document()); + document()->unregisterFormElementWithState(this); } void HTMLFormControlElementWithState::willMoveToNewOwnerDocument() { - FormControlElementWithState::unregisterFormControlElementWithState(this, document()); + document()->unregisterFormElementWithState(this); HTMLFormControlElement::willMoveToNewOwnerDocument(); } void HTMLFormControlElementWithState::didMoveToNewOwnerDocument() { - FormControlElementWithState::registerFormControlElementWithState(this, document()); + document()->registerFormElementWithState(this); HTMLFormControlElement::didMoveToNewOwnerDocument(); } @@ -289,7 +290,7 @@ void HTMLFormControlElementWithState::finishParsingChildren() if (doc->hasStateForNewFormElements()) { String state; if (doc->takeStateForFormElement(name().impl(), type().impl(), state)) - restoreState(state); + restoreFormControlState(state); } } diff --git a/WebCore/html/HTMLFormControlElement.h b/WebCore/html/HTMLFormControlElement.h index 7430df7..0a7bbd1 100644 --- a/WebCore/html/HTMLFormControlElement.h +++ b/WebCore/html/HTMLFormControlElement.h @@ -24,8 +24,6 @@ #ifndef HTMLFormControlElement_h #define HTMLFormControlElement_h -#include "FormControlElement.h" -#include "FormControlElementWithState.h" #include "HTMLElement.h" namespace WebCore { @@ -33,7 +31,7 @@ namespace WebCore { class FormDataList; class HTMLFormElement; -class HTMLFormControlElement : public HTMLElement, public FormControlElement { +class HTMLFormControlElement : public HTMLElement { public: HTMLFormControlElement(const QualifiedName& tagName, Document*, HTMLFormElement*); virtual ~HTMLFormControlElement(); @@ -43,10 +41,8 @@ public: HTMLFormElement* form() const { return m_form; } - virtual const AtomicString& type() const = 0; - - virtual bool isTextControl() const { return false; } - virtual bool isEnabled() const { return !disabled(); } + virtual bool isTextFormControl() const { return false; } + virtual bool isEnabledFormControl() const { return !disabled(); } virtual void parseMappedAttribute(MappedAttribute*); virtual void attach(); @@ -55,10 +51,10 @@ public: virtual void reset() {} - virtual bool valueMatchesRenderer() const { return m_valueMatchesRenderer; } - virtual void setValueMatchesRenderer(bool b = true) { m_valueMatchesRenderer = b; } + virtual bool formControlValueMatchesRenderer() const { return m_valueMatchesRenderer; } + virtual void setFormControlValueMatchesRenderer(bool b) { m_valueMatchesRenderer = b; } - void onChange(); + virtual void dispatchFormControlChangeEvent(); bool disabled() const; void setDisabled(bool); @@ -69,7 +65,7 @@ public: virtual bool isMouseFocusable() const; virtual bool isEnumeratable() const { return false; } - virtual bool isReadOnlyControl() const { return m_readOnly; } + virtual bool isReadOnlyFormControl() const { return m_readOnly; } void setReadOnly(bool); // Determines whether or not a control will be automatically focused @@ -78,7 +74,12 @@ public: virtual void recalcStyle(StyleChange); - virtual const AtomicString& name() const; + virtual const AtomicString& formControlName() const; + virtual const AtomicString& formControlType() const = 0; + + const AtomicString& type() const { return formControlType(); } + const AtomicString& name() const { return formControlName(); } + void setName(const AtomicString& name); virtual bool isFormControlElement() const { return true; } @@ -111,14 +112,11 @@ private: bool m_valueMatchesRenderer; }; -class HTMLFormControlElementWithState : public HTMLFormControlElement, public FormControlElementWithState { +class HTMLFormControlElementWithState : public HTMLFormControlElement { public: HTMLFormControlElementWithState(const QualifiedName& tagName, Document*, HTMLFormElement*); virtual ~HTMLFormControlElementWithState(); - virtual bool isFormControlElementWithState() const { return true; } - - virtual FormControlElement* toFormControlElement() { return this; } virtual void finishParsingChildren(); protected: diff --git a/WebCore/html/HTMLFormElement.cpp b/WebCore/html/HTMLFormElement.cpp index df4e541..64cac37 100644 --- a/WebCore/html/HTMLFormElement.cpp +++ b/WebCore/html/HTMLFormElement.cpp @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * (C) 2006 Alexey Proskuryakov (ap@nypop.com) * * This library is free software; you can redistribute it and/or @@ -34,6 +34,7 @@ #include "FileSystem.h" #include "FormData.h" #include "FormDataList.h" +#include "FormState.h" #include "Frame.h" #include "FrameLoader.h" #include "HTMLDocument.h" @@ -41,22 +42,21 @@ #include "HTMLImageElement.h" #include "HTMLInputElement.h" #include "HTMLNames.h" +#include "ScriptEventListener.h" #include "MIMETypeRegistry.h" +#include "MappedAttribute.h" #include "Page.h" #include "RenderTextControl.h" +#include <limits> #include <wtf/CurrentTime.h> #include <wtf/RandomNumber.h> -#include <limits> - #if PLATFORM(WX) #include <wx/defs.h> #include <wx/filename.h> #endif -#if PLATFORM(WIN_OS) -#include <shlwapi.h> -#endif +using namespace std; namespace WebCore { @@ -79,6 +79,7 @@ HTMLFormElement::HTMLFormElement(const QualifiedName& tagName, Document* doc) , m_doingsubmit(false) , m_inreset(false) , m_malformed(false) + , m_demoted(false) { ASSERT(hasTagName(formTag)); } @@ -107,6 +108,31 @@ void HTMLFormElement::attach() HTMLElement::attach(); } +bool HTMLFormElement::rendererIsNeeded(RenderStyle* style) +{ + if (!isDemoted()) + return HTMLElement::rendererIsNeeded(style); + + Node* node = parentNode(); + RenderObject* parentRenderer = node->renderer(); + bool parentIsTableElementPart = (parentRenderer->isTable() && node->hasTagName(tableTag)) + || (parentRenderer->isTableRow() && node->hasTagName(trTag)) + || (parentRenderer->isTableSection() && node->hasTagName(tbodyTag)) + || (parentRenderer->isTableCol() && node->hasTagName(colTag)) + || (parentRenderer->isTableCell() && node->hasTagName(trTag)); + + if (!parentIsTableElementPart) + return true; + + EDisplay display = style->display(); + bool formIsTablePart = display == TABLE || display == INLINE_TABLE || display == TABLE_ROW_GROUP + || display == TABLE_HEADER_GROUP || display == TABLE_FOOTER_GROUP || display == TABLE_ROW + || display == TABLE_COLUMN_GROUP || display == TABLE_COLUMN || display == TABLE_CELL + || display == TABLE_CAPTION; + + return formIsTablePart; +} + void HTMLFormElement::insertedIntoDocument() { if (document()->isHTMLDocument()) @@ -269,7 +295,7 @@ bool HTMLFormElement::prepareSubmit(Event* event) m_insubmit = true; m_doingsubmit = false; - if (dispatchEventForType(eventNames().submitEvent, true, true) && !m_doingsubmit) + if (dispatchEvent(eventNames().submitEvent, true, true) && !m_doingsubmit) m_doingsubmit = true; m_insubmit = false; @@ -280,6 +306,28 @@ bool HTMLFormElement::prepareSubmit(Event* event) return m_doingsubmit; } +static void transferMailtoPostFormDataToURL(RefPtr<FormData>& data, KURL& url, const String& encodingType) +{ + String body = data->flattenToString(); + data = FormData::create(); + + if (equalIgnoringCase(encodingType, "text/plain")) { + // Convention seems to be to decode, and s/&/\r\n/. Also, spaces are encoded as %20. + body = decodeURLEscapeSequences(body.replace('&', "\r\n").replace('+', ' ') + "\r\n"); + } + + Vector<char> bodyData; + bodyData.append("body=", 5); + FormDataBuilder::encodeStringAsFormData(bodyData, body.utf8()); + body = String(bodyData.data(), bodyData.size()).replace('+', "%20"); + + String query = url.query(); + if (!query.isEmpty()) + query.append('&'); + query.append(body); + url.setQuery(query); +} + void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool lockHistory, bool lockBackForwardList) { FrameView* view = document()->view(); @@ -297,14 +345,14 @@ void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool lockH HTMLFormControlElement* firstSuccessfulSubmitButton = 0; bool needButtonActivation = activateSubmitButton; // do we need to activate a submit button? - frame->loader()->clearRecordedFormValues(); - frame->loader()->setFormAboutToBeSubmitted(this); + Vector<pair<String, String> > formValues; + for (unsigned i = 0; i < formElements.size(); ++i) { HTMLFormControlElement* control = formElements[i]; if (control->hasLocalName(inputTag)) { HTMLInputElement* input = static_cast<HTMLInputElement*>(control); if (input->isTextField()) { - frame->loader()->recordFormValue(input->name(), input->value()); + formValues.append(pair<String, String>(input->name(), input->value())); if (input->isSearchField()) input->addSearchResult(); } @@ -317,6 +365,8 @@ void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool lockH } } + RefPtr<FormState> formState = FormState::create(this, formValues, frame); + if (needButtonActivation && firstSuccessfulSubmitButton) firstSuccessfulSubmitButton->setActivatedSubmit(true); @@ -331,25 +381,22 @@ void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool lockH if (!m_formDataBuilder.isMultiPartForm()) { RefPtr<FormData> data = createFormData(CString()); + if (isMailtoForm()) { - String body = data->flattenToString(); - if (equalIgnoringCase(m_formDataBuilder.encodingType(), "text/plain")) { - // Convention seems to be to decode, and s/&/\r\n/. Also, spaces are encoded as %20. - body = decodeURLEscapeSequences(body.replace('&', "\r\n").replace('+', ' ') + "\r\n"); - } - Vector<char> bodyData; - bodyData.append("body=", 5); - FormDataBuilder::encodeStringAsFormData(bodyData, body.utf8()); - data = FormData::create(String(bodyData.data(), bodyData.size()).replace('+', "%20").latin1()); + // Convert the form data into a string that we put into the URL. + KURL url = document()->completeURL(m_url); + transferMailtoPostFormDataToURL(data, url, m_formDataBuilder.encodingType()); + m_url = url.string(); } - frame->loader()->submitForm("POST", m_url, data, m_target, m_formDataBuilder.encodingType(), String(), event, lockHistory, lockBackForwardList); + + frame->loader()->submitForm("POST", m_url, data.release(), m_target, m_formDataBuilder.encodingType(), String(), lockHistory, lockBackForwardList, event, formState.release()); } else { Vector<char> boundary = m_formDataBuilder.generateUniqueBoundaryString(); - frame->loader()->submitForm("POST", m_url, createFormData(boundary.data()), m_target, m_formDataBuilder.encodingType(), boundary.data(), event, lockHistory, lockBackForwardList); + frame->loader()->submitForm("POST", m_url, createFormData(boundary.data()), m_target, m_formDataBuilder.encodingType(), boundary.data(), lockHistory, lockBackForwardList, event, formState.release()); } } else { m_formDataBuilder.setIsMultiPartForm(false); - frame->loader()->submitForm("GET", m_url, createFormData(CString()), m_target, String(), String(), event, lockHistory, lockBackForwardList); + frame->loader()->submitForm("GET", m_url, createFormData(CString()), m_target, String(), String(), lockHistory, lockBackForwardList, event, formState.release()); } if (needButtonActivation && firstSuccessfulSubmitButton) @@ -368,7 +415,7 @@ void HTMLFormElement::reset() // ### DOM2 labels this event as not cancelable, however // common browsers( sick! ) allow it be cancelled. - if ( !dispatchEventForType(eventNames().resetEvent,true, true) ) { + if ( !dispatchEvent(eventNames().resetEvent,true, true) ) { m_inreset = false; return; } @@ -402,9 +449,9 @@ void HTMLFormElement::parseMappedAttribute(MappedAttribute* attr) else document()->unregisterForDocumentActivationCallbacks(this); } else if (attr->name() == onsubmitAttr) - setInlineEventListenerForTypeAndAttribute(eventNames().submitEvent, attr); + setAttributeEventListener(eventNames().submitEvent, createAttributeEventListener(this, attr)); else if (attr->name() == onresetAttr) - setInlineEventListenerForTypeAndAttribute(eventNames().resetEvent, attr); + setAttributeEventListener(eventNames().resetEvent, createAttributeEventListener(this, attr)); else if (attr->name() == nameAttr) { const AtomicString& newName = attr->value(); if (inDocument() && document()->isHTMLDocument()) { @@ -581,70 +628,14 @@ void HTMLFormElement::willMoveToNewOwnerDocument() { if (!m_autocomplete) document()->unregisterForDocumentActivationCallbacks(this); + HTMLElement::willMoveToNewOwnerDocument(); } void HTMLFormElement::didMoveToNewOwnerDocument() { - if(m_autocomplete) + if (!m_autocomplete) document()->registerForDocumentActivationCallbacks(this); -} - -void HTMLFormElement::CheckedRadioButtons::addButton(HTMLFormControlElement* element) -{ - // We only want to add radio buttons. - if (!element->isRadioButton()) - return; - - // Without a name, there is no group. - if (element->name().isEmpty()) - return; - - HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(element); - - // We only track checked buttons. - if (!inputElement->checked()) - return; - - if (!m_nameToCheckedRadioButtonMap) - m_nameToCheckedRadioButtonMap.set(new NameToInputMap); - - pair<NameToInputMap::iterator, bool> result = m_nameToCheckedRadioButtonMap->add(element->name().impl(), inputElement); - if (result.second) - return; - - HTMLInputElement* oldCheckedButton = result.first->second; - if (oldCheckedButton == inputElement) - return; - - result.first->second = inputElement; - oldCheckedButton->setChecked(false); -} - -HTMLInputElement* HTMLFormElement::CheckedRadioButtons::checkedButtonForGroup(const AtomicString& name) const -{ - if (!m_nameToCheckedRadioButtonMap) - return 0; - - return m_nameToCheckedRadioButtonMap->get(name.impl()); -} - -void HTMLFormElement::CheckedRadioButtons::removeButton(HTMLFormControlElement* element) -{ - if (element->name().isEmpty() || !m_nameToCheckedRadioButtonMap) - return; - - NameToInputMap::iterator it = m_nameToCheckedRadioButtonMap->find(element->name().impl()); - if (it == m_nameToCheckedRadioButtonMap->end() || it->second != element) - return; - - InputElement* inputElement = toInputElement(element); - ASSERT_UNUSED(inputElement, inputElement); - ASSERT(inputElement->isChecked()); - ASSERT(element->isRadioButton()); - - m_nameToCheckedRadioButtonMap->remove(it); - if (m_nameToCheckedRadioButtonMap->isEmpty()) - m_nameToCheckedRadioButtonMap.clear(); + HTMLElement::didMoveToNewOwnerDocument(); } } // namespace diff --git a/WebCore/html/HTMLFormElement.h b/WebCore/html/HTMLFormElement.h index 8e5027c..d08e16c 100644 --- a/WebCore/html/HTMLFormElement.h +++ b/WebCore/html/HTMLFormElement.h @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,10 +24,9 @@ #ifndef HTMLFormElement_h #define HTMLFormElement_h +#include "CheckedRadioButtons.h" #include "FormDataBuilder.h" -#include "HTMLCollection.h" #include "HTMLElement.h" - #include <wtf/OwnPtr.h> namespace WebCore { @@ -40,6 +39,8 @@ class HTMLInputElement; class HTMLFormCollection; class TextEncoding; +struct CollectionCache; + class HTMLFormElement : public HTMLElement { public: HTMLFormElement(const QualifiedName&, Document*); @@ -49,6 +50,7 @@ public: virtual int tagPriority() const { return 3; } virtual void attach(); + virtual bool rendererIsNeeded(RenderStyle*); virtual void insertedIntoDocument(); virtual void removedFromDocument(); @@ -83,6 +85,9 @@ public: void setMalformed(bool malformed) { m_malformed = malformed; } bool isMalformed() const { return m_malformed; } + void setDemoted(bool demoted) { m_demoted = demoted; } + bool isDemoted() const { return m_demoted; } + virtual bool isURLAttribute(Attribute*) const; void submitClick(Event*); @@ -109,17 +114,6 @@ public: // FIXME: Change this to be private after getting rid of all the clients. Vector<HTMLFormControlElement*> formElements; - class CheckedRadioButtons { - public: - void addButton(HTMLFormControlElement*); - void removeButton(HTMLFormControlElement*); - HTMLInputElement* checkedButtonForGroup(const AtomicString& name) const; - - private: - typedef HashMap<AtomicStringImpl*, HTMLInputElement*> NameToInputMap; - OwnPtr<NameToInputMap> m_nameToCheckedRadioButtonMap; - }; - CheckedRadioButtons& checkedRadioButtons() { return m_checkedRadioButtons; } virtual void documentDidBecomeActive(); @@ -140,7 +134,7 @@ private: FormDataBuilder m_formDataBuilder; AliasMap* m_elementAliases; - HTMLCollection::CollectionInfo* collectionInfo; + CollectionCache* collectionInfo; CheckedRadioButtons m_checkedRadioButtons; @@ -152,6 +146,7 @@ private: bool m_doingsubmit : 1; bool m_inreset : 1; bool m_malformed : 1; + bool m_demoted : 1; AtomicString m_name; }; diff --git a/WebCore/html/HTMLFrameElement.cpp b/WebCore/html/HTMLFrameElement.cpp index 63ec265..adc3ff1 100644 --- a/WebCore/html/HTMLFrameElement.cpp +++ b/WebCore/html/HTMLFrameElement.cpp @@ -27,14 +27,15 @@ #include "Frame.h" #include "HTMLFrameSetElement.h" #include "HTMLNames.h" +#include "MappedAttribute.h" #include "RenderFrame.h" namespace WebCore { using namespace HTMLNames; -HTMLFrameElement::HTMLFrameElement(const QualifiedName& tagName, Document* doc, bool createdByParser) - : HTMLFrameElementBase(tagName, doc, createdByParser) +HTMLFrameElement::HTMLFrameElement(const QualifiedName& tagName, Document* document) + : HTMLFrameElementBase(tagName, document) , m_frameBorder(true) , m_frameBorderSet(false) { diff --git a/WebCore/html/HTMLFrameElement.h b/WebCore/html/HTMLFrameElement.h index 5cd9b92..ab602ee 100644 --- a/WebCore/html/HTMLFrameElement.h +++ b/WebCore/html/HTMLFrameElement.h @@ -33,10 +33,9 @@ class RenderObject; class RenderArena; class RenderStyle; -class HTMLFrameElement : public HTMLFrameElementBase -{ +class HTMLFrameElement : public HTMLFrameElementBase { public: - HTMLFrameElement(const QualifiedName&, Document*, bool createdByParser); + HTMLFrameElement(const QualifiedName&, Document*); virtual HTMLTagStatus endTagRequirement() const { return TagStatusForbidden; } virtual int tagPriority() const { return 0; } diff --git a/WebCore/html/HTMLFrameElement.idl b/WebCore/html/HTMLFrameElement.idl index bc512ff..106e57e 100644 --- a/WebCore/html/HTMLFrameElement.idl +++ b/WebCore/html/HTMLFrameElement.idl @@ -38,15 +38,17 @@ module html { // Introduced in DOM Level 2: readonly attribute [CheckFrameSecurity] Document contentDocument; -#if !defined(LANGUAGE_COM) +#if !defined(LANGUAGE_COM) || !LANGUAGE_COM // Extensions readonly attribute DOMWindow contentWindow; -#if ENABLE_SVG +#if defined(ENABLE_SVG) && ENABLE_SVG +#if !defined(LANGUAGE_OBJECTIVE_C) || !LANGUAGE_OBJECTIVE_C || defined(ENABLE_SVG_DOM_OBJC_BINDINGS) && ENABLE_SVG_DOM_OBJC_BINDINGS [SVGCheckSecurityDocument] SVGDocument getSVGDocument() raises(DOMException); #endif #endif +#endif attribute [ConvertNullToNullString, CustomSetter] DOMString location; readonly attribute long width; diff --git a/WebCore/html/HTMLFrameElementBase.cpp b/WebCore/html/HTMLFrameElementBase.cpp index 59e7d46..1e09595 100644 --- a/WebCore/html/HTMLFrameElementBase.cpp +++ b/WebCore/html/HTMLFrameElementBase.cpp @@ -34,7 +34,9 @@ #include "FrameView.h" #include "HTMLFrameSetElement.h" #include "HTMLNames.h" +#include "ScriptEventListener.h" #include "KURL.h" +#include "MappedAttribute.h" #include "Page.h" #include "RenderFrame.h" #include "Settings.h" @@ -43,8 +45,8 @@ namespace WebCore { using namespace HTMLNames; -HTMLFrameElementBase::HTMLFrameElementBase(const QualifiedName& tagName, Document* doc, bool createdByParser) - : HTMLFrameOwnerElement(tagName, doc, createdByParser) +HTMLFrameElementBase::HTMLFrameElementBase(const QualifiedName& tagName, Document* document) + : HTMLFrameOwnerElement(tagName, document) , m_scrolling(ScrollbarAuto) , m_marginWidth(-1) , m_marginHeight(-1) @@ -140,10 +142,10 @@ void HTMLFrameElementBase::parseMappedAttribute(MappedAttribute *attr) if (contentFrame()) contentFrame()->setInViewSourceMode(viewSourceMode()); } else if (attr->name() == onloadAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().loadEvent, attr); + setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onbeforeunloadAttr) { // FIXME: should <frame> elements have beforeunload handlers? - setInlineEventListenerForTypeAndAttribute(eventNames().beforeunloadEvent, attr); + setAttributeEventListener(eventNames().beforeunloadEvent, createAttributeEventListener(this, attr)); } else HTMLFrameOwnerElement::parseMappedAttribute(attr); } diff --git a/WebCore/html/HTMLFrameElementBase.h b/WebCore/html/HTMLFrameElementBase.h index 923cd2f..4a24451 100644 --- a/WebCore/html/HTMLFrameElementBase.h +++ b/WebCore/html/HTMLFrameElementBase.h @@ -82,7 +82,7 @@ public: bool viewSourceMode() const { return m_viewSource; } protected: - HTMLFrameElementBase(const QualifiedName&, Document*, bool createdByParser); + HTMLFrameElementBase(const QualifiedName&, Document*); bool isURLAllowed(const AtomicString&) const; void setNameAndOpenURL(); diff --git a/WebCore/html/HTMLFrameOwnerElement.cpp b/WebCore/html/HTMLFrameOwnerElement.cpp index 2e16e33..a98a3df 100644 --- a/WebCore/html/HTMLFrameOwnerElement.cpp +++ b/WebCore/html/HTMLFrameOwnerElement.cpp @@ -32,10 +32,9 @@ namespace WebCore { -HTMLFrameOwnerElement::HTMLFrameOwnerElement(const QualifiedName& tagName, Document* document, bool createdByParser) +HTMLFrameOwnerElement::HTMLFrameOwnerElement(const QualifiedName& tagName, Document* document) : HTMLElement(tagName, document) , m_contentFrame(0) - , m_createdByParser(createdByParser) { } diff --git a/WebCore/html/HTMLFrameOwnerElement.h b/WebCore/html/HTMLFrameOwnerElement.h index e887be0..3f50a02 100644 --- a/WebCore/html/HTMLFrameOwnerElement.h +++ b/WebCore/html/HTMLFrameOwnerElement.h @@ -35,7 +35,7 @@ class SVGDocument; class HTMLFrameOwnerElement : public HTMLElement { protected: - HTMLFrameOwnerElement(const QualifiedName& tagName, Document*, bool createdByParser); + HTMLFrameOwnerElement(const QualifiedName& tagName, Document*); public: virtual ~HTMLFrameOwnerElement(); @@ -49,8 +49,6 @@ public: virtual bool isFrameOwnerElement() const { return true; } virtual bool isKeyboardFocusable(KeyboardEvent*) const { return m_contentFrame; } - bool createdByParser() const { return m_createdByParser; } - virtual ScrollbarMode scrollingMode() const { return ScrollbarAuto; } #if ENABLE(SVG) @@ -60,7 +58,6 @@ public: private: friend class Frame; Frame* m_contentFrame; - bool m_createdByParser; }; } // namespace WebCore diff --git a/WebCore/html/HTMLFrameSetElement.cpp b/WebCore/html/HTMLFrameSetElement.cpp index 3994de4..f8e244c 100644 --- a/WebCore/html/HTMLFrameSetElement.cpp +++ b/WebCore/html/HTMLFrameSetElement.cpp @@ -29,8 +29,9 @@ #include "Event.h" #include "EventNames.h" #include "HTMLNames.h" +#include "ScriptEventListener.h" #include "Length.h" -#include "Length.h" +#include "MappedAttribute.h" #include "MouseEvent.h" #include "RenderFrameSet.h" #include "Text.h" @@ -88,13 +89,13 @@ void HTMLFrameSetElement::parseMappedAttribute(MappedAttribute *attr) if (!attr->isNull()) { if (m_rows) delete [] m_rows; m_rows = newLengthArray(attr->value().string(), m_totalRows); - setChanged(); + setNeedsStyleRecalc(); } } else if (attr->name() == colsAttr) { if (!attr->isNull()) { delete [] m_cols; m_cols = newLengthArray(attr->value().string(), m_totalCols); - setChanged(); + setNeedsStyleRecalc(); } } else if (attr->name() == frameborderAttr) { if (!attr->isNull()) { @@ -125,11 +126,11 @@ void HTMLFrameSetElement::parseMappedAttribute(MappedAttribute *attr) m_borderColorSet = true; } } else if (attr->name() == onloadAttr) { - document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().loadEvent, attr); + document()->setWindowAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(document()->frame(), attr)); } else if (attr->name() == onbeforeunloadAttr) { - document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().beforeunloadEvent, attr); + document()->setWindowAttributeEventListener(eventNames().beforeunloadEvent, createAttributeEventListener(document()->frame(), attr)); } else if (attr->name() == onunloadAttr) { - document()->setWindowInlineEventListenerForTypeAndAttribute(eventNames().unloadEvent, attr); + document()->setWindowAttributeEventListener(eventNames().unloadEvent, createAttributeEventListener(document()->frame(), attr)); } else HTMLElement::parseMappedAttribute(attr); } @@ -186,12 +187,12 @@ void HTMLFrameSetElement::defaultEventHandler(Event* evt) void HTMLFrameSetElement::recalcStyle(StyleChange ch) { - if (changed() && renderer()) { + if (needsStyleRecalc() && renderer()) { renderer()->setNeedsLayout(true); #ifdef FLATTEN_FRAMESET static_cast<RenderFrameSet*>(renderer())->setGridNeedsLayout(); #endif - setChanged(NoStyleChange); + setNeedsStyleRecalc(NoStyleChange); } HTMLElement::recalcStyle(ch); } diff --git a/WebCore/html/HTMLHRElement.cpp b/WebCore/html/HTMLHRElement.cpp index 8be23fd..d6cc58e 100644 --- a/WebCore/html/HTMLHRElement.cpp +++ b/WebCore/html/HTMLHRElement.cpp @@ -19,12 +19,14 @@ * Boston, MA 02110-1301, USA. * */ + #include "config.h" #include "HTMLHRElement.h" #include "CSSPropertyNames.h" #include "CSSValueKeywords.h" #include "HTMLNames.h" +#include "MappedAttribute.h" namespace WebCore { diff --git a/WebCore/html/HTMLHtmlElement.cpp b/WebCore/html/HTMLHtmlElement.cpp index 4ed2400..d4867a4 100644 --- a/WebCore/html/HTMLHtmlElement.cpp +++ b/WebCore/html/HTMLHtmlElement.cpp @@ -53,10 +53,8 @@ void HTMLHtmlElement::setVersion(const String &value) bool HTMLHtmlElement::checkDTD(const Node* newChild) { - // FIXME: Why is <script> allowed here? return newChild->hasTagName(headTag) || newChild->hasTagName(bodyTag) || - newChild->hasTagName(framesetTag) || newChild->hasTagName(noframesTag) || - newChild->hasTagName(scriptTag); + newChild->hasTagName(framesetTag) || newChild->hasTagName(noframesTag); } #if ENABLE(OFFLINE_WEB_APPLICATIONS) diff --git a/WebCore/html/HTMLIFrameElement.cpp b/WebCore/html/HTMLIFrameElement.cpp index 9ba3b13..a190bca 100644 --- a/WebCore/html/HTMLIFrameElement.cpp +++ b/WebCore/html/HTMLIFrameElement.cpp @@ -28,14 +28,15 @@ #include "Frame.h" #include "HTMLDocument.h" #include "HTMLNames.h" +#include "MappedAttribute.h" #include "RenderPartObject.h" namespace WebCore { using namespace HTMLNames; -HTMLIFrameElement::HTMLIFrameElement(const QualifiedName& tagName, Document* doc, bool createdByParser) - : HTMLFrameElementBase(tagName, doc, createdByParser) +HTMLIFrameElement::HTMLIFrameElement(const QualifiedName& tagName, Document* document) + : HTMLFrameElementBase(tagName, document) { ASSERT(hasTagName(iframeTag)); } diff --git a/WebCore/html/HTMLIFrameElement.h b/WebCore/html/HTMLIFrameElement.h index 3407a6d..362b991 100644 --- a/WebCore/html/HTMLIFrameElement.h +++ b/WebCore/html/HTMLIFrameElement.h @@ -30,7 +30,7 @@ namespace WebCore { class HTMLIFrameElement : public HTMLFrameElementBase { public: - HTMLIFrameElement(const QualifiedName&, Document*, bool createdByParser); + HTMLIFrameElement(const QualifiedName&, Document*); virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } virtual int tagPriority() const { return 1; } diff --git a/WebCore/html/HTMLIFrameElement.idl b/WebCore/html/HTMLIFrameElement.idl index c6a8599..b5684ca 100644 --- a/WebCore/html/HTMLIFrameElement.idl +++ b/WebCore/html/HTMLIFrameElement.idl @@ -40,15 +40,17 @@ module html { // Introduced in DOM Level 2: readonly attribute [CheckFrameSecurity] Document contentDocument; -#if !defined(LANGUAGE_COM) +#if !defined(LANGUAGE_COM) || !LANGUAGE_COM // Extensions readonly attribute DOMWindow contentWindow; -#if ENABLE_SVG +#if defined(ENABLE_SVG) && ENABLE_SVG +#if !defined(LANGUAGE_OBJECTIVE_C) || !LANGUAGE_OBJECTIVE_C || defined(ENABLE_SVG_DOM_OBJC_BINDINGS) && ENABLE_SVG_DOM_OBJC_BINDINGS [SVGCheckSecurityDocument] SVGDocument getSVGDocument() raises(DOMException); #endif #endif +#endif }; diff --git a/WebCore/html/HTMLImageElement.cpp b/WebCore/html/HTMLImageElement.cpp index c4e7608..c4bf5dc 100644 --- a/WebCore/html/HTMLImageElement.cpp +++ b/WebCore/html/HTMLImageElement.cpp @@ -30,7 +30,9 @@ #include "HTMLDocument.h" #include "HTMLFormElement.h" #include "HTMLNames.h" +#include "MappedAttribute.h" #include "RenderImage.h" +#include "ScriptEventListener.h" using namespace std; @@ -113,9 +115,9 @@ void HTMLImageElement::parseMappedAttribute(MappedAttribute* attr) } else if (attrName == ismapAttr) ismap = true; else if (attrName == onabortAttr) - setInlineEventListenerForTypeAndAttribute(eventNames().abortEvent, attr); + setAttributeEventListener(eventNames().abortEvent, createAttributeEventListener(this, attr)); else if (attrName == onloadAttr) - setInlineEventListenerForTypeAndAttribute(eventNames().loadEvent, attr); + setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr)); else if (attrName == compositeAttr) { if (!parseCompositeOperator(attr->value(), m_compositeOperator)) m_compositeOperator = CompositeSourceOver; diff --git a/WebCore/html/HTMLImageElement.idl b/WebCore/html/HTMLImageElement.idl index fe64e6f..d7da088 100644 --- a/WebCore/html/HTMLImageElement.idl +++ b/WebCore/html/HTMLImageElement.idl @@ -46,7 +46,7 @@ module html { readonly attribute long x; readonly attribute long y; -#if defined(LANGUAGE_OBJECTIVE_C) +#if defined(LANGUAGE_OBJECTIVE_C) && LANGUAGE_OBJECTIVE_C // Objective-C extension: readonly attribute DOMString altDisplayString; readonly attribute URL absoluteImageURL; diff --git a/WebCore/html/HTMLImageLoader.cpp b/WebCore/html/HTMLImageLoader.cpp index 5dac8bf..ea53d7e 100644 --- a/WebCore/html/HTMLImageLoader.cpp +++ b/WebCore/html/HTMLImageLoader.cpp @@ -42,7 +42,10 @@ HTMLImageLoader::~HTMLImageLoader() void HTMLImageLoader::dispatchLoadEvent() { - element()->dispatchEventForType(image()->errorOccurred() ? eventNames().errorEvent : eventNames().loadEvent, false, false); + bool errorOccurred = image()->errorOccurred(); + if (!errorOccurred && image()->httpStatusCodeErrorOccurred()) + errorOccurred = element()->hasTagName(HTMLNames::objectTag); // An <object> considers a 404 to be an error and should fire onerror. + element()->dispatchEvent(errorOccurred ? eventNames().errorEvent : eventNames().loadEvent, false, false); } String HTMLImageLoader::sourceURI(const AtomicString& attr) const @@ -50,12 +53,14 @@ String HTMLImageLoader::sourceURI(const AtomicString& attr) const return parseURL(attr); } -void HTMLImageLoader::notifyFinished(CachedResource* image) -{ +void HTMLImageLoader::notifyFinished(CachedResource*) +{ + CachedImage* cachedImage = image(); + Element* elem = element(); - ImageLoader::notifyFinished(image); + ImageLoader::notifyFinished(cachedImage); - if (image->errorOccurred() && elem->hasTagName(HTMLNames::objectTag)) + if ((cachedImage->errorOccurred() || cachedImage->httpStatusCodeErrorOccurred()) && elem->hasTagName(HTMLNames::objectTag)) static_cast<HTMLObjectElement*>(elem)->renderFallbackContent(); } diff --git a/WebCore/html/HTMLInputElement.cpp b/WebCore/html/HTMLInputElement.cpp index 103b740..2d1b3d0 100644 --- a/WebCore/html/HTMLInputElement.cpp +++ b/WebCore/html/HTMLInputElement.cpp @@ -26,8 +26,8 @@ #include "config.h" #include "HTMLInputElement.h" -#include "ChromeClient.h" #include "CSSPropertyNames.h" +#include "ChromeClient.h" #include "Document.h" #include "Editor.h" #include "Event.h" @@ -41,8 +41,10 @@ #include "HTMLFormElement.h" #include "HTMLImageLoader.h" #include "HTMLNames.h" +#include "ScriptEventListener.h" #include "KeyboardEvent.h" #include "LocalizedStrings.h" +#include "MappedAttribute.h" #include "MouseEvent.h" #include "Page.h" #include "RenderButton.h" @@ -68,7 +70,6 @@ const int maxSavedResults = 256; HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f) : HTMLFormControlElementWithState(tagName, doc, f) - , m_data(this, this) , m_xPos(0) , m_yPos(0) , m_maxResults(-1) @@ -98,7 +99,7 @@ HTMLInputElement::~HTMLInputElement() removeFromForm(); } -const AtomicString& HTMLInputElement::name() const +const AtomicString& HTMLInputElement::formControlName() const { return m_data.name(); } @@ -116,8 +117,7 @@ bool HTMLInputElement::autoComplete() const return true; } - -static inline HTMLFormElement::CheckedRadioButtons& checkedRadioButtons(const HTMLInputElement *element) +static inline CheckedRadioButtons& checkedRadioButtons(const HTMLInputElement *element) { if (HTMLFormElement* form = element->form()) return form->checkedRadioButtons(); @@ -164,14 +164,14 @@ bool HTMLInputElement::isMouseFocusable() const void HTMLInputElement::updateFocusAppearance(bool restorePreviousSelection) { if (isTextField()) - InputElement::updateFocusAppearance(m_data, document(), restorePreviousSelection); + InputElement::updateFocusAppearance(m_data, this, this, restorePreviousSelection); else HTMLFormControlElementWithState::updateFocusAppearance(restorePreviousSelection); } void HTMLInputElement::aboutToUnload() { - InputElement::aboutToUnload(m_data, document()); + InputElement::aboutToUnload(this, this); } bool HTMLInputElement::shouldUseInputMethod() const @@ -181,7 +181,7 @@ bool HTMLInputElement::shouldUseInputMethod() const void HTMLInputElement::dispatchFocusEvent() { - InputElement::dispatchFocusEvent(m_data, document()); + InputElement::dispatchFocusEvent(m_data, this, this); if (isTextField()) m_autofilled = false; @@ -191,7 +191,7 @@ void HTMLInputElement::dispatchFocusEvent() void HTMLInputElement::dispatchBlurEvent() { - InputElement::dispatchBlurEvent(m_data, document()); + InputElement::dispatchBlurEvent(m_data, this, this); HTMLFormControlElementWithState::dispatchBlurEvent(); } @@ -242,6 +242,14 @@ void HTMLInputElement::setInputType(const String& t) newType = SEARCH; else if (equalIgnoringCase(t, "range")) newType = RANGE; + else if (equalIgnoringCase(t, "email")) + newType = EMAIL; + else if (equalIgnoringCase(t, "number")) + newType = NUMBER; + else if (equalIgnoringCase(t, "tel")) + newType = TELEPHONE; + else if (equalIgnoringCase(t, "url")) + newType = URL; else newType = TEXT; @@ -278,7 +286,7 @@ void HTMLInputElement::setInputType(const String& t) if (!didStoreValue && willStoreValue) m_data.setValue(constrainValue(getAttribute(valueAttr))); else - InputElement::updateValueIfNeeded(m_data); + InputElement::updateValueIfNeeded(m_data, this); if (wasPasswordField && !isPasswordField) unregisterForActivationCallbackIfNeeded(); @@ -287,6 +295,7 @@ void HTMLInputElement::setInputType(const String& t) if (didRespectHeightAndWidth != willRespectHeightAndWidth) { NamedMappedAttrMap* map = mappedAttributes(); + ASSERT(map); if (Attribute* height = map->getAttributeItem(heightAttr)) attributeChanged(height, false); if (Attribute* width = map->getAttributeItem(widthAttr)) @@ -304,7 +313,7 @@ void HTMLInputElement::setInputType(const String& t) checkedRadioButtons(this).addButton(this); } - InputElement::notifyFormStateChanged(m_data, document()); + InputElement::notifyFormStateChanged(this); } m_haveType = true; @@ -312,7 +321,7 @@ void HTMLInputElement::setInputType(const String& t) m_imageLoader.clear(); } -const AtomicString& HTMLInputElement::type() const +const AtomicString& HTMLInputElement::formControlType() const { // needs to be lowercase according to DOM spec switch (inputType()) { @@ -324,6 +333,10 @@ const AtomicString& HTMLInputElement::type() const DEFINE_STATIC_LOCAL(const AtomicString, checkbox, ("checkbox")); return checkbox; } + case EMAIL: { + DEFINE_STATIC_LOCAL(const AtomicString, email, ("email")); + return email; + } case FILE: { DEFINE_STATIC_LOCAL(const AtomicString, file, ("file")); return file; @@ -338,6 +351,10 @@ const AtomicString& HTMLInputElement::type() const } case ISINDEX: return emptyAtom; + case NUMBER: { + DEFINE_STATIC_LOCAL(const AtomicString, number, ("number")); + return number; + } case PASSWORD: { DEFINE_STATIC_LOCAL(const AtomicString, password, ("password")); return password; @@ -362,30 +379,42 @@ const AtomicString& HTMLInputElement::type() const DEFINE_STATIC_LOCAL(const AtomicString, submit, ("submit")); return submit; } + case TELEPHONE: { + DEFINE_STATIC_LOCAL(const AtomicString, telephone, ("tel")); + return telephone; + } case TEXT: { DEFINE_STATIC_LOCAL(const AtomicString, text, ("text")); return text; } + case URL: { + DEFINE_STATIC_LOCAL(const AtomicString, url, ("url")); + return url; + } } return emptyAtom; } -bool HTMLInputElement::saveState(String& result) const +bool HTMLInputElement::saveFormControlState(String& result) const { if (!autoComplete()) return false; switch (inputType()) { case BUTTON: + case EMAIL: case FILE: case HIDDEN: case IMAGE: case ISINDEX: + case NUMBER: case RANGE: case RESET: case SEARCH: case SUBMIT: + case TELEPHONE: case TEXT: + case URL: result = value(); return true; case CHECKBOX: @@ -399,20 +428,24 @@ bool HTMLInputElement::saveState(String& result) const return false; } -void HTMLInputElement::restoreState(const String& state) +void HTMLInputElement::restoreFormControlState(const String& state) { ASSERT(inputType() != PASSWORD); // should never save/restore password fields switch (inputType()) { case BUTTON: + case EMAIL: case FILE: case HIDDEN: case IMAGE: case ISINDEX: + case NUMBER: case RANGE: case RESET: case SEARCH: case SUBMIT: + case TELEPHONE: case TEXT: + case URL: setValue(state); break; case CHECKBOX: @@ -487,7 +520,7 @@ void HTMLInputElement::select() void HTMLInputElement::setSelectionRange(int start, int end) { - InputElement::updateSelectionRange(m_data, start, end); + InputElement::updateSelectionRange(this, this, start, end); } void HTMLInputElement::accessKeyAction(bool sendToAnyElement) @@ -508,10 +541,14 @@ void HTMLInputElement::accessKeyAction(bool sendToAnyElement) case HIDDEN: // a no-op for this type break; + case EMAIL: case ISINDEX: + case NUMBER: case PASSWORD: case SEARCH: + case TELEPHONE: case TEXT: + case URL: // should never restore previous selection here focus(false); break; @@ -561,8 +598,8 @@ void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr) } else if (attr->name() == valueAttr) { // We only need to setChanged if the form is looking at the default value right now. if (m_data.value().isNull()) - setChanged(); - setValueMatchesRenderer(false); + setNeedsStyleRecalc(); + setFormControlValueMatchesRenderer(false); } else if (attr->name() == checkedAttr) { m_defaultChecked = !attr->isNull(); if (m_useDefaultChecked) { @@ -570,9 +607,9 @@ void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr) m_useDefaultChecked = true; } } else if (attr->name() == maxlengthAttr) - InputElement::parseMaxLengthAttribute(m_data, attr); + InputElement::parseMaxLengthAttribute(m_data, this, this, attr); else if (attr->name() == sizeAttr) - InputElement::parseSizeAttribute(m_data, attr); + InputElement::parseSizeAttribute(m_data, this, attr); else if (attr->name() == altAttr) { if (renderer() && inputType() == IMAGE) toRenderImage(renderer())->updateAltText(); @@ -601,20 +638,20 @@ void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr) if (respectHeightAndWidthAttrs()) addCSSLength(attr, CSSPropertyHeight, attr->value()); } else if (attr->name() == onfocusAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().focusEvent, attr); + setAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onblurAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().blurEvent, attr); + setAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onselectAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().selectEvent, attr); + setAttributeEventListener(eventNames().selectEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onchangeAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().changeEvent, attr); + setAttributeEventListener(eventNames().changeEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == oninputAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().inputEvent, attr); + setAttributeEventListener(eventNames().inputEvent, createAttributeEventListener(this, attr)); } // Search field and slider attributes all just cause updateFromElement to be called through style // recalcing. else if (attr->name() == onsearchAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().searchEvent, attr); + setAttributeEventListener(eventNames().searchEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == resultsAttr) { int oldResults = m_maxResults; m_maxResults = !attr->isNull() ? min(attr->value().toInt(), maxSavedResults) : -1; @@ -624,17 +661,17 @@ void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr) detach(); attach(); } - setChanged(); + setNeedsStyleRecalc(); } else if (attr->name() == placeholderAttr) { if (isTextField()) - InputElement::updatePlaceholderVisibility(m_data, document(), true); + updatePlaceholderVisibility(); } else if (attr->name() == autosaveAttr || attr->name() == incrementalAttr || attr->name() == minAttr || attr->name() == maxAttr || attr->name() == multipleAttr || attr->name() == precisionAttr) - setChanged(); + setNeedsStyleRecalc(); else HTMLFormControlElementWithState::parseMappedAttribute(attr); } @@ -644,16 +681,20 @@ bool HTMLInputElement::rendererIsNeeded(RenderStyle *style) switch (inputType()) { case BUTTON: case CHECKBOX: + case EMAIL: case FILE: case IMAGE: case ISINDEX: + case NUMBER: case PASSWORD: case RADIO: case RANGE: case RESET: case SEARCH: case SUBMIT: + case TELEPHONE: case TEXT: + case URL: return HTMLFormControlElementWithState::rendererIsNeeded(style); case HIDDEN: return false; @@ -680,10 +721,14 @@ RenderObject *HTMLInputElement::createRenderer(RenderArena *arena, RenderStyle * return new (arena) RenderImage(this); case RANGE: return new (arena) RenderSlider(this); + case EMAIL: case ISINDEX: + case NUMBER: case PASSWORD: case SEARCH: + case TELEPHONE: case TEXT: + case URL: return new (arena) RenderTextControlSingleLine(this); } ASSERT(false); @@ -719,7 +764,7 @@ void HTMLInputElement::attach() void HTMLInputElement::detach() { HTMLFormControlElementWithState::detach(); - setValueMatchesRenderer(false); + setFormControlValueMatchesRenderer(false); } String HTMLInputElement::altText() const @@ -762,12 +807,16 @@ bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart) return false; switch (inputType()) { + case EMAIL: case HIDDEN: case ISINDEX: + case NUMBER: case PASSWORD: case RANGE: case SEARCH: + case TELEPHONE: case TEXT: + case URL: // always successful encoding.appendData(name(), value()); return true; @@ -842,7 +891,7 @@ void HTMLInputElement::setChecked(bool nowChecked, bool sendChangeEvent) m_useDefaultChecked = false; m_checked = nowChecked; - setChanged(); + setNeedsStyleRecalc(); checkedRadioButtons(this).addButton(this); @@ -855,7 +904,7 @@ void HTMLInputElement::setChecked(bool nowChecked, bool sendChangeEvent) // because it says only to fire change events at "lose focus" time, which is // definitely wrong in practice for these types of elements. if (sendChangeEvent && inDocument() && (inputType() != RADIO || nowChecked)) - onChange(); + dispatchFormControlChangeEvent(); } void HTMLInputElement::setIndeterminate(bool _indeterminate) @@ -866,7 +915,7 @@ void HTMLInputElement::setIndeterminate(bool _indeterminate) m_indeterminate = _indeterminate; - setChanged(); + setNeedsStyleRecalc(); if (renderer() && renderer()->style()->hasAppearance()) theme()->stateChanged(renderer(), CheckedState); @@ -917,15 +966,19 @@ String HTMLInputElement::valueWithDefault() const switch (inputType()) { case BUTTON: case CHECKBOX: + case EMAIL: case FILE: case HIDDEN: case IMAGE: case ISINDEX: + case NUMBER: case PASSWORD: case RADIO: case RANGE: case SEARCH: + case TELEPHONE: case TEXT: + case URL: break; case RESET: v = resetButtonDefaultLabel(); @@ -946,21 +999,21 @@ void HTMLInputElement::setValue(const String& value) if (inputType() == FILE && !value.isEmpty()) return; - setValueMatchesRenderer(false); + setFormControlValueMatchesRenderer(false); if (storesValueSeparateFromAttribute()) { if (inputType() == FILE) m_fileList->clear(); else { m_data.setValue(constrainValue(value)); if (isTextField()) { - InputElement::updatePlaceholderVisibility(m_data, document()); + InputElement::updatePlaceholderVisibility(m_data, this, this); if (inDocument()) - document()->updateRendering(); + document()->updateStyleIfNeeded(); } } if (renderer()) renderer()->updateFromElement(); - setChanged(); + setNeedsStyleRecalc(); } else setAttribute(valueAttr, constrainValue(value)); @@ -972,21 +1025,26 @@ void HTMLInputElement::setValue(const String& value) // Make sure our UI side textfield changes to match the RenderTextControl android::WebViewCore::getWebViewCore(document()->view())->updateTextfield(this, false, value); #endif - InputElement::updateSelectionRange(m_data, max, max); + InputElement::updateSelectionRange(this, this, max, max); #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS } #endif else cacheSelection(max, max); } - InputElement::notifyFormStateChanged(m_data, document()); + InputElement::notifyFormStateChanged(this); } -String HTMLInputElement::placeholderValue() const +String HTMLInputElement::placeholder() const { return getAttribute(placeholderAttr).string(); } +void HTMLInputElement::setPlaceholder(const String& value) +{ + setAttribute(placeholderAttr, value); +} + bool HTMLInputElement::searchEventsShouldBeDispatched() const { return hasAttribute(incrementalAttr); @@ -996,7 +1054,7 @@ void HTMLInputElement::setValueFromRenderer(const String& value) { // File upload controls will always use setFileListFromRenderer. ASSERT(inputType() != FILE); - InputElement::setValueFromRenderer(m_data, document(), value); + InputElement::setValueFromRenderer(m_data, this, this, value); } void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths) @@ -1006,8 +1064,8 @@ void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths) for (int i = 0; i < size; i++) m_fileList->append(File::create(paths[i])); - setValueMatchesRenderer(); - InputElement::notifyFormStateChanged(m_data, document()); + setFormControlValueMatchesRenderer(true); + InputElement::notifyFormStateChanged(this); } bool HTMLInputElement::storesValueSeparateFromAttribute() const @@ -1021,12 +1079,16 @@ bool HTMLInputElement::storesValueSeparateFromAttribute() const case RESET: case SUBMIT: return false; + case EMAIL: case FILE: case ISINDEX: + case NUMBER: case PASSWORD: case RANGE: case SEARCH: + case TELEPHONE: case TEXT: + case URL: return true; } return false; @@ -1192,12 +1254,16 @@ void HTMLInputElement::defaultEventHandler(Event* evt) if (charCode == '\r') { switch (inputType()) { case CHECKBOX: + case EMAIL: case HIDDEN: case ISINDEX: + case NUMBER: case PASSWORD: case RANGE: case SEARCH: + case TELEPHONE: case TEXT: + case URL: // Simulate mouse click on the default form button for enter for these types of elements. clickDefaultFormButton = true; break; @@ -1316,12 +1382,16 @@ void HTMLInputElement::defaultEventHandler(Event* evt) if (!checked()) clickElement = true; break; + case EMAIL: case HIDDEN: case ISINDEX: + case NUMBER: case PASSWORD: case RANGE: case SEARCH: + case TELEPHONE: case TEXT: + case URL: break; } } @@ -1342,7 +1412,7 @@ void HTMLInputElement::defaultEventHandler(Event* evt) // Fire onChange for text fields. RenderObject* r = renderer(); if (r && r->isTextField() && toRenderTextControl(r)->isEdited()) { - onChange(); + dispatchFormControlChangeEvent(); // Refetch the renderer since arbitrary JS code run during onchange can do anything, including destroying it. r = renderer(); if (r && r->isTextField()) @@ -1356,7 +1426,7 @@ void HTMLInputElement::defaultEventHandler(Event* evt) } if (evt->isBeforeTextInsertedEvent()) - InputElement::handleBeforeTextInsertedEvent(m_data, document(), evt); + InputElement::handleBeforeTextInsertedEvent(m_data, this, document(), evt); if (isTextField() && renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent() || evt->type() == eventNames().blurEvent || evt->type() == eventNames().focusEvent)) static_cast<RenderTextControlSingleLine*>(renderer())->forwardEvent(evt); @@ -1489,7 +1559,7 @@ void HTMLInputElement::setAutofilled(bool b) return; m_autofilled = b; - setChanged(); + setNeedsStyleRecalc(); } FileList* HTMLInputElement::files() @@ -1501,7 +1571,7 @@ FileList* HTMLInputElement::files() String HTMLInputElement::constrainValue(const String& proposedValue) const { - return InputElement::constrainValue(m_data, proposedValue, m_data.maxLength()); + return InputElement::constrainValue(this, proposedValue, m_data.maxLength()); } bool HTMLInputElement::needsActivationCallback() @@ -1539,7 +1609,7 @@ void HTMLInputElement::onSearch() ASSERT(isSearchField()); if (renderer()) static_cast<RenderTextControlSingleLine*>(renderer())->stopSearchEventTimer(); - dispatchEventForType(eventNames().searchEvent, true, false); + dispatchEvent(eventNames().searchEvent, true, false); } VisibleSelection HTMLInputElement::selection() const diff --git a/WebCore/html/HTMLInputElement.h b/WebCore/html/HTMLInputElement.h index 5b6a5d6..be2b4f4 100644 --- a/WebCore/html/HTMLInputElement.h +++ b/WebCore/html/HTMLInputElement.h @@ -50,7 +50,11 @@ public: IMAGE, BUTTON, SEARCH, - RANGE + RANGE, + EMAIL, + NUMBER, + TELEPHONE, + URL }; enum AutoCompleteSetting { @@ -74,7 +78,7 @@ public: virtual void aboutToUnload(); virtual bool shouldUseInputMethod() const; - virtual const AtomicString& name() const; + virtual const AtomicString& formControlName() const; bool autoComplete() const; @@ -82,13 +86,13 @@ public: virtual bool isChecked() const { return checked() && (inputType() == CHECKBOX || inputType() == RADIO); } virtual bool isIndeterminate() const { return indeterminate(); } - bool readOnly() const { return isReadOnlyControl(); } + bool readOnly() const { return isReadOnlyFormControl(); } - virtual bool isTextControl() const { return isTextField(); } + virtual bool isTextFormControl() const { return isTextField(); } bool isTextButton() const { return m_type == SUBMIT || m_type == RESET || m_type == BUTTON; } virtual bool isRadioButton() const { return m_type == RADIO; } - virtual bool isTextField() const { return m_type == TEXT || m_type == PASSWORD || m_type == SEARCH || m_type == ISINDEX; } + virtual bool isTextField() const { return m_type == TEXT || m_type == PASSWORD || m_type == SEARCH || m_type == ISINDEX || m_type == EMAIL || m_type == NUMBER || m_type == TELEPHONE || m_type == URL; } virtual bool isSearchField() const { return m_type == SEARCH; } virtual bool isInputTypeHidden() const { return m_type == HIDDEN; } virtual bool isPasswordField() const { return m_type == PASSWORD; } @@ -98,13 +102,15 @@ public: bool indeterminate() const { return m_indeterminate; } void setIndeterminate(bool); virtual int size() const; - virtual const AtomicString& type() const; + virtual const AtomicString& formControlType() const; void setType(const String&); virtual String value() const; virtual void setValue(const String&); - virtual String placeholderValue() const; + virtual String placeholder() const; + virtual void setPlaceholder(const String&); + virtual bool searchEventsShouldBeDispatched() const; String valueWithDefault() const; @@ -112,8 +118,8 @@ public: virtual void setValueFromRenderer(const String&); void setFileListFromRenderer(const Vector<String>&); - virtual bool saveState(String& value) const; - virtual void restoreState(const String&); + virtual bool saveFormControlState(String& value) const; + virtual void restoreFormControlState(const String&); virtual bool canStartSelection() const; @@ -219,6 +225,11 @@ protected: virtual void willMoveToNewOwnerDocument(); virtual void didMoveToNewOwnerDocument(); + void updatePlaceholderVisibility() + { + InputElement::updatePlaceholderVisibility(m_data, this, this, true); + } + private: bool storesValueSeparateFromAttribute() const; @@ -232,7 +243,7 @@ private: short m_maxResults; OwnPtr<HTMLImageLoader> m_imageLoader; RefPtr<FileList> m_fileList; - unsigned m_type : 4; // InputType + unsigned m_type : 5; // InputType bool m_checked : 1; bool m_defaultChecked : 1; bool m_useDefaultChecked : 1; diff --git a/WebCore/html/HTMLInputElement.idl b/WebCore/html/HTMLInputElement.idl index 0734e6a..5536733 100644 --- a/WebCore/html/HTMLInputElement.idl +++ b/WebCore/html/HTMLInputElement.idl @@ -38,15 +38,16 @@ module html { attribute long maxLength; attribute boolean multiple; attribute [ConvertNullToNullString] DOMString name; + attribute DOMString placeholder; attribute boolean readOnly; -#if defined(LANGUAGE_OBJECTIVE_C) +#if defined(LANGUAGE_OBJECTIVE_C) && LANGUAGE_OBJECTIVE_C attribute [ConvertToString] DOMString size; // DOM level 2 changed this to a long, but our existing API is a string #else // FIXME: the spec says this should be a long, not an unsigned long attribute unsigned long size; // Changed string -> long as part of DOM level 2 #endif attribute [ConvertNullToNullString] DOMString src; - attribute [ConvertNullToNullString] DOMString type; // readonly dropped as part of DOM level 2 + attribute [ConvertNullToNullString, JSCCustomGetter] DOMString type; // readonly dropped as part of DOM level 2 attribute [ConvertNullToNullString] DOMString useMap; attribute [ConvertNullToNullString] DOMString value; readonly attribute boolean willValidate; diff --git a/WebCore/html/HTMLIsIndexElement.cpp b/WebCore/html/HTMLIsIndexElement.cpp index 7bc98b6..bcfa623 100644 --- a/WebCore/html/HTMLIsIndexElement.cpp +++ b/WebCore/html/HTMLIsIndexElement.cpp @@ -24,7 +24,9 @@ #include "config.h" #include "HTMLIsIndexElement.h" + #include "HTMLNames.h" +#include "MappedAttribute.h" namespace WebCore { @@ -41,6 +43,8 @@ void HTMLIsIndexElement::parseMappedAttribute(MappedAttribute* attr) { if (attr->name() == promptAttr) setValue(attr->value()); + else if (attr->name() == placeholderAttr) + updatePlaceholderVisibility(); else // don't call HTMLInputElement::parseMappedAttribute here, as it would // accept attributes this element does not support diff --git a/WebCore/html/HTMLKeygenElement.cpp b/WebCore/html/HTMLKeygenElement.cpp index 563ad3c..b1b6238 100644 --- a/WebCore/html/HTMLKeygenElement.cpp +++ b/WebCore/html/HTMLKeygenElement.cpp @@ -29,6 +29,7 @@ #include "FormDataList.h" #include "HTMLNames.h" #include "HTMLOptionElement.h" +#include "MappedAttribute.h" #include "SSLKeyGenerator.h" #include "Text.h" #include <wtf/StdLibExtras.h> @@ -54,7 +55,7 @@ HTMLKeygenElement::HTMLKeygenElement(const QualifiedName& tagName, Document* doc } } -const AtomicString& HTMLKeygenElement::type() const +const AtomicString& HTMLKeygenElement::formControlType() const { DEFINE_STATIC_LOCAL(const AtomicString, keygen, ("keygen")); return keygen; diff --git a/WebCore/html/HTMLKeygenElement.h b/WebCore/html/HTMLKeygenElement.h index 7997635..b2a0c26 100644 --- a/WebCore/html/HTMLKeygenElement.h +++ b/WebCore/html/HTMLKeygenElement.h @@ -33,7 +33,7 @@ public: HTMLKeygenElement(const QualifiedName&, Document*, HTMLFormElement* = 0); virtual int tagPriority() const { return 0; } - virtual const AtomicString& type() const; + virtual const AtomicString& formControlType() const; virtual bool isEnumeratable() const { return false; } virtual void parseMappedAttribute(MappedAttribute*); virtual bool appendFormData(FormDataList&, bool); diff --git a/WebCore/html/HTMLLIElement.cpp b/WebCore/html/HTMLLIElement.cpp index 2d5518e..044b93c 100644 --- a/WebCore/html/HTMLLIElement.cpp +++ b/WebCore/html/HTMLLIElement.cpp @@ -26,6 +26,7 @@ #include "CSSPropertyNames.h" #include "CSSValueKeywords.h" #include "HTMLNames.h" +#include "MappedAttribute.h" #include "RenderListItem.h" namespace WebCore { diff --git a/WebCore/html/HTMLLegendElement.cpp b/WebCore/html/HTMLLegendElement.cpp index 4092643..d6e08c7 100644 --- a/WebCore/html/HTMLLegendElement.cpp +++ b/WebCore/html/HTMLLegendElement.cpp @@ -47,7 +47,7 @@ bool HTMLLegendElement::isFocusable() const return HTMLElement::isFocusable(); } -const AtomicString& HTMLLegendElement::type() const +const AtomicString& HTMLLegendElement::formControlType() const { DEFINE_STATIC_LOCAL(const AtomicString, legend, ("legend")); return legend; diff --git a/WebCore/html/HTMLLegendElement.h b/WebCore/html/HTMLLegendElement.h index 6d01dce..713d73c 100644 --- a/WebCore/html/HTMLLegendElement.h +++ b/WebCore/html/HTMLLegendElement.h @@ -34,7 +34,7 @@ public: virtual ~HTMLLegendElement(); virtual bool isFocusable() const; - virtual const AtomicString& type() const; + virtual const AtomicString& formControlType() const; virtual void accessKeyAction(bool sendToAnyElement); /** diff --git a/WebCore/html/HTMLLinkElement.cpp b/WebCore/html/HTMLLinkElement.cpp index 28bf2fa..76a9703 100644 --- a/WebCore/html/HTMLLinkElement.cpp +++ b/WebCore/html/HTMLLinkElement.cpp @@ -3,6 +3,7 @@ * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Rob Buis (rwlbuis@gmail.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -33,6 +34,7 @@ #include "FrameLoaderClient.h" #include "FrameTree.h" #include "HTMLNames.h" +#include "MappedAttribute.h" #include "MediaList.h" #include "MediaQueryEvaluator.h" #include "Page.h" @@ -182,37 +184,28 @@ void HTMLLinkElement::process() // Stylesheet // This was buggy and would incorrectly match <link rel="alternate">, which has a different specified meaning. -dwh if (m_disabledState != 2 && m_isStyleSheet && document()->frame() && m_url.isValid()) { - // no need to load style sheets which aren't for the screen output - // ### there may be in some situations e.g. for an editor or script to manipulate // also, don't load style sheets for standalone documents - MediaQueryEvaluator allEval(true); - MediaQueryEvaluator screenEval("screen", true); - MediaQueryEvaluator printEval("print", true); - RefPtr<MediaList> media = MediaList::createAllowingDescriptionSyntax(m_media); - if (allEval.eval(media.get()) || screenEval.eval(media.get()) || printEval.eval(media.get())) { - - // Add ourselves as a pending sheet, but only if we aren't an alternate - // stylesheet. Alternate stylesheets don't hold up render tree construction. - if (!isAlternate()) - document()->addPendingSheet(); + // Add ourselves as a pending sheet, but only if we aren't an alternate + // stylesheet. Alternate stylesheets don't hold up render tree construction. + if (!isAlternate()) + document()->addPendingSheet(); + + String charset = getAttribute(charsetAttr); + if (charset.isEmpty() && document()->frame()) + charset = document()->frame()->loader()->encoding(); - String chset = getAttribute(charsetAttr); - if (chset.isEmpty() && document()->frame()) - chset = document()->frame()->loader()->encoding(); - - if (m_cachedSheet) { - if (m_loading) - document()->removePendingSheet(); - m_cachedSheet->removeClient(this); - } - m_loading = true; - m_cachedSheet = document()->docLoader()->requestCSSStyleSheet(m_url.string(), chset); - if (m_cachedSheet) - m_cachedSheet->addClient(this); - else if (!isAlternate()) { // request may have been denied if stylesheet is local and document is remote. - m_loading = false; + if (m_cachedSheet) { + if (m_loading) document()->removePendingSheet(); - } + m_cachedSheet->removeClient(this); + } + m_loading = true; + m_cachedSheet = document()->docLoader()->requestCSSStyleSheet(m_url, charset); + if (m_cachedSheet) + m_cachedSheet->addClient(this); + else if (!isAlternate()) { // The request may have been denied if stylesheet is local and document is remote. + m_loading = false; + document()->removePendingSheet(); } } else if (m_sheet) { // we no longer contain a stylesheet, e.g. perhaps rel or type was changed diff --git a/WebCore/html/HTMLLinkElement.idl b/WebCore/html/HTMLLinkElement.idl index 532ac31..98de809 100644 --- a/WebCore/html/HTMLLinkElement.idl +++ b/WebCore/html/HTMLLinkElement.idl @@ -35,12 +35,12 @@ module html { attribute [ConvertNullToNullString] DOMString target; attribute [ConvertNullToNullString] DOMString type; -#if !defined(LANGUAGE_COM) +#if !defined(LANGUAGE_COM) || !LANGUAGE_COM // DOM Level 2 Style readonly attribute StyleSheet sheet; #endif -#if defined(LANGUAGE_OBJECTIVE_C) +#if defined(LANGUAGE_OBJECTIVE_C) && LANGUAGE_OBJECTIVE_C // Objective-C extension: readonly attribute URL absoluteLinkURL; #endif diff --git a/WebCore/html/HTMLMapElement.cpp b/WebCore/html/HTMLMapElement.cpp index d7109c9..90204e0 100644 --- a/WebCore/html/HTMLMapElement.cpp +++ b/WebCore/html/HTMLMapElement.cpp @@ -18,6 +18,7 @@ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ + #include "config.h" #include "HTMLMapElement.h" @@ -25,8 +26,9 @@ #include "HTMLAreaElement.h" #include "HTMLCollection.h" #include "HTMLNames.h" -#include "IntSize.h" #include "HitTestResult.h" +#include "IntSize.h" +#include "MappedAttribute.h" using namespace std; @@ -96,7 +98,7 @@ void HTMLMapElement::parseMappedAttribute(MappedAttribute* attr) PassRefPtr<HTMLCollection> HTMLMapElement::areas() { - return HTMLCollection::create(this, HTMLCollection::MapAreas); + return HTMLCollection::create(this, MapAreas); } String HTMLMapElement::name() const diff --git a/WebCore/html/HTMLMarqueeElement.cpp b/WebCore/html/HTMLMarqueeElement.cpp index 040b6fb..d62eaab 100644 --- a/WebCore/html/HTMLMarqueeElement.cpp +++ b/WebCore/html/HTMLMarqueeElement.cpp @@ -19,12 +19,14 @@ * Boston, MA 02110-1301, USA. * */ + #include "config.h" #include "HTMLMarqueeElement.h" #include "CSSPropertyNames.h" #include "CSSValueKeywords.h" #include "HTMLNames.h" +#include "MappedAttribute.h" #include "RenderLayer.h" #include "RenderMarquee.h" @@ -37,6 +39,7 @@ const int defaultMinimumDelay = 60; HTMLMarqueeElement::HTMLMarqueeElement(const QualifiedName& tagName, Document* doc) : HTMLElement(tagName, doc) + , ActiveDOMObject(doc, this) , m_minimumDelay(defaultMinimumDelay) { ASSERT(hasTagName(marqueeTag)); @@ -119,4 +122,21 @@ void HTMLMarqueeElement::stop() renderBox()->layer()->marquee()->stop(); } +bool HTMLMarqueeElement::canSuspend() const +{ + return true; +} + +void HTMLMarqueeElement::suspend() +{ + if (renderer() && renderer()->hasLayer() && renderBox()->layer()->marquee()) + renderBox()->layer()->marquee()->suspend(); +} + +void HTMLMarqueeElement::resume() +{ + if (renderer() && renderer()->hasLayer() && renderBox()->layer()->marquee()) + renderBox()->layer()->marquee()->updateMarqueePosition(); +} + } // namespace WebCore diff --git a/WebCore/html/HTMLMarqueeElement.h b/WebCore/html/HTMLMarqueeElement.h index acd639b..2423fc6 100644 --- a/WebCore/html/HTMLMarqueeElement.h +++ b/WebCore/html/HTMLMarqueeElement.h @@ -23,11 +23,12 @@ #ifndef HTMLMarqueeElement_h #define HTMLMarqueeElement_h +#include "ActiveDOMObject.h" #include "HTMLElement.h" namespace WebCore { -class HTMLMarqueeElement : public HTMLElement { +class HTMLMarqueeElement : public HTMLElement, private ActiveDOMObject { public: HTMLMarqueeElement(const QualifiedName&, Document*); @@ -45,6 +46,11 @@ public: void stop(); private: + // ActiveDOMObject + virtual bool canSuspend() const; + virtual void suspend(); + virtual void resume(); + int m_minimumDelay; }; diff --git a/WebCore/html/HTMLMediaElement.cpp b/WebCore/html/HTMLMediaElement.cpp index df0ed04..6ad0653 100644 --- a/WebCore/html/HTMLMediaElement.cpp +++ b/WebCore/html/HTMLMediaElement.cpp @@ -28,10 +28,11 @@ #if ENABLE(VIDEO) #include "HTMLMediaElement.h" -#include "ContentType.h" #include "CSSHelper.h" #include "CSSPropertyNames.h" #include "CSSValueKeywords.h" +#include "ContentType.h" +#include "DocLoader.h" #include "Event.h" #include "EventNames.h" #include "ExceptionCode.h" @@ -41,25 +42,25 @@ #include "HTMLNames.h" #include "HTMLSourceElement.h" #include "HTMLVideoElement.h" -#include <limits> +#include "MIMETypeRegistry.h" +#include "MappedAttribute.h" +#include "MediaDocument.h" #include "MediaError.h" #include "MediaList.h" -#include "MediaQueryEvaluator.h" -#include "MIMETypeRegistry.h" #include "MediaPlayer.h" +#include "MediaQueryEvaluator.h" #include "Page.h" #include "ProgressEvent.h" #include "RenderVideo.h" -#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) -#include "RenderPartObject.h" -#endif #include "TimeRanges.h" +#include <limits> +#include <wtf/CurrentTime.h> +#include <wtf/MathExtras.h> + #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) +#include "RenderPartObject.h" #include "Widget.h" #endif -#include <wtf/CurrentTime.h> -#include <wtf/MathExtras.h> -#include <limits> using namespace std; @@ -73,12 +74,13 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* doc) , m_asyncEventTimer(this, &HTMLMediaElement::asyncEventTimerFired) , m_progressEventTimer(this, &HTMLMediaElement::progressEventTimerFired) , m_playbackProgressTimer(this, &HTMLMediaElement::playbackProgressTimerFired) + , m_playedTimeRanges() , m_playbackRate(1.0f) , m_defaultPlaybackRate(1.0f) , m_networkState(NETWORK_EMPTY) , m_readyState(HAVE_NOTHING) , m_volume(1.0f) - , m_currentTimeDuringSeek(0) + , m_lastSeekTime(0) , m_previousProgress(0) , m_previousProgressTime(numeric_limits<double>::max()) , m_lastTimeUpdateEventWallTime(0) @@ -87,6 +89,7 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* doc) , m_currentSourceNode(0) , m_player(0) , m_restrictions(NoRestrictions) + , m_playing(false) , m_processingMediaPlayerCallback(0) , m_processingLoad(false) , m_delayingTheLoadEvent(false) @@ -140,7 +143,16 @@ void HTMLMediaElement::attributeChanged(Attribute* attr, bool preserveDecls) } #endif } - + +void HTMLMediaElement::parseMappedAttribute(MappedAttribute *attr) +{ + if (attr->name() == autobufferAttr) { + if (m_player) + m_player->setAutobuffer(!attr->isNull()); + } else + HTMLElement::parseMappedAttribute(attr); +} + bool HTMLMediaElement::rendererIsNeeded(RenderStyle* style) { #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) @@ -231,7 +243,7 @@ void HTMLMediaElement::scheduleEvent(const AtomicString& eventName) void HTMLMediaElement::enqueueEvent(RefPtr<Event> event) { m_pendingEvents.append(event); - if (!m_asyncEventTimer.isActive()) + if (!m_asyncEventTimer.isActive()) m_asyncEventTimer.startOneShot(0); } @@ -362,7 +374,7 @@ void HTMLMediaElement::loadInternal() // 3 - If there are any tasks from the media element's media element event task source in // one of the task queues, then remove those tasks. - m_pendingEvents.clear(); + cancelPendingEventsAndCallbacks(); // 4 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, set the // error attribute to a new MediaError object whose code attribute is set to MEDIA_ERR_ABORTED, @@ -380,6 +392,8 @@ void HTMLMediaElement::loadInternal() // 5 m_error = 0; m_autoplaying = true; + m_playedTimeRanges = TimeRanges::create(); + m_lastSeekTime = 0; // 6 setPlaybackRate(defaultPlaybackRate()); @@ -392,9 +406,10 @@ void HTMLMediaElement::loadInternal() m_seeking = false; if (m_player) { m_player->pause(); + m_playing = false; m_player->seek(0); } - dispatchEventForType(eventNames().emptiedEvent, false, true); + dispatchEvent(eventNames().emptiedEvent, false, true); } selectMediaResource(); @@ -430,9 +445,13 @@ void HTMLMediaElement::selectMediaResource() // 5 - If the media element has a src attribute, then run these substeps ContentType contentType(""); if (!mediaSrc.isEmpty()) { - mediaSrc = document()->completeURL(mediaSrc).string(); - m_loadState = LoadingFromSrcAttr; - loadResource(mediaSrc, contentType); + KURL mediaURL = document()->completeURL(mediaSrc); + if (isSafeToLoadURL(mediaURL, Complain)) { + m_loadState = LoadingFromSrcAttr; + loadResource(mediaURL, contentType); + } else + noneSupported(); + return; } @@ -444,22 +463,23 @@ void HTMLMediaElement::selectMediaResource() void HTMLMediaElement::loadNextSourceChild() { ContentType contentType(""); - String mediaSrc; - - mediaSrc = nextSourceChild(&contentType); - if (mediaSrc.isEmpty()) { - noneSupported(); + KURL mediaURL = selectNextSourceChild(&contentType, Complain); + if (!mediaURL.isValid()) { + // It seems wrong to fail silently when we give up because no suitable <source> + // element can be found and set the error attribute if the element's 'src' attribute + // fails, but that is what the spec says. return; } m_loadState = LoadingFromSourceElement; - loadResource(mediaSrc, contentType); + loadResource(mediaURL, contentType); } -void HTMLMediaElement::loadResource(String url, ContentType& contentType) +void HTMLMediaElement::loadResource(const KURL& url, ContentType& contentType) { - // The resource fetch algorithm + ASSERT(isSafeToLoadURL(url, Complain)); + // The resource fetch algorithm m_networkState = NETWORK_LOADING; m_currentSrc = url; @@ -483,6 +503,21 @@ void HTMLMediaElement::loadResource(String url, ContentType& contentType) renderer()->updateFromElement(); } +bool HTMLMediaElement::isSafeToLoadURL(const KURL& url, InvalidSourceAction actionIfInvalid) +{ + Frame* frame = document()->frame(); + FrameLoader* loader = frame ? frame->loader() : 0; + + // don't allow remote to local urls + if (!loader || !loader->canLoad(url, String(), document())) { + if (actionIfInvalid == Complain) + FrameLoader::reportLocalLoadFailed(frame, url.string()); + return false; + } + + return true; +} + void HTMLMediaElement::startProgressEventTimer() { if (m_progressEventTimer.isActive()) @@ -502,8 +537,8 @@ void HTMLMediaElement::noneSupported() // 3 - Reaching this step indicates that either the URL failed to resolve, or the media // resource failed to load. Set the error attribute to a new MediaError object whose - // code attribute is set to MEDIA_ERR_NONE_SUPPORTED. - m_error = MediaError::create(MediaError::MEDIA_ERR_NONE_SUPPORTED); + // code attribute is set to MEDIA_ERR_SRC_NOT_SUPPORTED. + m_error = MediaError::create(MediaError::MEDIA_ERR_SRC_NOT_SUPPORTED); // 4- Set the element's networkState attribute to the NETWORK_NO_SOURCE value. m_networkState = NETWORK_NO_SOURCE; @@ -548,6 +583,16 @@ void HTMLMediaElement::mediaEngineError(PassRefPtr<MediaError> err) } +void HTMLMediaElement::cancelPendingEventsAndCallbacks() +{ + m_pendingEvents.clear(); + + for (Node* node = firstChild(); node; node = node->nextSibling()) { + if (node->hasTagName(sourceTag)) + static_cast<HTMLSourceElement*>(node)->cancelPendingErrorEvent(); + } +} + void HTMLMediaElement::mediaPlayerNetworkStateChanged(MediaPlayer*) { beginProcessingMediaPlayerCallback(); @@ -567,9 +612,11 @@ void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state) stopPeriodicTimers(); // If we failed while trying to load a <source> element, the movie was never parsed, and there are more - // <source> children, schedule the next one without reporting an error - if (m_readyState < HAVE_METADATA && m_loadState == LoadingFromSourceElement && havePotentialSourceChild()) { - scheduleLoad(); + // <source> children, schedule the next one + if (m_readyState < HAVE_METADATA && m_loadState == LoadingFromSourceElement) { + m_currentSourceNode->scheduleErrorEvent(); + if (havePotentialSourceChild()) + scheduleLoad(); return; } @@ -577,7 +624,7 @@ void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state) mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_NETWORK)); else if (state == MediaPlayer::DecodeError) mediaEngineError(MediaError::create(MediaError::MEDIA_ERR_DECODE)); - else if (state == MediaPlayer::FormatError) + else if (state == MediaPlayer::FormatError && m_loadState == LoadingFromSrcAttr) noneSupported(); if (isVideo()) @@ -586,31 +633,37 @@ void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state) return; } - if (state == MediaPlayer::Idle && m_networkState > NETWORK_IDLE) { + if (state == MediaPlayer::Idle) { ASSERT(static_cast<ReadyState>(m_player->readyState()) < HAVE_ENOUGH_DATA); + if (m_networkState > NETWORK_IDLE) { + stopPeriodicTimers(); + scheduleProgressEvent(eventNames().suspendEvent); + } m_networkState = NETWORK_IDLE; - stopPeriodicTimers(); - scheduleProgressEvent(eventNames().suspendEvent); } - if (state == MediaPlayer::Loading && (m_networkState < NETWORK_LOADING || m_networkState == NETWORK_NO_SOURCE)) { - ASSERT(static_cast<ReadyState>(m_player->readyState()) < HAVE_ENOUGH_DATA); + if (state == MediaPlayer::Loading) { + if (m_networkState < NETWORK_LOADING || m_networkState == NETWORK_NO_SOURCE) + startProgressEventTimer(); m_networkState = NETWORK_LOADING; - startProgressEventTimer(); } - if (state == MediaPlayer::Loaded && (m_networkState < NETWORK_LOADED || m_networkState == NETWORK_NO_SOURCE)) { + if (state == MediaPlayer::Loaded) { + NetworkState oldState = m_networkState; + m_networkState = NETWORK_LOADED; - m_progressEventTimer.stop(); + if (oldState < NETWORK_LOADED || oldState == NETWORK_NO_SOURCE) { + m_progressEventTimer.stop(); - // Check to see if readyState changes need to be dealt with before sending the - // 'load' event so we report 'canplaythrough' first. This is necessary because a - // media engine reports readyState and networkState changes separately - MediaPlayer::ReadyState currentState = m_player->readyState(); - if (static_cast<ReadyState>(currentState) != m_readyState) - setReadyState(currentState); + // Check to see if readyState changes need to be dealt with before sending the + // 'load' event so we report 'canplaythrough' first. This is necessary because a + // media engine reports readyState and networkState changes separately + MediaPlayer::ReadyState currentState = m_player->readyState(); + if (static_cast<ReadyState>(currentState) != m_readyState) + setReadyState(currentState); - scheduleProgressEvent(eventNames().loadEvent); + scheduleProgressEvent(eventNames().loadEvent); + } } } @@ -676,11 +729,6 @@ void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state) } bool isPotentiallyPlaying = potentiallyPlaying(); - if (m_readyState <= HAVE_CURRENT_DATA && oldState >= HAVE_FUTURE_DATA) { - if (isPotentiallyPlaying) - scheduleEvent(eventNames().waitingEvent); - } - if (m_readyState == HAVE_FUTURE_DATA && oldState <= HAVE_CURRENT_DATA) { scheduleEvent(eventNames().canplayEvent); if (isPotentiallyPlaying) @@ -763,7 +811,11 @@ void HTMLMediaElement::seek(float time, ExceptionCode& ec) return; // 5 - m_currentTimeDuringSeek = time; + if (m_playing) { + if (m_lastSeekTime < now) + m_playedTimeRanges->add(m_lastSeekTime, now); + } + m_lastSeekTime = time; // 6 - set the seeking flag, it will be cleared when the engine tells is the time has actually changed m_seeking = true; @@ -794,7 +846,7 @@ float HTMLMediaElement::currentTime() const if (!m_player) return 0; if (m_seeking) - return m_currentTimeDuringSeek; + return m_lastSeekTime; return m_player->currentTime(); } @@ -803,6 +855,13 @@ void HTMLMediaElement::setCurrentTime(float time, ExceptionCode& ec) seek(time, ec); } +float HTMLMediaElement::startTime() const +{ + if (!m_player) + return 0; + return m_player->startTime(); +} + float HTMLMediaElement::duration() const { if (m_readyState >= HAVE_METADATA) @@ -859,6 +918,16 @@ void HTMLMediaElement::setAutoplay(bool b) setBooleanAttribute(autoplayAttr, b); } +bool HTMLMediaElement::autobuffer() const +{ + return hasAttribute(autobufferAttr); +} + +void HTMLMediaElement::setAutobuffer(bool b) +{ + setBooleanAttribute(autobufferAttr, b); +} + void HTMLMediaElement::play() { if (m_restrictions & RequireUserGestureForRateChangeRestriction && !processingUserGesture()) @@ -1065,55 +1134,65 @@ bool HTMLMediaElement::havePotentialSourceChild() { // Stash the current <source> node so we can restore it after checking // to see there is another potential - Node* currentSourceNode = m_currentSourceNode; - String nextUrl = nextSourceChild(); + HTMLSourceElement* currentSourceNode = m_currentSourceNode; + KURL nextURL = selectNextSourceChild(0, DoNothing); m_currentSourceNode = currentSourceNode; - return !nextUrl.isEmpty(); + return nextURL.isValid(); } -String HTMLMediaElement::nextSourceChild(ContentType *contentType) +KURL HTMLMediaElement::selectNextSourceChild(ContentType *contentType, InvalidSourceAction actionIfInvalid) { - String mediaSrc; + KURL mediaURL; + Node* node; bool lookingForPreviousNode = m_currentSourceNode; + bool canUse = false; - for (Node* node = firstChild(); node; node = node->nextSibling()) { + for (node = firstChild(); !canUse && node; node = node->nextSibling()) { if (!node->hasTagName(sourceTag)) continue; if (lookingForPreviousNode) { - if (m_currentSourceNode == node) + if (m_currentSourceNode == static_cast<HTMLSourceElement*>(node)) lookingForPreviousNode = false; continue; } - + HTMLSourceElement* source = static_cast<HTMLSourceElement*>(node); if (!source->hasAttribute(srcAttr)) - continue; + goto check_again; + if (source->hasAttribute(mediaAttr)) { MediaQueryEvaluator screenEval("screen", document()->frame(), renderer() ? renderer()->style() : 0); RefPtr<MediaList> media = MediaList::createAllowingDescriptionSyntax(source->media()); - if (!screenEval.eval(media.get())) - continue; + if (!screenEval.eval(media.get())) + goto check_again; } - if (source->hasAttribute(typeAttr)) { - ContentType type(source->type()); - if (!MediaPlayer::supportsType(type)) - continue; - // return type with all parameters in place so the media engine can use them - if (contentType) - *contentType = type; + if (source->hasAttribute(typeAttr)) { + if (!MediaPlayer::supportsType(ContentType(source->type()))) + goto check_again; } - mediaSrc = source->src().string(); - m_currentSourceNode = node; - break; - } - if (!mediaSrc.isEmpty()) - mediaSrc = document()->completeURL(mediaSrc).string(); + // Is it safe to load this url? + mediaURL = source->src(); + if (!mediaURL.isValid() || !isSafeToLoadURL(mediaURL, actionIfInvalid)) + goto check_again; + + // Making it this far means the <source> looks reasonable + canUse = true; + if (contentType) + *contentType = ContentType(source->type()); + +check_again: + if (!canUse && actionIfInvalid == Complain) + source->scheduleErrorEvent(); + m_currentSourceNode = static_cast<HTMLSourceElement*>(node); + } - return mediaSrc; + if (!canUse) + m_currentSourceNode = 0; + return canUse ? mediaURL : KURL(); } void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*) @@ -1127,7 +1206,7 @@ void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*) float now = currentTime(); float dur = duration(); - if (now >= dur) { + if (!isnan(dur) && dur && now >= dur) { if (loop()) { ExceptionCode ignoredException; m_sentEndEvent = false; @@ -1195,6 +1274,17 @@ void HTMLMediaElement::mediaPlayerSizeChanged(MediaPlayer*) endProcessingMediaPlayerCallback(); } +void HTMLMediaElement::mediaPlayerSawUnsupportedTracks(MediaPlayer*) +{ + // The MediaPlayer came across content it cannot completely handle. + // This is normally acceptable except when we are in a standalone + // MediaDocument. If so, tell the document what has happened. + if (ownerDocument()->isMediaDocument()) { + MediaDocument* mediaDocument = static_cast<MediaDocument*>(ownerDocument()); + mediaDocument->mediaElementSawUnsupportedTracks(); + } +} + PassRefPtr<TimeRanges> HTMLMediaElement::buffered() const { // FIXME real ranges support @@ -1205,8 +1295,16 @@ PassRefPtr<TimeRanges> HTMLMediaElement::buffered() const PassRefPtr<TimeRanges> HTMLMediaElement::played() const { - // FIXME track played - return TimeRanges::create(); + if (!m_playedTimeRanges) { + // We are not yet loaded + return TimeRanges::create(); + } + if (m_playing) { + float time = currentTime(); + if (m_lastSeekTime < time) + m_playedTimeRanges->add(m_lastSeekTime, time); + } + return m_playedTimeRanges->copy(); } PassRefPtr<TimeRanges> HTMLMediaElement::seekable() const @@ -1224,7 +1322,11 @@ bool HTMLMediaElement::potentiallyPlaying() const bool HTMLMediaElement::endedPlayback() const { - return m_player && m_readyState >= HAVE_METADATA && currentTime() >= duration() && !loop(); + if (!m_player || m_readyState < HAVE_METADATA) + return false; + + float dur = duration(); + return !isnan(dur) && currentTime() >= dur && !loop(); } bool HTMLMediaElement::stoppedDueToErrors() const @@ -1281,9 +1383,14 @@ void HTMLMediaElement::updatePlayState() m_player->setRate(m_playbackRate); m_player->play(); startPlaybackProgressTimer(); + m_playing = true; } else if (!shouldBePlaying && !playerPaused) { m_player->pause(); m_playbackProgressTimer.stop(); + m_playing = false; + float time = currentTime(); + if (m_lastSeekTime < time) + m_playedTimeRanges->add(m_lastSeekTime, time); } if (renderer()) @@ -1419,15 +1526,12 @@ void HTMLMediaElement::setMediaPlayerProxy(WebMediaPlayerProxy* proxy) String HTMLMediaElement::initialURL() { - String initialSrc = mediaSrc = getAttribute(srcAttr); + KURL initialSrc = document()->completeURL(getAttribute(srcAttr)); - if (initialSrc.isEmpty()) - initialSrc = nextSourceChild(); - - if (!initialSrc.isEmpty()) - initialSrc = document()->completeURL(initialSrc).string(); + if (!initialSrc.isValid()) + initialSrc = selectNextSourceChild(0, DoNothing).string(); - m_currentSrc = initialSrc; + m_currentSrc = initialSrc.string(); return initialSrc; } @@ -1438,7 +1542,7 @@ void HTMLMediaElement::finishParsingChildren() if (!m_player) m_player.set(new MediaPlayer(this)); - document()->updateRendering(); + document()->updateStyleIfNeeded(); if (m_needWidgetUpdate && renderer()) static_cast<RenderPartObject*>(renderer())->updateWidget(true); } diff --git a/WebCore/html/HTMLMediaElement.h b/WebCore/html/HTMLMediaElement.h index ab0ab11..65c542b 100644 --- a/WebCore/html/HTMLMediaElement.h +++ b/WebCore/html/HTMLMediaElement.h @@ -39,6 +39,7 @@ namespace WebCore { class Event; +class HTMLSourceElement; class MediaError; class KURL; class TimeRanges; @@ -51,6 +52,7 @@ public: bool checkDTD(const Node* newChild); void attributeChanged(Attribute*, bool preserveDecls); + void parseMappedAttribute(MappedAttribute *); virtual bool rendererIsNeeded(RenderStyle*); virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); @@ -84,9 +86,11 @@ public: enum NetworkState { NETWORK_EMPTY, NETWORK_IDLE, NETWORK_LOADING, NETWORK_LOADED, NETWORK_NO_SOURCE }; NetworkState networkState() const; + bool autobuffer() const; + void setAutobuffer(bool); + PassRefPtr<TimeRanges> buffered() const; void load(ExceptionCode&); - String canPlayType(const String& mimeType) const; // ready state @@ -97,6 +101,7 @@ public: // playback state float currentTime() const; void setCurrentTime(float, ExceptionCode&); + float startTime() const; float duration() const; bool paused() const; float defaultPlaybackRate() const; @@ -154,6 +159,7 @@ private: // MediaPlayerObserver virtual void mediaPlayerDurationChanged(MediaPlayer*); virtual void mediaPlayerRateChanged(MediaPlayer*); virtual void mediaPlayerSizeChanged(MediaPlayer*); + virtual void mediaPlayerSawUnsupportedTracks(MediaPlayer*); private: void loadTimerFired(Timer<HTMLMediaElement>*); @@ -174,13 +180,17 @@ private: // loading void selectMediaResource(); - void loadResource(String url, ContentType& contentType); + void loadResource(const KURL&, ContentType&); void loadNextSourceChild(); void userCancelledLoad(); - String nextSourceChild(ContentType* contentType = 0); bool havePotentialSourceChild(); void noneSupported(); void mediaEngineError(PassRefPtr<MediaError> err); + void cancelPendingEventsAndCallbacks(); + + enum InvalidSourceAction { DoNothing, Complain }; + bool isSafeToLoadURL(const KURL&, InvalidSourceAction); + KURL selectNextSourceChild(ContentType*, InvalidSourceAction); // These "internal" functions do not check user gesture restrictions. void loadInternal(); @@ -214,6 +224,7 @@ protected: Timer<HTMLMediaElement> m_progressEventTimer; Timer<HTMLMediaElement> m_playbackProgressTimer; Vector<RefPtr<Event> > m_pendingEvents; + RefPtr<TimeRanges> m_playedTimeRanges; float m_playbackRate; float m_defaultPlaybackRate; @@ -224,7 +235,7 @@ protected: RefPtr<MediaError> m_error; float m_volume; - float m_currentTimeDuringSeek; + float m_lastSeekTime; unsigned m_previousProgress; double m_previousProgressTime; @@ -238,12 +249,14 @@ protected: // loading state enum LoadState { WaitingForSource, LoadingFromSrcAttr, LoadingFromSourceElement }; LoadState m_loadState; - Node *m_currentSourceNode; + HTMLSourceElement *m_currentSourceNode; OwnPtr<MediaPlayer> m_player; BehaviorRestrictions m_restrictions; + bool m_playing; + // counter incremented while processing a callback from the media player, so we can avoid // calling the media engine recursively int m_processingMediaPlayerCallback; diff --git a/WebCore/html/HTMLMediaElement.idl b/WebCore/html/HTMLMediaElement.idl index 931980b..008e059 100644 --- a/WebCore/html/HTMLMediaElement.idl +++ b/WebCore/html/HTMLMediaElement.idl @@ -39,6 +39,7 @@ interface [GenerateConstructor, Conditional=VIDEO] HTMLMediaElement : HTMLElemen const unsigned short NETWORK_LOADED = 3; const unsigned short NETWORK_NO_SOURCE = 4; readonly attribute unsigned short networkState; + attribute boolean autobuffer; readonly attribute TimeRanges buffered; void load() @@ -57,6 +58,7 @@ interface [GenerateConstructor, Conditional=VIDEO] HTMLMediaElement : HTMLElemen // playback state attribute float currentTime setter raises (DOMException); + readonly attribute float startTime; readonly attribute float duration; readonly attribute boolean paused; attribute float defaultPlaybackRate; diff --git a/WebCore/html/HTMLMetaElement.cpp b/WebCore/html/HTMLMetaElement.cpp index 0a07651..48284e3 100644 --- a/WebCore/html/HTMLMetaElement.cpp +++ b/WebCore/html/HTMLMetaElement.cpp @@ -19,11 +19,13 @@ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ + #include "config.h" #include "HTMLMetaElement.h" #include "Document.h" #include "HTMLNames.h" +#include "MappedAttribute.h" namespace WebCore { diff --git a/WebCore/html/HTMLNameCollection.cpp b/WebCore/html/HTMLNameCollection.cpp index fdebe78..d5657da 100644 --- a/WebCore/html/HTMLNameCollection.cpp +++ b/WebCore/html/HTMLNameCollection.cpp @@ -32,7 +32,7 @@ namespace WebCore { using namespace HTMLNames; -HTMLNameCollection::HTMLNameCollection(PassRefPtr<Document> document, Type type, const String& name) +HTMLNameCollection::HTMLNameCollection(PassRefPtr<Document> document, CollectionType type, const String& name) : HTMLCollection(document.get(), type, document->nameCollectionInfo(type, name)) , m_name(name) { diff --git a/WebCore/html/HTMLNameCollection.h b/WebCore/html/HTMLNameCollection.h index 9add926..3e990d7 100644 --- a/WebCore/html/HTMLNameCollection.h +++ b/WebCore/html/HTMLNameCollection.h @@ -32,13 +32,13 @@ class Document; class HTMLNameCollection : public HTMLCollection { public: - static PassRefPtr<HTMLNameCollection> create(PassRefPtr<Document> document, Type type, const String& name) + static PassRefPtr<HTMLNameCollection> create(PassRefPtr<Document> document, CollectionType type, const String& name) { return adoptRef(new HTMLNameCollection(document, type, name)); } private: - HTMLNameCollection(PassRefPtr<Document>, Type, const String& name); + HTMLNameCollection(PassRefPtr<Document>, CollectionType, const String& name); virtual Element* itemAfter(Element*) const; diff --git a/WebCore/html/HTMLNoScriptElement.cpp b/WebCore/html/HTMLNoScriptElement.cpp new file mode 100644 index 0000000..3bbfbe6 --- /dev/null +++ b/WebCore/html/HTMLNoScriptElement.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(XHTMLMP) +#include "HTMLNoScriptElement.h" + +#include "CSSStyleSelector.h" +#include "HTMLNames.h" +#include "RenderObject.h" + +namespace WebCore { + +using namespace HTMLNames; + +HTMLNoScriptElement::HTMLNoScriptElement(const QualifiedName& tagName, Document* doc) + : HTMLElement(tagName, doc) +{ + ASSERT(hasTagName(noscriptTag)); +} + +HTMLNoScriptElement::~HTMLNoScriptElement() +{ +} + +bool HTMLNoScriptElement::checkDTD(const Node* newChild) +{ + return newChild->isTextNode() || inBlockTagList(newChild); +} + +void HTMLNoScriptElement::attach() +{ + HTMLElement::attach(); + + // If no need to process <noscript>, we hide it by setting display:none temporarily + if (!document()->shouldProcessNoscriptElement()) { + if (renderer() && renderer()->style()) + renderer()->style()->setDisplay(NONE); + setNeedsStyleRecalc(); + } +} + +void HTMLNoScriptElement::recalcStyle(StyleChange change) +{ + if (!document()->shouldProcessNoscriptElement() || !renderer() || !renderer()->style()) + return; + + // If <noscript> needs processing, we make it visiable here, including its visible children + RefPtr<RenderStyle> style = renderer()->style(); + if (style->display() == NONE) { + style->setDisplay(INLINE); + + // Create renderers for its children + if (hasChildNodes()) { + for (Node* n = firstChild(); n; n = n->traverseNextNode(this)) + if (!n->renderer()) + n->createRendererIfNeeded(); + } + } +} + +bool HTMLNoScriptElement::childShouldCreateRenderer(Node* child) const +{ + return document()->shouldProcessNoscriptElement(); +} + +} +#endif diff --git a/WebCore/html/HTMLNoScriptElement.h b/WebCore/html/HTMLNoScriptElement.h new file mode 100644 index 0000000..2cc5a3c --- /dev/null +++ b/WebCore/html/HTMLNoScriptElement.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef HTMLNoScriptElement_h +#define HTMLNoScriptElement_h + +#if ENABLE(XHTMLMP) +#include "HTMLElement.h" + +namespace WebCore { + +class HTMLNoScriptElement : public HTMLElement { +public: + HTMLNoScriptElement(const QualifiedName&, Document*); + +private: + virtual ~HTMLNoScriptElement(); + + virtual bool checkDTD(const Node*); + virtual void attach(); + virtual void recalcStyle(StyleChange); + virtual bool childShouldCreateRenderer(Node*) const; + virtual bool rendererIsNeeded(RenderStyle*) { return true; } +}; + +} //namespace + +#endif +#endif diff --git a/WebCore/html/HTMLOListElement.cpp b/WebCore/html/HTMLOListElement.cpp index c1e0d7c..63fd437 100644 --- a/WebCore/html/HTMLOListElement.cpp +++ b/WebCore/html/HTMLOListElement.cpp @@ -18,12 +18,14 @@ * Boston, MA 02110-1301, USA. * */ + #include "config.h" #include "HTMLOListElement.h" #include "CSSPropertyNames.h" #include "CSSValueKeywords.h" #include "HTMLNames.h" +#include "MappedAttribute.h" #include "RenderListItem.h" namespace WebCore { diff --git a/WebCore/html/HTMLObjectElement.cpp b/WebCore/html/HTMLObjectElement.cpp index a41e037..6be41c9 100644 --- a/WebCore/html/HTMLObjectElement.cpp +++ b/WebCore/html/HTMLObjectElement.cpp @@ -32,14 +32,15 @@ #include "HTMLFormElement.h" #include "HTMLImageLoader.h" #include "HTMLNames.h" +#include "ScriptEventListener.h" #include "MIMETypeRegistry.h" +#include "MappedAttribute.h" #include "RenderImage.h" #include "RenderPartObject.h" #include "RenderWidget.h" #include "ScriptController.h" #include "Text.h" - namespace WebCore { using namespace HTMLNames; @@ -94,7 +95,7 @@ void HTMLObjectElement::parseMappedAttribute(MappedAttribute *attr) if (renderer()) m_needWidgetUpdate = true; } else if (attr->name() == onloadAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().loadEvent, attr); + setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == nameAttr) { const AtomicString& newName = attr->value(); if (isDocNamedItem() && inDocument() && document()->isHTMLDocument()) { @@ -163,7 +164,7 @@ void HTMLObjectElement::attach() void HTMLObjectElement::updateWidget() { - document()->updateRendering(); + document()->updateStyleIfNeeded(); if (m_needWidgetUpdate && renderer() && !m_useFallbackContent && !isImageType()) static_cast<RenderPartObject*>(renderer())->updateWidget(true); } @@ -174,7 +175,7 @@ void HTMLObjectElement::finishParsingChildren() if (!m_useFallbackContent) { m_needWidgetUpdate = true; if (inDocument()) - setChanged(); + setNeedsStyleRecalc(); } } @@ -222,7 +223,7 @@ void HTMLObjectElement::childrenChanged(bool changedByParser, Node* beforeChange updateDocNamedItem(); if (inDocument() && !m_useFallbackContent) { m_needWidgetUpdate = true; - setChanged(); + setNeedsStyleRecalc(); } HTMLPlugInElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); } diff --git a/WebCore/html/HTMLObjectElement.idl b/WebCore/html/HTMLObjectElement.idl index c225238..5d4562c 100644 --- a/WebCore/html/HTMLObjectElement.idl +++ b/WebCore/html/HTMLObjectElement.idl @@ -50,14 +50,16 @@ module html { // Introduced in DOM Level 2: readonly attribute [CheckFrameSecurity] Document contentDocument; -#if !defined(LANGUAGE_COM) -#if ENABLE_SVG +#if !defined(LANGUAGE_COM) || !LANGUAGE_COM +#if defined(ENABLE_SVG) && ENABLE_SVG +#if !defined(LANGUAGE_OBJECTIVE_C) || !LANGUAGE_OBJECTIVE_C || defined(ENABLE_SVG_DOM_OBJC_BINDINGS) && ENABLE_SVG_DOM_OBJC_BINDINGS [SVGCheckSecurityDocument] SVGDocument getSVGDocument() raises(DOMException); #endif #endif +#endif -#if defined(LANGUAGE_OBJECTIVE_C) +#if defined(LANGUAGE_OBJECTIVE_C) && LANGUAGE_OBJECTIVE_C // Objective-C extension: readonly attribute URL absoluteImageURL; #endif diff --git a/WebCore/html/HTMLOptGroupElement.cpp b/WebCore/html/HTMLOptGroupElement.cpp index 5c79e74..af81b07 100644 --- a/WebCore/html/HTMLOptGroupElement.cpp +++ b/WebCore/html/HTMLOptGroupElement.cpp @@ -49,7 +49,7 @@ bool HTMLOptGroupElement::isFocusable() const return HTMLElement::isFocusable(); } -const AtomicString& HTMLOptGroupElement::type() const +const AtomicString& HTMLOptGroupElement::formControlType() const { DEFINE_STATIC_LOCAL(const AtomicString, optgroup, ("optgroup")); return optgroup; diff --git a/WebCore/html/HTMLOptGroupElement.h b/WebCore/html/HTMLOptGroupElement.h index b161728..13e92ca 100644 --- a/WebCore/html/HTMLOptGroupElement.h +++ b/WebCore/html/HTMLOptGroupElement.h @@ -36,7 +36,7 @@ public: HTMLOptGroupElement(const QualifiedName&, Document*, HTMLFormElement* = 0); virtual bool checkDTD(const Node*); - virtual const AtomicString& type() const; + virtual const AtomicString& formControlType() const; virtual bool isFocusable() const; virtual void parseMappedAttribute(MappedAttribute*); virtual bool rendererIsNeeded(RenderStyle*) { return false; } diff --git a/WebCore/html/HTMLOptionElement.cpp b/WebCore/html/HTMLOptionElement.cpp index e59537d..66968b0 100644 --- a/WebCore/html/HTMLOptionElement.cpp +++ b/WebCore/html/HTMLOptionElement.cpp @@ -30,9 +30,10 @@ #include "ExceptionCode.h" #include "HTMLNames.h" #include "HTMLSelectElement.h" +#include "MappedAttribute.h" +#include "NodeRenderStyle.h" #include "RenderMenuList.h" #include "Text.h" -#include "NodeRenderStyle.h" #include <wtf/StdLibExtras.h> #include <wtf/Vector.h> @@ -42,7 +43,6 @@ using namespace HTMLNames; HTMLOptionElement::HTMLOptionElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f) : HTMLFormControlElement(tagName, doc, f) - , m_data(this) , m_style(0) { ASSERT(hasTagName(optionTag)); @@ -71,7 +71,7 @@ bool HTMLOptionElement::isFocusable() const return HTMLElement::isFocusable(); } -const AtomicString& HTMLOptionElement::type() const +const AtomicString& HTMLOptionElement::formControlType() const { DEFINE_STATIC_LOCAL(const AtomicString, option, ("option")); return option; @@ -79,7 +79,7 @@ const AtomicString& HTMLOptionElement::type() const String HTMLOptionElement::text() const { - return OptionElement::collectOptionText(m_data, document()); + return OptionElement::collectOptionText(m_data, this); } void HTMLOptionElement::setText(const String &text, ExceptionCode& ec) @@ -104,22 +104,7 @@ void HTMLOptionElement::accessKeyAction(bool) int HTMLOptionElement::index() const { - // Let's do this dynamically. Might be a bit slow, but we're sure - // we won't forget to update a member variable in some cases... - HTMLSelectElement* select = ownerSelectElement(); - if (select) { - const Vector<HTMLElement*>& items = select->listItems(); - int l = items.size(); - int optionIndex = 0; - for(int i = 0; i < l; i++) { - if (items[i]->hasLocalName(optionTag)) { - if (static_cast<HTMLOptionElement*>(items[i]) == this) - return optionIndex; - optionIndex++; - } - } - } - return 0; + return OptionElement::optionIndex(ownerSelectElement(), this); } void HTMLOptionElement::parseMappedAttribute(MappedAttribute *attr) @@ -136,7 +121,7 @@ void HTMLOptionElement::parseMappedAttribute(MappedAttribute *attr) String HTMLOptionElement::value() const { - return OptionElement::collectOptionValue(m_data, document()); + return OptionElement::collectOptionValue(m_data, this); } void HTMLOptionElement::setValue(const String& value) @@ -154,7 +139,7 @@ void HTMLOptionElement::setSelected(bool selected) if (m_data.selected() == selected) return; - OptionElement::setSelectedState(m_data, selected); + OptionElement::setSelectedState(m_data, this, selected); if (HTMLSelectElement* select = ownerSelectElement()) select->setSelectedIndex(selected ? index() : -1, false); @@ -162,7 +147,7 @@ void HTMLOptionElement::setSelected(bool selected) void HTMLOptionElement::setSelectedState(bool selected) { - OptionElement::setSelectedState(m_data, selected); + OptionElement::setSelectedState(m_data, this, selected); } void HTMLOptionElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) @@ -221,7 +206,7 @@ RenderStyle* HTMLOptionElement::nonRendererRenderStyle() const String HTMLOptionElement::textIndentedToRespectGroupLabel() const { - return OptionElement::collectOptionTextRespectingGroupLabel(m_data, document()); + return OptionElement::collectOptionTextRespectingGroupLabel(m_data, this); } bool HTMLOptionElement::disabled() const diff --git a/WebCore/html/HTMLOptionElement.h b/WebCore/html/HTMLOptionElement.h index 8c0f260..f13a802 100644 --- a/WebCore/html/HTMLOptionElement.h +++ b/WebCore/html/HTMLOptionElement.h @@ -48,9 +48,9 @@ public: virtual void detach(); virtual void setRenderStyle(PassRefPtr<RenderStyle>); - virtual const AtomicString& type() const; + virtual const AtomicString& formControlType() const; - String text() const; + virtual String text() const; void setText(const String&, ExceptionCode&); int index() const; diff --git a/WebCore/html/HTMLOptionElement.idl b/WebCore/html/HTMLOptionElement.idl index 34fa999..612d459 100644 --- a/WebCore/html/HTMLOptionElement.idl +++ b/WebCore/html/HTMLOptionElement.idl @@ -28,7 +28,7 @@ module html { ] HTMLOptionElement : HTMLElement { readonly attribute HTMLFormElement form; attribute boolean defaultSelected; -#if defined(LANGUAGE_JAVASCRIPT) +#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT attribute [ConvertNullToNullString] DOMString text setter raises(DOMException); #else diff --git a/WebCore/html/HTMLOptionsCollection.idl b/WebCore/html/HTMLOptionsCollection.idl index 226f3d7..5f85fcb 100644 --- a/WebCore/html/HTMLOptionsCollection.idl +++ b/WebCore/html/HTMLOptionsCollection.idl @@ -36,7 +36,7 @@ module html { raises (DOMException); [Custom] void remove(in unsigned long index); -#if !defined(LANGUAGE_JAVASCRIPT) +#if !defined(LANGUAGE_JAVASCRIPT) || !LANGUAGE_JAVASCRIPT Node item(in unsigned long index); Node namedItem(in DOMString name); #endif diff --git a/WebCore/html/HTMLParagraphElement.cpp b/WebCore/html/HTMLParagraphElement.cpp index 44eaecc..a8deb10 100644 --- a/WebCore/html/HTMLParagraphElement.cpp +++ b/WebCore/html/HTMLParagraphElement.cpp @@ -19,6 +19,7 @@ * Boston, MA 02110-1301, USA. * */ + #include "config.h" #include "HTMLParagraphElement.h" @@ -26,6 +27,7 @@ #include "CSSValueKeywords.h" #include "Document.h" #include "HTMLNames.h" +#include "MappedAttribute.h" namespace WebCore { diff --git a/WebCore/html/HTMLParamElement.cpp b/WebCore/html/HTMLParamElement.cpp index 6e1197b..d5fc6e7 100644 --- a/WebCore/html/HTMLParamElement.cpp +++ b/WebCore/html/HTMLParamElement.cpp @@ -25,6 +25,7 @@ #include "Document.h" #include "HTMLNames.h" +#include "MappedAttribute.h" namespace WebCore { diff --git a/WebCore/html/HTMLParser.cpp b/WebCore/html/HTMLParser.cpp index a4d4671..dab58b3 100644 --- a/WebCore/html/HTMLParser.cpp +++ b/WebCore/html/HTMLParser.cpp @@ -3,7 +3,8 @@ (C) 1997 Torben Weis (weis@kde.org) (C) 1999,2001 Lars Knoll (knoll@kde.org) (C) 2000,2001 Dirk Mueller (mueller@kde.org) - Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -27,6 +28,7 @@ #include "CharacterNames.h" #include "CSSPropertyNames.h" #include "CSSValueKeywords.h" +#include "ChromeClient.h" #include "Comment.h" #include "Console.h" #include "DOMWindow.h" @@ -45,15 +47,17 @@ #include "HTMLIsIndexElement.h" #include "HTMLMapElement.h" #include "HTMLNames.h" +#include "HTMLParserQuirks.h" #include "HTMLTableCellElement.h" #include "HTMLTableRowElement.h" #include "HTMLTableSectionElement.h" #include "HTMLTokenizer.h" #include "LocalizedStrings.h" +#include "Page.h" #include "Settings.h" #include "Text.h" #include <wtf/StdLibExtras.h> - + namespace WebCore { using namespace HTMLNames; @@ -126,7 +130,6 @@ HTMLParser::HTMLParser(HTMLDocument* doc, bool reportErrors) , m_blockStack(0) , m_blocksInStack(0) , m_hasPElementInScope(NotInScope) - , m_head(0) , m_inBody(false) , m_haveContent(false) , m_haveFrameSet(false) @@ -134,6 +137,7 @@ HTMLParser::HTMLParser(HTMLDocument* doc, bool reportErrors) , m_reportErrors(reportErrors) , m_handlingResidualStyleAcrossBlocks(false) , m_inStrayTableContent(0) + , m_parserQuirks(m_document->page() ? m_document->page()->chrome()->client()->createHTMLParserQuirks() : 0) { } @@ -144,7 +148,6 @@ HTMLParser::HTMLParser(DocumentFragment* frag) , m_blockStack(0) , m_blocksInStack(0) , m_hasPElementInScope(NotInScope) - , m_head(0) , m_inBody(true) , m_haveContent(false) , m_haveFrameSet(false) @@ -152,6 +155,7 @@ HTMLParser::HTMLParser(DocumentFragment* frag) , m_reportErrors(false) , m_handlingResidualStyleAcrossBlocks(false) , m_inStrayTableContent(0) + , m_parserQuirks(m_document->page() ? m_document->page()->chrome()->client()->createHTMLParserQuirks() : 0) { if (frag) frag->ref(); @@ -161,7 +165,7 @@ HTMLParser::~HTMLParser() { freeBlock(); if (m_didRefCurrent) - m_current->deref(); + m_current->deref(); } void HTMLParser::reset() @@ -183,6 +187,9 @@ void HTMLParser::reset() m_isindexElement = 0; m_skipModeTag = nullAtom; + + if (m_parserQuirks) + m_parserQuirks->reset(); } void HTMLParser::setCurrent(Node* newCurrent) @@ -334,6 +341,9 @@ bool HTMLParser::insertNode(Node* n, bool flat) popBlock(m_blockStack->tagName); } + if (m_parserQuirks && !m_parserQuirks->shouldInsertNode(m_current, n)) + return false; + // let's be stupid and just try to insert it. // this should work if the document is well-formed Node* newNode = m_current->addChild(n); @@ -347,6 +357,8 @@ bool HTMLParser::insertNode(Node* n, bool flat) // This case should only be hit when a demoted <form> is placed inside a table. ASSERT(localName == formTag); reportError(FormInsideTablePartError, &m_current->localName()); + HTMLFormElement* form = static_cast<HTMLFormElement*>(n); + form->setDemoted(true); } else { // The pushBlock function transfers ownership of current to the block stack // so we're guaranteed that m_didRefCurrent is false. The code below is an @@ -417,9 +429,9 @@ bool HTMLParser::handleError(Node* n, bool flat, const AtomicString& localName, reportError(RedundantHTMLBodyError, &localName); // we have another <HTML> element.... apply attributes to existing one // make sure we don't overwrite already existing attributes - NamedAttrMap* map = static_cast<Element*>(n)->attributes(true); + NamedNodeMap* map = static_cast<Element*>(n)->attributes(true); Element* existingHTML = static_cast<Element*>(m_document->documentElement()); - NamedAttrMap* bmap = existingHTML->attributes(false); + NamedNodeMap* bmap = existingHTML->attributes(false); for (unsigned l = 0; map && l < map->length(); ++l) { Attribute* it = map->attributeItem(l); if (!bmap->getAttributeItem(it->name())) @@ -428,7 +440,7 @@ bool HTMLParser::handleError(Node* n, bool flat, const AtomicString& localName, } return false; } - } else if (h->hasLocalName(titleTag) || h->hasLocalName(styleTag)) { + } else if (h->hasLocalName(titleTag) || h->hasLocalName(styleTag) || h->hasLocalName(scriptTag)) { bool createdHead = false; if (!m_head) { createHead(); @@ -461,9 +473,9 @@ bool HTMLParser::handleError(Node* n, bool flat, const AtomicString& localName, // make sure we don't overwrite already existing attributes // some sites use <body bgcolor=rightcolor>...<body bgcolor=wrongcolor> reportError(RedundantHTMLBodyError, &localName); - NamedAttrMap* map = static_cast<Element*>(n)->attributes(true); + NamedNodeMap* map = static_cast<Element*>(n)->attributes(true); Element* existingBody = m_document->body(); - NamedAttrMap* bmap = existingBody->attributes(false); + NamedNodeMap* bmap = existingBody->attributes(false); for (unsigned l = 0; map && l < map->length(); ++l) { Attribute* it = map->attributeItem(l); if (!bmap->getAttributeItem(it->name())) @@ -506,8 +518,7 @@ bool HTMLParser::handleError(Node* n, bool flat, const AtomicString& localName, elt->hasLocalName(baseTag))) { if (!m_head) { m_head = new HTMLHeadElement(headTag, m_document); - e = m_head; - insertNode(e); + insertNode(m_head.get()); handled = true; } } else { @@ -517,6 +528,12 @@ bool HTMLParser::handleError(Node* n, bool flat, const AtomicString& localName, return false; } if (!m_haveFrameSet) { + // Ensure that head exists. + // But not for older versions of Mail, where the implicit <head> isn't expected - <rdar://problem/6863795> + if (shouldCreateImplicitHead(m_document)) + createHead(); + + popBlock(headTag); e = new HTMLBodyElement(bodyTag, m_document); startBody(); insertNode(e); @@ -530,6 +547,7 @@ bool HTMLParser::handleError(Node* n, bool flat, const AtomicString& localName, else { // This means the body starts here... if (!m_haveFrameSet) { + ASSERT(currentTagName == headTag); popBlock(currentTagName); e = new HTMLBodyElement(bodyTag, m_document); startBody(); @@ -699,6 +717,12 @@ bool HTMLParser::bodyCreateErrorCheck(Token*, RefPtr<Node>&) // body no longer allowed if we have a frameset if (m_haveFrameSet) return false; + + // Ensure that head exists (unless parsing a fragment). + // But not for older versions of Mail, where the implicit <head> isn't expected - <rdar://problem/6863795> + if (!m_isParsingFragment && shouldCreateImplicitHead(m_document)) + createHead(); + popBlock(headTag); startBody(); return true; @@ -886,7 +910,9 @@ PassRefPtr<Node> HTMLParser::getNode(Token* t) gFunctionMap.set(nobrTag.localName().impl(), &HTMLParser::nestedCreateErrorCheck); gFunctionMap.set(noembedTag.localName().impl(), &HTMLParser::noembedCreateErrorCheck); gFunctionMap.set(noframesTag.localName().impl(), &HTMLParser::noframesCreateErrorCheck); +#if !ENABLE(XHTMLMP) gFunctionMap.set(noscriptTag.localName().impl(), &HTMLParser::noscriptCreateErrorCheck); +#endif gFunctionMap.set(olTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); gFunctionMap.set(pTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); gFunctionMap.set(plaintextTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); @@ -992,11 +1018,13 @@ bool HTMLParser::isInline(Node* node) const e->hasLocalName(noframesTag) || e->hasLocalName(nolayerTag) || e->hasLocalName(noembedTag)) return true; +#if !ENABLE(XHTMLMP) if (e->hasLocalName(noscriptTag) && !m_isParsingFragment) { Settings* settings = m_document->settings(); if (settings && settings->isJavaScriptEnabled()) return true; } +#endif } return false; @@ -1335,7 +1363,10 @@ void HTMLParser::pushBlock(const AtomicString& tagName, int level) void HTMLParser::popBlock(const AtomicString& tagName, bool reportErrors) { HTMLStackElem* elem = m_blockStack; - + + if (m_parserQuirks && elem && !m_parserQuirks->shouldPopBlock(elem->tagName, tagName)) + return; + int maxLevel = 0; while (elem && (elem->tagName != tagName)) { @@ -1510,20 +1541,25 @@ void HTMLParser::freeBlock() void HTMLParser::createHead() { - if (m_head || !m_document->documentElement()) + if (m_head) return; + if (!m_document->documentElement()) { + insertNode(new HTMLHtmlElement(htmlTag, m_document)); + ASSERT(m_document->documentElement()); + } + m_head = new HTMLHeadElement(headTag, m_document); HTMLElement* body = m_document->body(); ExceptionCode ec = 0; - m_document->documentElement()->insertBefore(m_head, body, ec); + m_document->documentElement()->insertBefore(m_head.get(), body, ec); if (ec) m_head = 0; // If the body does not exist yet, then the <head> should be pushed as the current block. if (m_head && !body) { pushBlock(m_head->localName(), m_head->tagPriority()); - setCurrent(m_head); + setCurrent(m_head.get()); } } @@ -1624,4 +1660,22 @@ void HTMLParser::reportErrorToConsole(HTMLParserErrorCode errorCode, const Atomi message, lineNumber, m_document->url().string()); } +#ifdef BUILDING_ON_LEOPARD +bool shouldCreateImplicitHead(Document* document) +{ + ASSERT(document); + + Settings* settings = document->page() ? document->page()->settings() : 0; + return settings ? !settings->needsLeopardMailQuirks() : true; +} +#elif defined(BUILDING_ON_TIGER) +bool shouldCreateImplicitHead(Document* document) +{ + ASSERT(document); + + Settings* settings = document->page() ? document->page()->settings() : 0; + return settings ? !settings->needsTigerMailQuirks() : true; +} +#endif + } diff --git a/WebCore/html/HTMLParser.h b/WebCore/html/HTMLParser.h index 23fb980..19f553e 100644 --- a/WebCore/html/HTMLParser.h +++ b/WebCore/html/HTMLParser.h @@ -3,7 +3,7 @@ (C) 1997 Torben Weis (weis@kde.org) (C) 1998 Waldo Bastian (bastian@kde.org) (C) 1999 Lars Knoll (knoll@kde.org) - Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -26,6 +26,7 @@ #include "QualifiedName.h" #include <wtf/Forward.h> +#include <wtf/OwnPtr.h> #include <wtf/RefPtr.h> #include "HTMLParserErrorCodes.h" @@ -38,6 +39,7 @@ class HTMLDocument; class HTMLFormElement; class HTMLHeadElement; class HTMLMapElement; +class HTMLParserQuirks; class Node; struct HTMLStackElem; @@ -169,7 +171,7 @@ private: RefPtr<HTMLFormElement> m_currentFormElement; // currently active form RefPtr<HTMLMapElement> m_currentMapElement; // current map - HTMLHeadElement* m_head; // head element; needed for HTML which defines <base> after </head> + RefPtr<HTMLHeadElement> m_head; // head element; needed for HTML which defines <base> after </head> RefPtr<Node> m_isindexElement; // a possible <isindex> element in the head bool m_inBody; @@ -182,8 +184,16 @@ private: bool m_reportErrors; bool m_handlingResidualStyleAcrossBlocks; int m_inStrayTableContent; + + OwnPtr<HTMLParserQuirks> m_parserQuirks; }; +#if defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_TIGER) +bool shouldCreateImplicitHead(Document*); +#else +inline bool shouldCreateImplicitHead(Document*) { return true; } +#endif + } #endif // HTMLParser_h diff --git a/WebCore/html/HTMLParserQuirks.h b/WebCore/html/HTMLParserQuirks.h new file mode 100644 index 0000000..b5972a6 --- /dev/null +++ b/WebCore/html/HTMLParserQuirks.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE 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 HTMLParserQuirks_h +#define HTMLParserQuirks_h + +#include <wtf/Noncopyable.h> + +namespace WebCore { + +class AtomicString; +class Node; + +class HTMLParserQuirks : Noncopyable { +public: + HTMLParserQuirks() { } + virtual ~HTMLParserQuirks() { } + + virtual void reset() = 0; + + virtual bool shouldInsertNode(Node* parent, Node* newNode) = 0; + virtual bool shouldPopBlock(const AtomicString& tagNameOnStack, const AtomicString& tagNameToPop) = 0; +}; + +} // namespace WebCore + +#endif // HTMLParserQuirks_h diff --git a/WebCore/html/HTMLPlugInElement.cpp b/WebCore/html/HTMLPlugInElement.cpp index 4344b3d..d950d9d 100644 --- a/WebCore/html/HTMLPlugInElement.cpp +++ b/WebCore/html/HTMLPlugInElement.cpp @@ -21,6 +21,7 @@ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ + #include "config.h" #include "HTMLPlugInElement.h" @@ -30,6 +31,7 @@ #include "FrameLoader.h" #include "FrameTree.h" #include "HTMLNames.h" +#include "MappedAttribute.h" #include "Page.h" #include "RenderWidget.h" #include "ScriptController.h" @@ -46,7 +48,7 @@ using namespace HTMLNames; HTMLPlugInElement::HTMLPlugInElement(const QualifiedName& tagName, Document* doc) // FIXME: Always passing false as createdByParser is odd (see bug22851). - : HTMLFrameOwnerElement(tagName, doc, false) + : HTMLFrameOwnerElement(tagName, doc) #if ENABLE(NETSCAPE_PLUGIN_API) , m_NPObject(0) #endif diff --git a/WebCore/html/HTMLPreElement.cpp b/WebCore/html/HTMLPreElement.cpp index 23ecaaa..f340ae3 100644 --- a/WebCore/html/HTMLPreElement.cpp +++ b/WebCore/html/HTMLPreElement.cpp @@ -21,12 +21,14 @@ * Boston, MA 02110-1301, USA. * */ + #include "config.h" #include "HTMLPreElement.h" #include "CSSPropertyNames.h" #include "CSSValueKeywords.h" #include "HTMLNames.h" +#include "MappedAttribute.h" namespace WebCore { diff --git a/WebCore/html/HTMLScriptElement.cpp b/WebCore/html/HTMLScriptElement.cpp index 4744b34..86cc3a2 100644 --- a/WebCore/html/HTMLScriptElement.cpp +++ b/WebCore/html/HTMLScriptElement.cpp @@ -26,6 +26,8 @@ #include "Document.h" #include "EventNames.h" #include "HTMLNames.h" +#include "MappedAttribute.h" +#include "ScriptEventListener.h" #include "Text.h" namespace WebCore { @@ -67,7 +69,7 @@ void HTMLScriptElement::parseMappedAttribute(MappedAttribute* attr) if (attrName == srcAttr) handleSourceAttribute(m_data, attr->value()); else if (attrName == onloadAttr) - setInlineEventListenerForTypeAndAttribute(eventNames().loadEvent, attr); + setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr)); else HTMLElement::parseMappedAttribute(attr); } @@ -209,18 +211,23 @@ String HTMLScriptElement::languageAttributeValue() const { return getAttribute(languageAttr).string(); } + +String HTMLScriptElement::forAttributeValue() const +{ + return getAttribute(forAttr).string(); +} void HTMLScriptElement::dispatchLoadEvent() { ASSERT(!m_data.haveFiredLoadEvent()); m_data.setHaveFiredLoadEvent(true); - dispatchEventForType(eventNames().loadEvent, false, false); + dispatchEvent(eventNames().loadEvent, false, false); } void HTMLScriptElement::dispatchErrorEvent() { - dispatchEventForType(eventNames().errorEvent, true, false); + dispatchEvent(eventNames().errorEvent, true, false); } } diff --git a/WebCore/html/HTMLScriptElement.h b/WebCore/html/HTMLScriptElement.h index 8839131..4d18beb 100644 --- a/WebCore/html/HTMLScriptElement.h +++ b/WebCore/html/HTMLScriptElement.h @@ -35,7 +35,7 @@ public: HTMLScriptElement(const QualifiedName&, Document*, bool createdByParser); ~HTMLScriptElement(); - bool shouldExecuteAsJavaScript() const; + virtual bool shouldExecuteAsJavaScript() const; virtual String scriptContent() const; virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } @@ -75,11 +75,14 @@ public: virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const; + bool haveFiredLoadEvent() const { return m_data.haveFiredLoadEvent(); } + protected: virtual String sourceAttributeValue() const; virtual String charsetAttributeValue() const; virtual String typeAttributeValue() const; virtual String languageAttributeValue() const; + virtual String forAttributeValue() const; virtual void dispatchLoadEvent(); virtual void dispatchErrorEvent(); diff --git a/WebCore/html/HTMLSelectElement.cpp b/WebCore/html/HTMLSelectElement.cpp index 107fbd0..95038e6 100644 --- a/WebCore/html/HTMLSelectElement.cpp +++ b/WebCore/html/HTMLSelectElement.cpp @@ -21,67 +21,31 @@ * Boston, MA 02110-1301, USA. * */ - + #include "config.h" #include "HTMLSelectElement.h" #include "AXObjectCache.h" -#include "CSSPropertyNames.h" -#include "CSSStyleSelector.h" -#include "CharacterNames.h" -#include "ChromeClient.h" -#include "Document.h" -#include "Event.h" -#include "EventHandler.h" #include "EventNames.h" -#include "FormDataList.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "FrameLoaderClient.h" -#include "HTMLFormElement.h" #include "HTMLNames.h" #include "HTMLOptionElement.h" #include "HTMLOptionsCollection.h" -#include "KeyboardEvent.h" -#include "MouseEvent.h" -#include "Page.h" +#include "MappedAttribute.h" #include "RenderListBox.h" #include "RenderMenuList.h" -#include <math.h> -#include <wtf/StdLibExtras.h> -#include <wtf/Vector.h> - -#if PLATFORM(MAC) -#define ARROW_KEYS_POP_MENU 1 -#else -#define ARROW_KEYS_POP_MENU 0 -#endif +#include "ScriptEventListener.h" using namespace std; -using namespace WTF; -using namespace Unicode; namespace WebCore { using namespace HTMLNames; -static const DOMTimeStamp typeAheadTimeout = 1000; - // Upper limit agreed upon with representatives of Opera and Mozilla. static const unsigned maxSelectItems = 10000; -HTMLSelectElement::HTMLSelectElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f) - : HTMLFormControlElementWithState(tagName, doc, f) - , m_minwidth(0) - , m_size(0) - , m_multiple(false) - , m_recalcListItems(false) - , m_lastOnChangeIndex(-1) - , m_activeSelectionAnchorIndex(-1) - , m_activeSelectionEndIndex(-1) - , m_activeSelectionState(false) - , m_repeatingChar(0) - , m_lastCharTime(0) +HTMLSelectElement::HTMLSelectElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form) + : HTMLFormControlElementWithState(tagName, document, form) { ASSERT(hasTagName(selectTag) || hasTagName(keygenTag)); } @@ -93,120 +57,52 @@ bool HTMLSelectElement::checkDTD(const Node* newChild) newChild->hasTagName(scriptTag); } -void HTMLSelectElement::recalcStyle( StyleChange ch ) +void HTMLSelectElement::recalcStyle(StyleChange change) { - if (hasChangedChild() && renderer()) { - if (usesMenuList()) - static_cast<RenderMenuList*>(renderer())->setOptionsChanged(true); - else - static_cast<RenderListBox*>(renderer())->setOptionsChanged(true); - } else if (m_recalcListItems) - recalcListItems(); - - HTMLFormControlElementWithState::recalcStyle(ch); + SelectElement::recalcStyle(m_data, this); + HTMLFormControlElementWithState::recalcStyle(change); } -const AtomicString& HTMLSelectElement::type() const +const AtomicString& HTMLSelectElement::formControlType() const { DEFINE_STATIC_LOCAL(const AtomicString, selectMultiple, ("select-multiple")); DEFINE_STATIC_LOCAL(const AtomicString, selectOne, ("select-one")); - return m_multiple ? selectMultiple : selectOne; + return m_data.multiple() ? selectMultiple : selectOne; } int HTMLSelectElement::selectedIndex() const { - // return the number of the first option selected - unsigned index = 0; - const Vector<HTMLElement*>& items = listItems(); - for (unsigned int i = 0; i < items.size(); i++) { - if (items[i]->hasLocalName(optionTag)) { - if (static_cast<HTMLOptionElement*>(items[i])->selected()) - return index; - index++; - } - } - return -1; -} - -int HTMLSelectElement::lastSelectedListIndex() const -{ - // return the number of the last option selected - unsigned index = 0; - bool found = false; - const Vector<HTMLElement*>& items = listItems(); - for (unsigned int i = 0; i < items.size(); i++) { - if (items[i]->hasLocalName(optionTag)) { - if (static_cast<HTMLOptionElement*>(items[i])->selected()) { - index = i; - found = true; - } - } - } - return found ? (int) index : -1; + return SelectElement::selectedIndex(m_data, this); } void HTMLSelectElement::deselectItems(HTMLOptionElement* excludeElement) { - const Vector<HTMLElement*>& items = listItems(); - unsigned i; - for (i = 0; i < items.size(); i++) { - if (items[i]->hasLocalName(optionTag) && (items[i] != excludeElement)) { - HTMLOptionElement* element = static_cast<HTMLOptionElement*>(items[i]); - element->setSelectedState(false); - } - } + SelectElement::deselectItems(m_data, this, excludeElement); } void HTMLSelectElement::setSelectedIndex(int optionIndex, bool deselect, bool fireOnChange) { - const Vector<HTMLElement*>& items = listItems(); - int listIndex = optionToListIndex(optionIndex); - HTMLOptionElement* element = 0; - - if (!multiple()) - deselect = true; - - if (listIndex >= 0) { - if (m_activeSelectionAnchorIndex < 0 || deselect) - setActiveSelectionAnchorIndex(listIndex); - if (m_activeSelectionEndIndex < 0 || deselect) - setActiveSelectionEndIndex(listIndex); - element = static_cast<HTMLOptionElement*>(items[listIndex]); - element->setSelectedState(true); - } - - if (deselect) - deselectItems(element); - - scrollToSelection(); - - // This only gets called with fireOnChange for menu lists. - if (fireOnChange && usesMenuList()) - menuListOnChange(); - - Frame* frame = document()->frame(); - if (frame) - frame->page()->chrome()->client()->formStateDidChange(this); + SelectElement::setSelectedIndex(m_data, this, optionIndex, deselect, fireOnChange); } int HTMLSelectElement::activeSelectionStartListIndex() const { - if (m_activeSelectionAnchorIndex >= 0) - return m_activeSelectionAnchorIndex; + if (m_data.activeSelectionAnchorIndex() >= 0) + return m_data.activeSelectionAnchorIndex(); return optionToListIndex(selectedIndex()); } int HTMLSelectElement::activeSelectionEndListIndex() const { - if (m_activeSelectionEndIndex >= 0) - return m_activeSelectionEndIndex; - return lastSelectedListIndex(); + if (m_data.activeSelectionEndIndex() >= 0) + return m_data.activeSelectionEndIndex(); + return SelectElement::lastSelectedListIndex(m_data, this); } unsigned HTMLSelectElement::length() const { unsigned len = 0; - const Vector<HTMLElement*>& items = listItems(); + const Vector<Element*>& items = listItems(); for (unsigned i = 0; i < items.size(); ++i) { if (items[i]->hasLocalName(optionTag)) ++len; @@ -226,27 +122,24 @@ void HTMLSelectElement::add(HTMLElement *element, HTMLElement *before, Exception void HTMLSelectElement::remove(int index) { - ExceptionCode ec = 0; int listIndex = optionToListIndex(index); + if (listIndex < 0) + return; - const Vector<HTMLElement*>& items = listItems(); - if (listIndex < 0 || index >= int(items.size())) - return; // ### what should we do ? remove the last item? - - Element *item = items[listIndex]; + Element* item = listItems()[listIndex]; ASSERT(item->parentNode()); + ExceptionCode ec; item->parentNode()->removeChild(item, ec); } String HTMLSelectElement::value() { - unsigned i; - const Vector<HTMLElement*>& items = listItems(); - for (i = 0; i < items.size(); i++) { + const Vector<Element*>& items = listItems(); + for (unsigned i = 0; i < items.size(); i++) { if (items[i]->hasLocalName(optionTag) && static_cast<HTMLOptionElement*>(items[i])->selected()) return static_cast<HTMLOptionElement*>(items[i])->value(); } - return String(""); + return ""; } void HTMLSelectElement::setValue(const String &value) @@ -255,9 +148,9 @@ void HTMLSelectElement::setValue(const String &value) return; // find the option with value() matching the given parameter // and make it the current selection. - const Vector<HTMLElement*>& items = listItems(); + const Vector<Element*>& items = listItems(); unsigned optionIndex = 0; - for (unsigned i = 0; i < items.size(); i++) + for (unsigned i = 0; i < items.size(); i++) { if (items[i]->hasLocalName(optionTag)) { if (static_cast<HTMLOptionElement*>(items[i])->value() == value) { setSelectedIndex(optionIndex, true); @@ -265,40 +158,24 @@ void HTMLSelectElement::setValue(const String &value) } optionIndex++; } + } } -bool HTMLSelectElement::saveState(String& value) const +bool HTMLSelectElement::saveFormControlState(String& value) const { - const Vector<HTMLElement*>& items = listItems(); - int l = items.size(); - Vector<char, 1024> characters(l); - for (int i = 0; i < l; ++i) { - HTMLElement* e = items[i]; - bool selected = e->hasLocalName(optionTag) && static_cast<HTMLOptionElement*>(e)->selected(); - characters[i] = selected ? 'X' : '.'; - } - value = String(characters.data(), l); - return true; + return SelectElement::saveFormControlState(m_data, this, value); } -void HTMLSelectElement::restoreState(const String& state) +void HTMLSelectElement::restoreFormControlState(const String& state) { - recalcListItems(); - - const Vector<HTMLElement*>& items = listItems(); - int l = items.size(); - for (int i = 0; i < l; i++) - if (items[i]->hasLocalName(optionTag)) - static_cast<HTMLOptionElement*>(items[i])->setSelectedState(state[i] == 'X'); - - setChanged(); + SelectElement::restoreFormControlState(m_data, this, state); } -void HTMLSelectElement::parseMappedAttribute(MappedAttribute *attr) +void HTMLSelectElement::parseMappedAttribute(MappedAttribute* attr) { - bool oldUsesMenuList = usesMenuList(); + bool oldUsesMenuList = m_data.usesMenuList(); if (attr->name() == sizeAttr) { - int oldSize = m_size; + int oldSize = m_data.size(); // Set the attribute value to a number. // This is important since the style rules for this attribute can determine the appearance property. int size = attr->value().toInt(); @@ -306,31 +183,25 @@ void HTMLSelectElement::parseMappedAttribute(MappedAttribute *attr) if (attrSize != attr->value()) attr->setValue(attrSize); - m_size = max(size, 1); - if ((oldUsesMenuList != usesMenuList() || (!oldUsesMenuList && m_size != oldSize)) && attached()) { + m_data.setSize(max(size, 1)); + if ((oldUsesMenuList != m_data.usesMenuList() || (!oldUsesMenuList && m_data.size() != oldSize)) && attached()) { detach(); attach(); setRecalcListItems(); } - } else if (attr->name() == widthAttr) { - m_minwidth = max(attr->value().toInt(), 0); - } else if (attr->name() == multipleAttr) { - m_multiple = (!attr->isNull()); - if (oldUsesMenuList != usesMenuList() && attached()) { - detach(); - attach(); - } - } else if (attr->name() == accesskeyAttr) { + } else if (attr->name() == multipleAttr) + SelectElement::parseMultipleAttribute(m_data, this, attr); + else if (attr->name() == accesskeyAttr) { // FIXME: ignore for the moment } else if (attr->name() == alignAttr) { // Don't map 'align' attribute. This matches what Firefox, Opera and IE do. // See http://bugs.webkit.org/show_bug.cgi?id=12072 } else if (attr->name() == onfocusAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().focusEvent, attr); + setAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onblurAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().blurEvent, attr); + setAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onchangeAttr) { - setInlineEventListenerForTypeAndAttribute(eventNames().changeEvent, attr); + setAttributeEventListener(eventNames().changeEvent, createAttributeEventListener(this, attr)); } else HTMLFormControlElementWithState::parseMappedAttribute(attr); } @@ -351,98 +222,34 @@ bool HTMLSelectElement::isMouseFocusable() const bool HTMLSelectElement::canSelectAll() const { - return !usesMenuList(); + return !m_data.usesMenuList(); } void HTMLSelectElement::selectAll() { - ASSERT(!usesMenuList()); - if (!renderer() || !multiple()) - return; - - // Save the selection so it can be compared to the new selectAll selection when we call onChange - saveLastSelection(); - - m_activeSelectionState = true; - setActiveSelectionAnchorIndex(nextSelectableListIndex(-1)); - setActiveSelectionEndIndex(previousSelectableListIndex(-1)); - - updateListBoxSelection(false); - listBoxOnChange(); + SelectElement::selectAll(m_data, this); } RenderObject* HTMLSelectElement::createRenderer(RenderArena* arena, RenderStyle*) { - if (usesMenuList()) + if (m_data.usesMenuList()) return new (arena) RenderMenuList(this); return new (arena) RenderListBox(this); } bool HTMLSelectElement::appendFormData(FormDataList& list, bool) { - if (name().isEmpty()) - return false; - - bool successful = false; - const Vector<HTMLElement*>& items = listItems(); - - unsigned i; - for (i = 0; i < items.size(); i++) { - if (items[i]->hasLocalName(optionTag)) { - HTMLOptionElement *option = static_cast<HTMLOptionElement*>(items[i]); - if (option->selected()) { - list.appendData(name(), option->value()); - successful = true; - } - } - } - - // ### this case should not happen. make sure that we select the first option - // in any case. otherwise we have no consistency with the DOM interface. FIXME! - // we return the first one if it was a combobox select - if (!successful && !m_multiple && m_size <= 1 && items.size() && - (items[0]->hasLocalName(optionTag))) { - HTMLOptionElement *option = static_cast<HTMLOptionElement*>(items[0]); - if (option->value().isNull()) - list.appendData(name(), option->text().stripWhiteSpace()); - else - list.appendData(name(), option->value()); - successful = true; - } - - return successful; + return SelectElement::appendFormData(m_data, this, list); } int HTMLSelectElement::optionToListIndex(int optionIndex) const { - const Vector<HTMLElement*>& items = listItems(); - int listSize = (int)items.size(); - if (optionIndex < 0 || optionIndex >= listSize) - return -1; - - int optionIndex2 = -1; - for (int listIndex = 0; listIndex < listSize; listIndex++) { - if (items[listIndex]->hasLocalName(optionTag)) { - optionIndex2++; - if (optionIndex2 == optionIndex) - return listIndex; - } - } - return -1; + return SelectElement::optionToListIndex(m_data, this, optionIndex); } int HTMLSelectElement::listToOptionIndex(int listIndex) const { - const Vector<HTMLElement*>& items = listItems(); - if (listIndex < 0 || listIndex >= int(items.size()) || - !items[listIndex]->hasLocalName(optionTag)) - return -1; - - int optionIndex = 0; // actual index of option not counting OPTGROUP entries that may be in list - for (int i = 0; i < listIndex; i++) - if (items[i]->hasLocalName(optionTag)) - optionIndex++; - return optionIndex; + return SelectElement::listToOptionIndex(m_data, this, listIndex); } PassRefPtr<HTMLOptionsCollection> HTMLSelectElement::options() @@ -452,37 +259,7 @@ PassRefPtr<HTMLOptionsCollection> HTMLSelectElement::options() void HTMLSelectElement::recalcListItems(bool updateSelectedStates) const { - m_listItems.clear(); - HTMLOptionElement* foundSelected = 0; - for (Node* current = firstChild(); current; current = current->traverseNextSibling(this)) { - if (current->hasTagName(optgroupTag) && current->firstChild()) { - // FIXME: It doesn't make sense to add an optgroup to the list items, - // when it has children, but not to add it if it happens to have, - // children (say some comment nodes or text nodes), yet that's what - // this code does! - m_listItems.append(static_cast<HTMLElement*>(current)); - current = current->firstChild(); - // FIXME: It doesn't make sense to handle an <optgroup> inside another <optgroup> - // if it's not the first child, but not handle it if it happens to be the first - // child, yet that's what this code does! - } - - if (current->hasTagName(optionTag)) { - m_listItems.append(static_cast<HTMLElement*>(current)); - if (updateSelectedStates) { - if (!foundSelected && (usesMenuList() || (!m_multiple && static_cast<HTMLOptionElement*>(current)->selected()))) { - foundSelected = static_cast<HTMLOptionElement*>(current); - foundSelected->setSelectedState(true); - } else if (foundSelected && !m_multiple && static_cast<HTMLOptionElement*>(current)->selected()) { - foundSelected->setSelectedState(false); - foundSelected = static_cast<HTMLOptionElement*>(current); - } - } - } - if (current->hasTagName(hrTag)) - m_listItems.append(static_cast<HTMLElement*>(current)); - } - m_recalcListItems = false; + SelectElement::recalcListItems(const_cast<SelectElementData&>(m_data), this, updateSelectedStates); } void HTMLSelectElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) @@ -496,493 +273,65 @@ void HTMLSelectElement::childrenChanged(bool changedByParser, Node* beforeChange void HTMLSelectElement::setRecalcListItems() { - m_recalcListItems = true; - m_activeSelectionAnchorIndex = -1; // Manual selection anchor is reset when manipulating the select programmatically. - if (renderer()) { - if (usesMenuList()) - static_cast<RenderMenuList*>(renderer())->setOptionsChanged(true); - else - static_cast<RenderListBox*>(renderer())->setOptionsChanged(true); - } + SelectElement::setRecalcListItems(m_data, this); + if (!inDocument()) m_collectionInfo.reset(); - setChanged(); } void HTMLSelectElement::reset() { - bool optionSelected = false; - HTMLOptionElement* firstOption = 0; - const Vector<HTMLElement*>& items = listItems(); - unsigned i; - for (i = 0; i < items.size(); i++) { - if (items[i]->hasLocalName(optionTag)) { - HTMLOptionElement *option = static_cast<HTMLOptionElement*>(items[i]); - if (!option->getAttribute(selectedAttr).isNull()) { - option->setSelectedState(true); - optionSelected = true; - } else - option->setSelectedState(false); - if (!firstOption) - firstOption = option; - } - } - if (!optionSelected && firstOption && usesMenuList()) - firstOption->setSelectedState(true); - - setChanged(); + SelectElement::reset(m_data, this); } void HTMLSelectElement::dispatchFocusEvent() { - if (usesMenuList()) - // Save the selection so it can be compared to the new selection when we call onChange during dispatchBlurEvent. - saveLastSelection(); + SelectElement::dispatchFocusEvent(m_data, this); HTMLFormControlElementWithState::dispatchFocusEvent(); } void HTMLSelectElement::dispatchBlurEvent() { - // We only need to fire onChange here for menu lists, because we fire onChange for list boxes whenever the selection change is actually made. - // This matches other browsers' behavior. - if (usesMenuList()) - menuListOnChange(); + SelectElement::dispatchBlurEvent(m_data, this); HTMLFormControlElementWithState::dispatchBlurEvent(); } -void HTMLSelectElement::defaultEventHandler(Event* evt) +void HTMLSelectElement::defaultEventHandler(Event* event) { - if (!renderer()) + SelectElement::defaultEventHandler(m_data, this, event, form()); + if (event->defaultHandled()) return; - - if (usesMenuList()) - menuListDefaultEventHandler(evt); - else - listBoxDefaultEventHandler(evt); - - if (evt->defaultHandled()) - return; - - if (evt->type() == eventNames().keypressEvent && evt->isKeyboardEvent()) { - KeyboardEvent* keyboardEvent = static_cast<KeyboardEvent*>(evt); - - if (!keyboardEvent->ctrlKey() && !keyboardEvent->altKey() && !keyboardEvent->metaKey() && - isPrintableChar(keyboardEvent->charCode())) { - typeAheadFind(keyboardEvent); - evt->setDefaultHandled(); - return; - } - } - - HTMLFormControlElementWithState::defaultEventHandler(evt); -} - -void HTMLSelectElement::menuListDefaultEventHandler(Event* evt) -{ - if (evt->type() == eventNames().keydownEvent) { - if (!renderer() || !evt->isKeyboardEvent()) - return; - String keyIdentifier = static_cast<KeyboardEvent*>(evt)->keyIdentifier(); - bool handled = false; -#if ARROW_KEYS_POP_MENU - if (keyIdentifier == "Down" || keyIdentifier == "Up") { - focus(); - // Save the selection so it can be compared to the new selection when we call onChange during setSelectedIndex, - // which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu. - saveLastSelection(); - if (RenderMenuList* menuList = static_cast<RenderMenuList*>(renderer())) - menuList->showPopup(); - handled = true; - } -#elif defined ANDROID_KEYBOARD_NAVIGATION - if ("Enter" == keyIdentifier && usesMenuList()) { - menuList->showPopup(); - handled = true; - } -#else - int listIndex = optionToListIndex(selectedIndex()); - if (keyIdentifier == "Down" || keyIdentifier == "Right") { - int size = listItems().size(); - for (listIndex += 1; - listIndex >= 0 && listIndex < size && (listItems()[listIndex]->disabled() || !listItems()[listIndex]->hasTagName(optionTag)); - ++listIndex) { } - - if (listIndex >= 0 && listIndex < size) - setSelectedIndex(listToOptionIndex(listIndex)); - handled = true; - } else if (keyIdentifier == "Up" || keyIdentifier == "Left") { - int size = listItems().size(); - for (listIndex -= 1; - listIndex >= 0 && listIndex < size && (listItems()[listIndex]->disabled() || !listItems()[listIndex]->hasTagName(optionTag)); - --listIndex) { } - - if (listIndex >= 0 && listIndex < size) - setSelectedIndex(listToOptionIndex(listIndex)); - handled = true; - } -#endif - if (handled) - evt->setDefaultHandled(); - } - - // Use key press event here since sending simulated mouse events - // on key down blocks the proper sending of the key press event. - if (evt->type() == eventNames().keypressEvent) { - if (!renderer() || !evt->isKeyboardEvent()) - return; - int keyCode = static_cast<KeyboardEvent*>(evt)->keyCode(); - bool handled = false; -#if ARROW_KEYS_POP_MENU - if (keyCode == ' ') { - focus(); - // Save the selection so it can be compared to the new selection when we call onChange during setSelectedIndex, - // which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu. - saveLastSelection(); - if (RenderMenuList* menuList = static_cast<RenderMenuList*>(renderer())) - menuList->showPopup(); - handled = true; - } - if (keyCode == '\r') { - menuListOnChange(); - if (form()) - form()->submitClick(evt); - handled = true; - } -#else - int listIndex = optionToListIndex(selectedIndex()); - if (keyCode == '\r') { - // listIndex should already be selected, but this will fire the onchange handler. - setSelectedIndex(listToOptionIndex(listIndex), true, true); - handled = true; - } -#endif - if (handled) - evt->setDefaultHandled(); - } - - if (evt->type() == eventNames().mousedownEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton) { - focus(); - if (RenderMenuList* menuList = static_cast<RenderMenuList*>(renderer())) { - if (menuList->popupIsVisible()) - menuList->hidePopup(); - else { - // Save the selection so it can be compared to the new selection when we call onChange during setSelectedIndex, - // which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu. - saveLastSelection(); - menuList->showPopup(); - } - } - evt->setDefaultHandled(); - } + HTMLFormControlElementWithState::defaultEventHandler(event); } -void HTMLSelectElement::listBoxDefaultEventHandler(Event* evt) +void HTMLSelectElement::setActiveSelectionAnchorIndex(int index) { - if (evt->type() == eventNames().mousedownEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton) { - focus(); - - // Convert to coords relative to the list box if needed. - MouseEvent* mouseEvent = static_cast<MouseEvent*>(evt); - IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(mouseEvent->absoluteLocation(), false, true)); - int listIndex = static_cast<RenderListBox*>(renderer())->listIndexAtOffset(localOffset.x(), localOffset.y()); - if (listIndex >= 0) { - // Save the selection so it can be compared to the new selection when we call onChange during mouseup, or after autoscroll finishes. - saveLastSelection(); - - m_activeSelectionState = true; - - bool multiSelectKeyPressed = false; -#if PLATFORM(MAC) - multiSelectKeyPressed = mouseEvent->metaKey(); -#else - multiSelectKeyPressed = mouseEvent->ctrlKey(); -#endif - - bool shiftSelect = multiple() && mouseEvent->shiftKey(); - bool multiSelect = multiple() && multiSelectKeyPressed && !mouseEvent->shiftKey(); - - HTMLElement* clickedElement = listItems()[listIndex]; - HTMLOptionElement* option = 0; - if (clickedElement->hasLocalName(optionTag)) { - option = static_cast<HTMLOptionElement*>(clickedElement); - - // Keep track of whether an active selection (like during drag selection), should select or deselect - if (option->selected() && multiSelectKeyPressed) - m_activeSelectionState = false; - - if (!m_activeSelectionState) - option->setSelectedState(false); - } - - // If we're not in any special multiple selection mode, then deselect all other items, excluding the clicked option. - // If no option was clicked, then this will deselect all items in the list. - if (!shiftSelect && !multiSelect) - deselectItems(option); - - // If the anchor hasn't been set, and we're doing a single selection or a shift selection, then initialize the anchor to the first selected index. - if (m_activeSelectionAnchorIndex < 0 && !multiSelect) - setActiveSelectionAnchorIndex(selectedIndex()); - - // Set the selection state of the clicked option - if (option && !option->disabled()) - option->setSelectedState(true); - - // If there was no selectedIndex() for the previous initialization, or - // If we're doing a single selection, or a multiple selection (using cmd or ctrl), then initialize the anchor index to the listIndex that just got clicked. - if (listIndex >= 0 && (m_activeSelectionAnchorIndex < 0 || !shiftSelect)) - setActiveSelectionAnchorIndex(listIndex); - - setActiveSelectionEndIndex(listIndex); - updateListBoxSelection(!multiSelect); - - if (Frame* frame = document()->frame()) - frame->eventHandler()->setMouseDownMayStartAutoscroll(); - - evt->setDefaultHandled(); - } - } else if (evt->type() == eventNames().mouseupEvent && evt->isMouseEvent() && static_cast<MouseEvent*>(evt)->button() == LeftButton && document()->frame()->eventHandler()->autoscrollRenderer() != renderer()) - // This makes sure we fire onChange for a single click. For drag selection, onChange will fire when the autoscroll timer stops. - listBoxOnChange(); - else if (evt->type() == eventNames().keydownEvent) { - if (!evt->isKeyboardEvent()) - return; - String keyIdentifier = static_cast<KeyboardEvent*>(evt)->keyIdentifier(); - - int endIndex = 0; - if (m_activeSelectionEndIndex < 0) { - // Initialize the end index - if (keyIdentifier == "Down") - endIndex = nextSelectableListIndex(lastSelectedListIndex()); - else if (keyIdentifier == "Up") - endIndex = previousSelectableListIndex(optionToListIndex(selectedIndex())); - } else { - // Set the end index based on the current end index - if (keyIdentifier == "Down") - endIndex = nextSelectableListIndex(m_activeSelectionEndIndex); - else if (keyIdentifier == "Up") - endIndex = previousSelectableListIndex(m_activeSelectionEndIndex); - } - - if (keyIdentifier == "Down" || keyIdentifier == "Up") { - // Save the selection so it can be compared to the new selection when we call onChange immediately after making the new selection. - saveLastSelection(); - - ASSERT(endIndex >= 0 && (unsigned)endIndex < listItems().size()); - setActiveSelectionEndIndex(endIndex); - - // If the anchor is unitialized, or if we're going to deselect all other options, then set the anchor index equal to the end index. - bool deselectOthers = !multiple() || !static_cast<KeyboardEvent*>(evt)->shiftKey(); - if (m_activeSelectionAnchorIndex < 0 || deselectOthers) { - m_activeSelectionState = true; - if (deselectOthers) - deselectItems(); - setActiveSelectionAnchorIndex(m_activeSelectionEndIndex); - } - - static_cast<RenderListBox*>(renderer())->scrollToRevealElementAtListIndex(endIndex); - updateListBoxSelection(deselectOthers); - listBoxOnChange(); - evt->setDefaultHandled(); - } - } else if (evt->type() == eventNames().keypressEvent) { - if (!evt->isKeyboardEvent()) - return; - int keyCode = static_cast<KeyboardEvent*>(evt)->keyCode(); - - if (keyCode == '\r') { - if (form()) - form()->submitClick(evt); - evt->setDefaultHandled(); - return; - } - } + SelectElement::setActiveSelectionAnchorIndex(m_data, this, index); } -void HTMLSelectElement::setActiveSelectionAnchorIndex(int index) +void HTMLSelectElement::setActiveSelectionEndIndex(int index) { - m_activeSelectionAnchorIndex = index; - - // Cache the selection state so we can restore the old selection as the new selection pivots around this anchor index - const Vector<HTMLElement*>& items = listItems(); - m_cachedStateForActiveSelection.clear(); - for (unsigned i = 0; i < items.size(); i++) { - if (items[i]->hasLocalName(optionTag)) { - HTMLOptionElement* option = static_cast<HTMLOptionElement*>(items[i]); - m_cachedStateForActiveSelection.append(option->selected()); - } else - m_cachedStateForActiveSelection.append(false); - } + SelectElement::setActiveSelectionEndIndex(m_data, index); } void HTMLSelectElement::updateListBoxSelection(bool deselectOtherOptions) { - ASSERT(renderer() && renderer()->isListBox()); - - unsigned start; - unsigned end; - ASSERT(m_activeSelectionAnchorIndex >= 0); - start = min(m_activeSelectionAnchorIndex, m_activeSelectionEndIndex); - end = max(m_activeSelectionAnchorIndex, m_activeSelectionEndIndex); - - const Vector<HTMLElement*>& items = listItems(); - for (unsigned i = 0; i < items.size(); i++) { - if (items[i]->hasLocalName(optionTag)) { - HTMLOptionElement* option = static_cast<HTMLOptionElement*>(items[i]); - if (!option->disabled()) { - if (i >= start && i <= end) - option->setSelectedState(m_activeSelectionState); - else if (deselectOtherOptions || i >= m_cachedStateForActiveSelection.size()) - option->setSelectedState(false); - else - option->setSelectedState(m_cachedStateForActiveSelection[i]); - } - } - } - - scrollToSelection(); + SelectElement::updateListBoxSelection(m_data, this, deselectOtherOptions); } void HTMLSelectElement::menuListOnChange() { - ASSERT(usesMenuList()); - int selected = selectedIndex(); - if (m_lastOnChangeIndex != selected) { - m_lastOnChangeIndex = selected; - onChange(); - } + SelectElement::menuListOnChange(m_data, this); } void HTMLSelectElement::listBoxOnChange() { - ASSERT(!usesMenuList()); - - const Vector<HTMLElement*>& items = listItems(); - - // If the cached selection list is empty, or the size has changed, then fire onChange, and return early. - if (m_lastOnChangeSelection.isEmpty() || m_lastOnChangeSelection.size() != items.size()) { - onChange(); - return; - } - - // Update m_lastOnChangeSelection and fire onChange - bool fireOnChange = false; - for (unsigned i = 0; i < items.size(); i++) { - bool selected = false; - if (items[i]->hasLocalName(optionTag)) - selected = static_cast<HTMLOptionElement*>(items[i])->selected(); - if (selected != m_lastOnChangeSelection[i]) - fireOnChange = true; - m_lastOnChangeSelection[i] = selected; - } - if (fireOnChange) - onChange(); + SelectElement::listBoxOnChange(m_data, this); } void HTMLSelectElement::saveLastSelection() { - const Vector<HTMLElement*>& items = listItems(); - - if (usesMenuList()) { - m_lastOnChangeIndex = selectedIndex(); - return; - } - - m_lastOnChangeSelection.clear(); - for (unsigned i = 0; i < items.size(); i++) { - if (items[i]->hasLocalName(optionTag)) { - HTMLOptionElement* option = static_cast<HTMLOptionElement*>(items[i]); - m_lastOnChangeSelection.append(option->selected()); - } else - m_lastOnChangeSelection.append(false); - } -} - -static String stripLeadingWhiteSpace(const String& string) -{ - int length = string.length(); - int i; - for (i = 0; i < length; ++i) - if (string[i] != noBreakSpace && - (string[i] <= 0x7F ? !isASCIISpace(string[i]) : (direction(string[i]) != WhiteSpaceNeutral))) - break; - - return string.substring(i, length - i); -} - -void HTMLSelectElement::typeAheadFind(KeyboardEvent* event) -{ - if (event->timeStamp() < m_lastCharTime) - return; - - DOMTimeStamp delta = event->timeStamp() - m_lastCharTime; - - m_lastCharTime = event->timeStamp(); - - UChar c = event->charCode(); - - String prefix; - int searchStartOffset = 1; - if (delta > typeAheadTimeout) { - m_typedString = prefix = String(&c, 1); - m_repeatingChar = c; - } else { - m_typedString.append(c); - - if (c == m_repeatingChar) - // The user is likely trying to cycle through all the items starting with this character, so just search on the character - prefix = String(&c, 1); - else { - m_repeatingChar = 0; - prefix = m_typedString; - searchStartOffset = 0; - } - } - - const Vector<HTMLElement*>& items = listItems(); - int itemCount = items.size(); - if (itemCount < 1) - return; - - int selected = selectedIndex(); - int index = (optionToListIndex(selected >= 0 ? selected : 0) + searchStartOffset) % itemCount; - ASSERT(index >= 0); - for (int i = 0; i < itemCount; i++, index = (index + 1) % itemCount) { - if (!items[index]->hasTagName(optionTag) || items[index]->disabled()) - continue; - - String text = static_cast<HTMLOptionElement*>(items[index])->textIndentedToRespectGroupLabel(); - if (stripLeadingWhiteSpace(text).startsWith(prefix, false)) { - setSelectedIndex(listToOptionIndex(index)); - if(!usesMenuList()) - listBoxOnChange(); - setChanged(); - return; - } - } -} - -int HTMLSelectElement::nextSelectableListIndex(int startIndex) -{ - const Vector<HTMLElement*>& items = listItems(); - int index = startIndex + 1; - while (index >= 0 && (unsigned)index < items.size() && (!items[index]->hasLocalName(optionTag) || items[index]->disabled())) - index++; - if ((unsigned) index == items.size()) - return startIndex; - return index; -} - -int HTMLSelectElement::previousSelectableListIndex(int startIndex) -{ - const Vector<HTMLElement*>& items = listItems(); - if (startIndex == -1) - startIndex = items.size(); - int index = startIndex - 1; - while (index >= 0 && (unsigned)index < items.size() && (!items[index]->hasLocalName(optionTag) || items[index]->disabled())) - index--; - if (index == -1) - return startIndex; - return index; + SelectElement::saveLastSelection(m_data, this); } void HTMLSelectElement::accessKeyAction(bool sendToAnyElement) @@ -992,23 +341,8 @@ void HTMLSelectElement::accessKeyAction(bool sendToAnyElement) } void HTMLSelectElement::accessKeySetSelectedIndex(int index) -{ - // first bring into focus the list box - if (!focused()) - accessKeyAction(false); - - // if this index is already selected, unselect. otherwise update the selected index - Node* listNode = item(index); - if (listNode && listNode->hasTagName(optionTag)) { - HTMLOptionElement* listElement = static_cast<HTMLOptionElement*>(listNode); - if (listElement->selected()) - listElement->setSelectedState(false); - else - setSelectedIndex(index, false, true); - } - - listBoxOnChange(); - scrollToSelection(); +{ + SelectElement::accessKeySetSelectedIndex(m_data, this, index); } void HTMLSelectElement::setMultiple(bool multiple) @@ -1050,7 +384,7 @@ void HTMLSelectElement::setOption(unsigned index, HTMLOptionElement* option, Exc if (!ec) { add(option, before, ec); if (diff >= 0 && option->selected()) - setSelectedIndex(index, !m_multiple); + setSelectedIndex(index, !m_data.multiple()); } } @@ -1069,27 +403,29 @@ void HTMLSelectElement::setLength(unsigned newLen, ExceptionCode& ec) if (ec) break; } while (++diff); + } else { + const Vector<Element*>& items = listItems(); + + size_t optionIndex = 0; + for (size_t listIndex = 0; listIndex < items.size(); listIndex++) { + if (items[listIndex]->hasLocalName(optionTag) && optionIndex++ >= newLen) { + Element *item = items[listIndex]; + ASSERT(item->parentNode()); + item->parentNode()->removeChild(item, ec); + } + } } - else // remove elements - while (diff-- > 0) - remove(newLen); } void HTMLSelectElement::scrollToSelection() { - if (renderer() && !usesMenuList()) - static_cast<RenderListBox*>(renderer())->selectionChanged(); + SelectElement::scrollToSelection(m_data, this); } -#ifndef NDEBUG - -void HTMLSelectElement::checkListItems() const +void HTMLSelectElement::insertedIntoTree(bool deep) { - Vector<HTMLElement*> items = m_listItems; - recalcListItems(false); - ASSERT(items == m_listItems); + SelectElement::insertedIntoTree(m_data, this); + HTMLFormControlElementWithState::insertedIntoTree(deep); } -#endif - } // namespace diff --git a/WebCore/html/HTMLSelectElement.h b/WebCore/html/HTMLSelectElement.h index 59e4a4b..df7832c 100644 --- a/WebCore/html/HTMLSelectElement.h +++ b/WebCore/html/HTMLSelectElement.h @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,10 +24,9 @@ #ifndef HTMLSelectElement_h #define HTMLSelectElement_h -#include "Event.h" -#include "HTMLCollection.h" +#include "CollectionCache.h" #include "HTMLFormControlElement.h" -#include <wtf/Vector.h> +#include "SelectElement.h" namespace WebCore { @@ -35,77 +34,32 @@ class HTMLOptionElement; class HTMLOptionsCollection; class KeyboardEvent; -class HTMLSelectElement : public HTMLFormControlElementWithState { +class HTMLSelectElement : public HTMLFormControlElementWithState, public SelectElement { public: HTMLSelectElement(const QualifiedName&, Document*, HTMLFormElement* = 0); - virtual int tagPriority() const { return 6; } - virtual bool checkDTD(const Node* newChild); - - virtual const AtomicString& type() const; - - virtual bool isKeyboardFocusable(KeyboardEvent*) const; - virtual bool isMouseFocusable() const; - virtual bool canSelectAll() const; - virtual void selectAll(); - - virtual void recalcStyle(StyleChange); - - virtual void dispatchFocusEvent(); - virtual void dispatchBlurEvent(); - - virtual bool canStartSelection() const { return false; } - - int selectedIndex() const; - void setSelectedIndex(int index, bool deselect = true, bool fireOnChange = false); - int lastSelectedListIndex() const; - - virtual bool isEnumeratable() const { return true; } + virtual int selectedIndex() const; + virtual void setSelectedIndex(int index, bool deselect = true, bool fireOnChange = false); unsigned length() const; - int minWidth() const { return m_minwidth; } - - int size() const { return m_size; } - - bool multiple() const { return m_multiple; } + virtual int size() const { return m_data.size(); } + virtual bool multiple() const { return m_data.multiple(); } void add(HTMLElement* element, HTMLElement* before, ExceptionCode&); void remove(int index); String value(); void setValue(const String&); - - PassRefPtr<HTMLOptionsCollection> options(); - virtual bool saveState(String& value) const; - virtual void restoreState(const String&); + PassRefPtr<HTMLOptionsCollection> options(); virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); - virtual void parseMappedAttribute(MappedAttribute*); - - virtual RenderObject* createRenderer(RenderArena*, RenderStyle *); - virtual bool appendFormData(FormDataList&, bool); - - // get the actual listbox index of the optionIndexth option - int optionToListIndex(int optionIndex) const; - // reverse of optionToListIndex - get optionIndex from listboxIndex - int listToOptionIndex(int listIndex) const; - void setRecalcListItems(); - const Vector<HTMLElement*>& listItems() const - { - if (m_recalcListItems) - recalcListItems(); - else - checkListItems(); - return m_listItems; - } - virtual void reset(); + virtual const Vector<Element*>& listItems() const { return m_data.listItems(this); } - virtual void defaultEventHandler(Event*); virtual void accessKeyAction(bool sendToAnyElement); void accessKeySetSelectedIndex(int); @@ -119,64 +73,72 @@ public: Node* namedItem(const AtomicString& name); Node* item(unsigned index); - HTMLCollection::CollectionInfo* collectionInfo() { return &m_collectionInfo; } - - void setActiveSelectionAnchorIndex(int index); - void setActiveSelectionEndIndex(int index) { m_activeSelectionEndIndex = index; } - void updateListBoxSelection(bool deselectOtherOptions); - void listBoxOnChange(); - void menuListOnChange(); + CollectionCache* collectionInfo() { return &m_collectionInfo; } + + void scrollToSelection(); + +private: + virtual int tagPriority() const { return 6; } + virtual bool checkDTD(const Node* newChild); + + virtual const AtomicString& formControlType() const; - int activeSelectionStartListIndex() const; - int activeSelectionEndListIndex() const; + virtual bool isKeyboardFocusable(KeyboardEvent*) const; + virtual bool isMouseFocusable() const; + virtual bool canSelectAll() const; + virtual void selectAll(); + + virtual void recalcStyle(StyleChange); + + virtual void dispatchFocusEvent(); + virtual void dispatchBlurEvent(); - void scrollToSelection(); + virtual bool canStartSelection() const { return false; } + + virtual bool isEnumeratable() const { return true; } + + virtual bool saveFormControlState(String& value) const; + virtual void restoreFormControlState(const String&); + virtual void parseMappedAttribute(MappedAttribute*); + + virtual RenderObject* createRenderer(RenderArena*, RenderStyle *); + virtual bool appendFormData(FormDataList&, bool); + +#if PLATFORM(ANDROID) +public: + virtual int listToOptionIndex(int listIndex) const; + virtual int optionToListIndex(int optionIndex) const; private: +#else + virtual int listToOptionIndex(int listIndex) const; + virtual int optionToListIndex(int optionIndex) const; +#endif + + virtual void reset(); + + virtual void defaultEventHandler(Event*); + + virtual void setActiveSelectionAnchorIndex(int index); + virtual void setActiveSelectionEndIndex(int index); + virtual void updateListBoxSelection(bool deselectOtherOptions); + virtual void listBoxOnChange(); + virtual void menuListOnChange(); + + virtual int activeSelectionStartListIndex() const; + virtual int activeSelectionEndListIndex() const; + void recalcListItems(bool updateSelectedStates = true) const; - void checkListItems() const; void deselectItems(HTMLOptionElement* excludeElement = 0); -#ifdef ANDROID_LISTBOX_USES_MENU_LIST - bool usesMenuList() const { return true; } -#else - bool usesMenuList() const { return !m_multiple && m_size <= 1; } -#endif - int nextSelectableListIndex(int startIndex); - int previousSelectableListIndex(int startIndex); - void menuListDefaultEventHandler(Event*); - void listBoxDefaultEventHandler(Event*); void typeAheadFind(KeyboardEvent*); void saveLastSelection(); - mutable Vector<HTMLElement*> m_listItems; - Vector<bool> m_cachedStateForActiveSelection; - Vector<bool> m_lastOnChangeSelection; - int m_minwidth; - int m_size; - bool m_multiple; - mutable bool m_recalcListItems; - mutable int m_lastOnChangeIndex; - - int m_activeSelectionAnchorIndex; - int m_activeSelectionEndIndex; - bool m_activeSelectionState; - - // Instance variables for type-ahead find - UChar m_repeatingChar; - DOMTimeStamp m_lastCharTime; - String m_typedString; - - HTMLCollection::CollectionInfo m_collectionInfo; -}; + virtual void insertedIntoTree(bool); -#ifdef NDEBUG - -inline void HTMLSelectElement::checkListItems() const -{ -} - -#endif + SelectElementData m_data; + CollectionCache m_collectionInfo; +}; } // namespace diff --git a/WebCore/html/HTMLSelectElement.idl b/WebCore/html/HTMLSelectElement.idl index d3e85a8..fb08bb1 100644 --- a/WebCore/html/HTMLSelectElement.idl +++ b/WebCore/html/HTMLSelectElement.idl @@ -33,7 +33,7 @@ module html { attribute [ConvertNullToNullString] DOMString value; // Modified in DOM Level 2: -#if defined(LANGUAGE_OBJECTIVE_C) +#if defined(LANGUAGE_OBJECTIVE_C) && LANGUAGE_OBJECTIVE_C readonly attribute long length; #else attribute unsigned long length @@ -56,7 +56,7 @@ module html { in HTMLElement before) raises(DOMException); -#if defined(LANGUAGE_JAVASCRIPT) +#if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT // In JS, we support both options index and options object parameters - this cannot be autogenerated now. [Custom] void remove(/* 1 */); #else diff --git a/WebCore/html/HTMLSourceElement.cpp b/WebCore/html/HTMLSourceElement.cpp index 609bcbf..2f09997 100644 --- a/WebCore/html/HTMLSourceElement.cpp +++ b/WebCore/html/HTMLSourceElement.cpp @@ -28,6 +28,7 @@ #if ENABLE(VIDEO) #include "HTMLSourceElement.h" +#include "EventNames.h" #include "HTMLDocument.h" #include "HTMLMediaElement.h" #include "HTMLNames.h" @@ -40,6 +41,7 @@ using namespace HTMLNames; HTMLSourceElement::HTMLSourceElement(const QualifiedName& tagName, Document* doc) : HTMLElement(tagName, doc) + , m_errorEventTimer(this, &HTMLSourceElement::errorEventTimerFired) { ASSERT(hasTagName(sourceTag)); } @@ -88,5 +90,23 @@ void HTMLSourceElement::setType(const String& type) setAttribute(typeAttr, type); } +void HTMLSourceElement::scheduleErrorEvent() +{ + if (m_errorEventTimer.isActive()) + return; + + m_errorEventTimer.startOneShot(0); +} + +void HTMLSourceElement::cancelPendingErrorEvent() +{ + m_errorEventTimer.stop(); +} + +void HTMLSourceElement::errorEventTimerFired(Timer<HTMLSourceElement>*) +{ + dispatchEvent(eventNames().errorEvent, false, true); +} + } #endif diff --git a/WebCore/html/HTMLSourceElement.h b/WebCore/html/HTMLSourceElement.h index 9027b88..50d6687 100644 --- a/WebCore/html/HTMLSourceElement.h +++ b/WebCore/html/HTMLSourceElement.h @@ -29,6 +29,7 @@ #if ENABLE(VIDEO) #include "HTMLElement.h" +#include "Timer.h" #include <limits> namespace WebCore { @@ -51,6 +52,14 @@ public: void setSrc(const String&); void setMedia(const String&); void setType(const String&); + + void scheduleErrorEvent(); + void cancelPendingErrorEvent(); + +private: + void errorEventTimerFired(Timer<HTMLSourceElement>*); + + Timer<HTMLSourceElement> m_errorEventTimer; }; } //namespace diff --git a/WebCore/html/HTMLStyleElement.cpp b/WebCore/html/HTMLStyleElement.cpp index bed1cdc..f6b5924 100644 --- a/WebCore/html/HTMLStyleElement.cpp +++ b/WebCore/html/HTMLStyleElement.cpp @@ -20,11 +20,13 @@ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ + #include "config.h" #include "HTMLStyleElement.h" #include "Document.h" #include "HTMLNames.h" +#include "MappedAttribute.h" namespace WebCore { diff --git a/WebCore/html/HTMLStyleElement.idl b/WebCore/html/HTMLStyleElement.idl index e6238b7..a1b86f8 100644 --- a/WebCore/html/HTMLStyleElement.idl +++ b/WebCore/html/HTMLStyleElement.idl @@ -29,7 +29,7 @@ module html { attribute [ConvertNullToNullString] DOMString media; attribute [ConvertNullToNullString] DOMString type; -#if !defined(LANGUAGE_COM) +#if !defined(LANGUAGE_COM) || !LANGUAGE_COM // DOM Level 2 Style readonly attribute StyleSheet sheet; #endif diff --git a/WebCore/html/HTMLTableCaptionElement.cpp b/WebCore/html/HTMLTableCaptionElement.cpp index 35cf8a1..2c94727 100644 --- a/WebCore/html/HTMLTableCaptionElement.cpp +++ b/WebCore/html/HTMLTableCaptionElement.cpp @@ -21,11 +21,13 @@ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ + #include "config.h" #include "HTMLTableCaptionElement.h" #include "CSSPropertyNames.h" #include "HTMLNames.h" +#include "MappedAttribute.h" namespace WebCore { diff --git a/WebCore/html/HTMLTableCellElement.cpp b/WebCore/html/HTMLTableCellElement.cpp index 1313393..05f02c7 100644 --- a/WebCore/html/HTMLTableCellElement.cpp +++ b/WebCore/html/HTMLTableCellElement.cpp @@ -23,6 +23,7 @@ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ + #include "config.h" #include "HTMLTableCellElement.h" @@ -30,6 +31,7 @@ #include "CSSValueKeywords.h" #include "HTMLNames.h" #include "HTMLTableElement.h" +#include "MappedAttribute.h" #include "RenderTableCell.h" #ifdef ANDROID_LAYOUT #include "Document.h" diff --git a/WebCore/html/HTMLTableColElement.cpp b/WebCore/html/HTMLTableColElement.cpp index 11f6df6..ae18ab1 100644 --- a/WebCore/html/HTMLTableColElement.cpp +++ b/WebCore/html/HTMLTableColElement.cpp @@ -23,13 +23,15 @@ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ + #include "config.h" #include "HTMLTableColElement.h" #include "CSSPropertyNames.h" #include "HTMLNames.h" -#include "RenderTableCol.h" #include "HTMLTableElement.h" +#include "MappedAttribute.h" +#include "RenderTableCol.h" #include "Text.h" namespace WebCore { diff --git a/WebCore/html/HTMLTableElement.cpp b/WebCore/html/HTMLTableElement.cpp index bb2c2ee..e37c171 100644 --- a/WebCore/html/HTMLTableElement.cpp +++ b/WebCore/html/HTMLTableElement.cpp @@ -31,9 +31,10 @@ #include "ExceptionCode.h" #include "HTMLNames.h" #include "HTMLTableCaptionElement.h" -#include "HTMLTableRowsCollection.h" #include "HTMLTableRowElement.h" +#include "HTMLTableRowsCollection.h" #include "HTMLTableSectionElement.h" +#include "MappedAttribute.h" #include "RenderTable.h" #include "Text.h" @@ -310,7 +311,7 @@ static bool setTableCellsChanged(Node* n) } if (cellChanged) - n->setChanged(); + n->setNeedsStyleRecalc(); return cellChanged; } @@ -455,7 +456,7 @@ void HTMLTableElement::parseMappedAttribute(MappedAttribute* attr) for (Node* child = firstChild(); child; child = child->nextSibling()) cellChanged |= setTableCellsChanged(child); if (cellChanged) - setChanged(); + setNeedsStyleRecalc(); } } @@ -655,7 +656,7 @@ PassRefPtr<HTMLCollection> HTMLTableElement::rows() PassRefPtr<HTMLCollection> HTMLTableElement::tBodies() { - return HTMLCollection::create(this, HTMLCollection::TableTBodies); + return HTMLCollection::create(this, TableTBodies); } String HTMLTableElement::align() const diff --git a/WebCore/html/HTMLTablePartElement.cpp b/WebCore/html/HTMLTablePartElement.cpp index 6341197..19babf6 100644 --- a/WebCore/html/HTMLTablePartElement.cpp +++ b/WebCore/html/HTMLTablePartElement.cpp @@ -23,6 +23,7 @@ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ + #include "config.h" #include "HTMLTablePartElement.h" @@ -31,6 +32,7 @@ #include "CSSValueKeywords.h" #include "Document.h" #include "HTMLNames.h" +#include "MappedAttribute.h" namespace WebCore { diff --git a/WebCore/html/HTMLTableRowElement.cpp b/WebCore/html/HTMLTableRowElement.cpp index 98d928a..94be02e 100644 --- a/WebCore/html/HTMLTableRowElement.cpp +++ b/WebCore/html/HTMLTableRowElement.cpp @@ -168,7 +168,7 @@ void HTMLTableRowElement::deleteCell(int index, ExceptionCode& ec) PassRefPtr<HTMLCollection> HTMLTableRowElement::cells() { - return HTMLCollection::create(this, HTMLCollection::TRCells); + return HTMLCollection::create(this, TRCells); } void HTMLTableRowElement::setCells(HTMLCollection *, ExceptionCode& ec) diff --git a/WebCore/html/HTMLTableRowsCollection.cpp b/WebCore/html/HTMLTableRowsCollection.cpp index 7047576..b38c271 100644 --- a/WebCore/html/HTMLTableRowsCollection.cpp +++ b/WebCore/html/HTMLTableRowsCollection.cpp @@ -149,7 +149,7 @@ HTMLTableRowElement* HTMLTableRowsCollection::lastRow(HTMLTableElement* table) } HTMLTableRowsCollection::HTMLTableRowsCollection(PassRefPtr<HTMLTableElement> table) - : HTMLCollection(table, Other, 0) + : HTMLCollection(table, OtherCollection, 0) { } diff --git a/WebCore/html/HTMLTableSectionElement.cpp b/WebCore/html/HTMLTableSectionElement.cpp index 900976c..e91a96a 100644 --- a/WebCore/html/HTMLTableSectionElement.cpp +++ b/WebCore/html/HTMLTableSectionElement.cpp @@ -167,7 +167,7 @@ void HTMLTableSectionElement::setVAlign(const String &value) PassRefPtr<HTMLCollection> HTMLTableSectionElement::rows() { - return HTMLCollection::create(this, HTMLCollection::TSectionRows); + return HTMLCollection::create(this, TSectionRows); } } diff --git a/WebCore/html/HTMLTagNames.in b/WebCore/html/HTMLTagNames.in index 8b1fa2b..14119ef 100644 --- a/WebCore/html/HTMLTagNames.in +++ b/WebCore/html/HTMLTagNames.in @@ -8,9 +8,7 @@ acronym interfaceName=HTMLElement address interfaceName=HTMLElement applet area -#if ENABLE_VIDEO -audio wrapperOnlyIfMediaIsAvailable -#endif +audio wrapperOnlyIfMediaIsAvailable,conditional=VIDEO b interfaceName=HTMLElement base basefont interfaceName=HTMLBaseFontElement @@ -39,7 +37,7 @@ embed fieldset interfaceName=HTMLFieldSetElement, constructorNeedsFormElement font form -frame constructorNeedsCreatedByParser +frame frameset interfaceName=HTMLFrameSetElement head h1 interfaceName=HTMLHeadingElement @@ -51,7 +49,7 @@ h6 interfaceName=HTMLHeadingElement hr interfaceName=HTMLHRElement html i interfaceName=HTMLElement -iframe interfaceName=HTMLIFrameElement, constructorNeedsCreatedByParser +iframe interfaceName=HTMLIFrameElement image mapToTagName=img img interfaceName=HTMLImageElement, constructorNeedsFormElement input constructorNeedsFormElement @@ -73,7 +71,11 @@ nobr interfaceName=HTMLElement noembed interfaceName=HTMLElement noframes interfaceName=HTMLElement nolayer interfaceName=HTMLElement +#if ENABLE_XHTMLMP +noscript interfaceName=HTMLNoScriptElement +#else noscript interfaceName=HTMLElement +#endif object constructorNeedsCreatedByParser ol interfaceName=HTMLOListElement optgroup interfaceName=HTMLOptGroupElement, constructorNeedsFormElement @@ -88,9 +90,7 @@ samp interfaceName=HTMLElement script constructorNeedsCreatedByParser select constructorNeedsFormElement small interfaceName=HTMLElement -#if ENABLE_VIDEO -source wrapperOnlyIfMediaIsAvailable -#endif +source wrapperOnlyIfMediaIsAvailable,conditional=VIDEO span interfaceName=HTMLElement strike interfaceName=HTMLElement strong interfaceName=HTMLElement @@ -110,8 +110,6 @@ tt interfaceName=HTMLElement u interfaceName=HTMLElement ul interfaceName=HTMLUListElement var interfaceName=HTMLElement -#if ENABLE_VIDEO -video wrapperOnlyIfMediaIsAvailable -#endif +video wrapperOnlyIfMediaIsAvailable,conditional=VIDEO wbr interfaceName=HTMLElement xmp interfaceName=HTMLPreElement diff --git a/WebCore/html/HTMLTextAreaElement.cpp b/WebCore/html/HTMLTextAreaElement.cpp index 4eec088..41a0126 100644 --- a/WebCore/html/HTMLTextAreaElement.cpp +++ b/WebCore/html/HTMLTextAreaElement.cpp @@ -34,11 +34,13 @@ #include "FormDataList.h" #include "Frame.h" #include "HTMLNames.h" +#include "MappedAttribute.h" #include "Page.h" #include "RenderStyle.h" #include "RenderTextControlMultiLine.h" -#include "VisibleSelection.h" +#include "ScriptEventListener.h" #include "Text.h" +#include "VisibleSelection.h" #include <wtf/StdLibExtras.h> #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS @@ -69,23 +71,23 @@ HTMLTextAreaElement::HTMLTextAreaElement(const QualifiedName& tagName, Document* , m_cachedSelectionEnd(-1) { ASSERT(hasTagName(textareaTag)); - setValueMatchesRenderer(); + setFormControlValueMatchesRenderer(true); notifyFormStateChanged(this); } -const AtomicString& HTMLTextAreaElement::type() const +const AtomicString& HTMLTextAreaElement::formControlType() const { DEFINE_STATIC_LOCAL(const AtomicString, textarea, ("textarea")); return textarea; } -bool HTMLTextAreaElement::saveState(String& result) const +bool HTMLTextAreaElement::saveFormControlState(String& result) const { result = value(); return true; } -void HTMLTextAreaElement::restoreState(const String& state) +void HTMLTextAreaElement::restoreFormControlState(const String& state) { setDefaultValue(state); } @@ -183,13 +185,13 @@ void HTMLTextAreaElement::parseMappedAttribute(MappedAttribute* attr) // Don't map 'align' attribute. This matches what Firefox, Opera and IE do. // See http://bugs.webkit.org/show_bug.cgi?id=7075 } else if (attr->name() == onfocusAttr) - setInlineEventListenerForTypeAndAttribute(eventNames().focusEvent, attr); + setAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(this, attr)); else if (attr->name() == onblurAttr) - setInlineEventListenerForTypeAndAttribute(eventNames().blurEvent, attr); + setAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(this, attr)); else if (attr->name() == onselectAttr) - setInlineEventListenerForTypeAndAttribute(eventNames().selectEvent, attr); + setAttributeEventListener(eventNames().selectEvent, createAttributeEventListener(this, attr)); else if (attr->name() == onchangeAttr) - setInlineEventListenerForTypeAndAttribute(eventNames().changeEvent, attr); + setAttributeEventListener(eventNames().changeEvent, createAttributeEventListener(this, attr)); else HTMLFormControlElementWithState::parseMappedAttribute(attr); } @@ -268,12 +270,12 @@ void HTMLTextAreaElement::rendererWillBeDestroyed() void HTMLTextAreaElement::updateValue() const { - if (valueMatchesRenderer()) + if (formControlValueMatchesRenderer()) return; ASSERT(renderer()); m_value = toRenderTextControl(renderer())->text(); - const_cast<HTMLTextAreaElement*>(this)->setValueMatchesRenderer(); + const_cast<HTMLTextAreaElement*>(this)->setFormControlValueMatchesRenderer(true); notifyFormStateChanged(this); } @@ -297,9 +299,9 @@ void HTMLTextAreaElement::setValue(const String& value) return; m_value = normalizedValue; - setValueMatchesRenderer(); + setFormControlValueMatchesRenderer(true); if (inDocument()) - document()->updateRendering(); + document()->updateStyleIfNeeded(); if (renderer()) renderer()->updateFromElement(); @@ -313,7 +315,7 @@ void HTMLTextAreaElement::setValue(const String& value) setSelectionRange(endOfString, endOfString); } - setChanged(); + setNeedsStyleRecalc(); notifyFormStateChanged(this); } diff --git a/WebCore/html/HTMLTextAreaElement.h b/WebCore/html/HTMLTextAreaElement.h index f78386c..e22b5d5 100644 --- a/WebCore/html/HTMLTextAreaElement.h +++ b/WebCore/html/HTMLTextAreaElement.h @@ -43,14 +43,14 @@ public: virtual bool isEnumeratable() const { return true; } - virtual const AtomicString& type() const; + virtual const AtomicString& formControlType() const; - virtual bool saveState(String& value) const; - virtual void restoreState(const String&); + virtual bool saveFormControlState(String& value) const; + virtual void restoreFormControlState(const String&); - bool readOnly() const { return isReadOnlyControl(); } + bool readOnly() const { return isReadOnlyFormControl(); } - virtual bool isTextControl() const { return true; } + virtual bool isTextFormControl() const { return true; } int selectionStart(); int selectionEnd(); diff --git a/WebCore/html/HTMLTokenizer.cpp b/WebCore/html/HTMLTokenizer.cpp index e4952f7..25e9adf 100644 --- a/WebCore/html/HTMLTokenizer.cpp +++ b/WebCore/html/HTMLTokenizer.cpp @@ -7,6 +7,7 @@ (C) 2001 Dirk Mueller (mueller@kde.org) Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. Copyright (C) 2005, 2006 Alexey Proskuryakov (ap@nypop.com) + Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -40,6 +41,7 @@ #include "HTMLParser.h" #include "HTMLScriptElement.h" #include "HTMLViewSourceDocument.h" +#include "MappedAttribute.h" #include "Page.h" #include "PreloadScanner.h" #include "ScriptController.h" @@ -449,6 +451,10 @@ HTMLTokenizer::State HTMLTokenizer::scriptHandler(State state) } else { // Parse m_scriptCode containing <script> info doScriptExec = m_scriptNode->shouldExecuteAsJavaScript(); +#if ENABLE(XHTMLMP) + if (!doScriptExec) + m_doc->setShouldProcessNoscriptElement(true); +#endif m_scriptNode = 0; } } @@ -1884,7 +1890,7 @@ PassRefPtr<Node> HTMLTokenizer::processToken() ScriptController* scriptController = (!m_fragment && m_doc->frame()) ? m_doc->frame()->script() : 0; if (scriptController && scriptController->isEnabled()) // FIXME: Why isn't this m_currentScriptTagStartLineNumber? I suspect this is wrong. - scriptController->setEventHandlerLineno(m_currentTagStartLineNumber + 1); // Script line numbers are 1 based. + scriptController->setEventHandlerLineNumber(m_currentTagStartLineNumber + 1); // Script line numbers are 1 based. if (m_dest > m_buffer) { m_currentToken.text = StringImpl::createStrippingNullCharacters(m_buffer, m_dest - m_buffer); if (m_currentToken.tagName != commentAtom) @@ -1892,7 +1898,7 @@ PassRefPtr<Node> HTMLTokenizer::processToken() } else if (m_currentToken.tagName == nullAtom) { m_currentToken.reset(); if (scriptController) - scriptController->setEventHandlerLineno(m_lineNumber + 1); // Script line numbers are 1 based. + scriptController->setEventHandlerLineNumber(m_lineNumber + 1); // Script line numbers are 1 based. return 0; } @@ -1911,7 +1917,7 @@ PassRefPtr<Node> HTMLTokenizer::processToken() } m_currentToken.reset(); if (scriptController) - scriptController->setEventHandlerLineno(0); + scriptController->setEventHandlerLineNumber(0); return n.release(); } @@ -1933,7 +1939,16 @@ HTMLTokenizer::~HTMLTokenizer() void HTMLTokenizer::enlargeBuffer(int len) { - int newSize = max(m_bufferSize * 2, m_bufferSize + len); + // Resize policy: Always at least double the size of the buffer each time. + int delta = max(len, m_bufferSize); + + // Check for overflow. + // For now, handle overflow the same way we handle fastRealloc failure, with CRASH. + static const int maxSize = INT_MAX / sizeof(UChar); + if (delta > maxSize - m_bufferSize) + CRASH(); + + int newSize = m_bufferSize + delta; int oldOffset = m_dest - m_buffer; m_buffer = static_cast<UChar*>(fastRealloc(m_buffer, newSize * sizeof(UChar))); m_dest = m_buffer + oldOffset; @@ -1942,7 +1957,16 @@ void HTMLTokenizer::enlargeBuffer(int len) void HTMLTokenizer::enlargeScriptBuffer(int len) { - int newSize = max(m_scriptCodeCapacity * 2, m_scriptCodeCapacity + len); + // Resize policy: Always at least double the size of the buffer each time. + int delta = max(len, m_scriptCodeCapacity); + + // Check for overflow. + // For now, handle overflow the same way we handle fastRealloc failure, with CRASH. + static const int maxSize = INT_MAX / sizeof(UChar); + if (delta > maxSize - m_scriptCodeCapacity) + CRASH(); + + int newSize = m_scriptCodeCapacity + delta; m_scriptCode = static_cast<UChar*>(fastRealloc(m_scriptCode, newSize * sizeof(UChar))); m_scriptCodeCapacity = newSize; } @@ -1992,11 +2016,15 @@ void HTMLTokenizer::notifyFinished(CachedResource*) #endif if (errorOccurred) - n->dispatchEventForType(eventNames().errorEvent, true, false); + n->dispatchEvent(eventNames().errorEvent, true, false); else { if (static_cast<HTMLScriptElement*>(n.get())->shouldExecuteAsJavaScript()) m_state = scriptExecution(sourceCode, m_state); - n->dispatchEventForType(eventNames().loadEvent, false, false); +#if ENABLE(XHTMLMP) + else + m_doc->setShouldProcessNoscriptElement(true); +#endif + n->dispatchEvent(eventNames().loadEvent, false, false); } // The state of m_pendingScripts.isEmpty() can change inside the scriptExecution() diff --git a/WebCore/html/HTMLUListElement.cpp b/WebCore/html/HTMLUListElement.cpp index c1a7644..f36cb57 100644 --- a/WebCore/html/HTMLUListElement.cpp +++ b/WebCore/html/HTMLUListElement.cpp @@ -18,11 +18,13 @@ * Boston, MA 02110-1301, USA. * */ + #include "config.h" #include "HTMLUListElement.h" #include "CSSPropertyNames.h" #include "HTMLNames.h" +#include "MappedAttribute.h" namespace WebCore { diff --git a/WebCore/html/HTMLVideoElement.cpp b/WebCore/html/HTMLVideoElement.cpp index b0aac3c..d465b73 100644 --- a/WebCore/html/HTMLVideoElement.cpp +++ b/WebCore/html/HTMLVideoElement.cpp @@ -33,6 +33,7 @@ #include "Document.h" #include "HTMLImageLoader.h" #include "HTMLNames.h" +#include "MappedAttribute.h" #include "RenderImage.h" #include "RenderVideo.h" diff --git a/WebCore/html/HTMLViewSourceDocument.cpp b/WebCore/html/HTMLViewSourceDocument.cpp index 596f16e..d4d6df7 100644 --- a/WebCore/html/HTMLViewSourceDocument.cpp +++ b/WebCore/html/HTMLViewSourceDocument.cpp @@ -26,18 +26,19 @@ #include "HTMLViewSourceDocument.h" #include "DOMImplementation.h" -#include "HTMLTokenizer.h" -#include "HTMLHtmlElement.h" #include "HTMLAnchorElement.h" #include "HTMLBodyElement.h" #include "HTMLDivElement.h" -#include "HTMLTableElement.h" +#include "HTMLHtmlElement.h" +#include "HTMLNames.h" #include "HTMLTableCellElement.h" +#include "HTMLTableElement.h" #include "HTMLTableRowElement.h" #include "HTMLTableSectionElement.h" +#include "HTMLTokenizer.h" +#include "MappedAttribute.h" #include "Text.h" #include "TextDocument.h" -#include "HTMLNames.h" namespace WebCore { @@ -150,6 +151,17 @@ void HTMLViewSourceDocument::addViewSourceToken(Token* token) m_current = static_cast<Element*>(m_current->parent()); } else { const String& value = attr->value().string(); + + // Compare ignoring case since HTMLTokenizer doesn't + // lower names when passing in tokens to + // HTMLViewSourceDocument. + if (equalIgnoringCase(token->tagName, "base") && equalIgnoringCase(attr->name().localName(), "href")) { + // Catch the href attribute in the base element. + // It will be used for rendering anchors created + // by addLink() below. + setBaseElementURL(KURL(url(), value)); + } + // FIXME: XML could use namespace prefixes and confuse us. if (equalIgnoringCase(attr->name().localName(), "src") || equalIgnoringCase(attr->name().localName(), "href")) m_current = addLink(value, equalIgnoringCase(token->tagName, "a")); diff --git a/WebCore/html/ImageData.idl b/WebCore/html/ImageData.idl index 9be14ff..7f37b52 100644 --- a/WebCore/html/ImageData.idl +++ b/WebCore/html/ImageData.idl @@ -34,7 +34,7 @@ module html { ] ImageData { readonly attribute long width; readonly attribute long height; -#if !defined(LANGUAGE_JAVASCRIPT) || defined(V8_BINDING) +#if !defined(LANGUAGE_JAVASCRIPT) || !LANGUAGE_JAVASCRIPT || defined(V8_BINDING) && V8_BINDING readonly attribute CanvasPixelArray data; #endif }; diff --git a/WebCore/html/MediaError.h b/WebCore/html/MediaError.h index 7dcf72a..5e77d9e 100644 --- a/WebCore/html/MediaError.h +++ b/WebCore/html/MediaError.h @@ -34,7 +34,7 @@ namespace WebCore { class MediaError : public RefCounted<MediaError> { public: - enum Code { MEDIA_ERR_ABORTED = 1, MEDIA_ERR_NETWORK, MEDIA_ERR_DECODE, MEDIA_ERR_NONE_SUPPORTED }; + enum Code { MEDIA_ERR_ABORTED = 1, MEDIA_ERR_NETWORK, MEDIA_ERR_DECODE, MEDIA_ERR_SRC_NOT_SUPPORTED }; static PassRefPtr<MediaError> create(Code code) { return adoptRef(new MediaError(code)); } diff --git a/WebCore/html/MediaError.idl b/WebCore/html/MediaError.idl index 162170f..4dcea7d 100644 --- a/WebCore/html/MediaError.idl +++ b/WebCore/html/MediaError.idl @@ -28,7 +28,7 @@ module html { const unsigned short MEDIA_ERR_ABORTED = 1; const unsigned short MEDIA_ERR_NETWORK = 2; const unsigned short MEDIA_ERR_DECODE = 3; - const unsigned short MEDIA_ERR_NONE_SUPPORTED = 4; + const unsigned short MEDIA_ERR_SRC_NOT_SUPPORTED = 4; readonly attribute unsigned short code; }; } diff --git a/WebCore/html/PreloadScanner.cpp b/WebCore/html/PreloadScanner.cpp index 782e9bd..1c1d28a 100644 --- a/WebCore/html/PreloadScanner.cpp +++ b/WebCore/html/PreloadScanner.cpp @@ -44,7 +44,8 @@ #include <wtf/CurrentTime.h> #include <wtf/unicode/Unicode.h> -#if COMPILER(GCC) +// Use __GNUC__ instead of PLATFORM(GCC) to stay consistent with the gperf generated c file +#ifdef __GNUC__ // The main tokenizer includes this too so we are getting two copies of the data. However, this way the code gets inlined. #include "HTMLEntityNames.c" #else @@ -225,8 +226,8 @@ unsigned PreloadScanner::consumeEntity(SegmentedString& source, bool& notEnoughC else if (cc >= 'A' && cc <= 'F') result = 10 + cc - 'A'; else { - source.push(seenChars[1]); source.push('#'); + source.push(seenChars[1]); return 0; } entityState = Hex; @@ -280,8 +281,8 @@ unsigned PreloadScanner::consumeEntity(SegmentedString& source, bool& notEnoughC if (seenChars.size() == 2) source.push(seenChars[0]); else if (seenChars.size() == 3) { - source.push(seenChars[1]); source.push(seenChars[0]); + source.push(seenChars[1]); } else source.prepend(SegmentedString(String(seenChars.data(), seenChars.size() - 1))); return 0; diff --git a/WebCore/html/TimeRanges.cpp b/WebCore/html/TimeRanges.cpp index ad81ac8..e5b070d 100644 --- a/WebCore/html/TimeRanges.cpp +++ b/WebCore/html/TimeRanges.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,6 +34,17 @@ TimeRanges::TimeRanges(float start, float end) add(start, end); } +PassRefPtr<TimeRanges> TimeRanges::copy() +{ + RefPtr<TimeRanges> newSession = TimeRanges::create(); + + unsigned size = m_ranges.size(); + for (unsigned i = 0; i < size; i++) + newSession->add(m_ranges[i].m_start, m_ranges[i].m_end); + + return newSession.release(); +} + float TimeRanges::start(unsigned index, ExceptionCode& ec) const { if (index >= length()) { @@ -53,9 +64,46 @@ float TimeRanges::end(unsigned index, ExceptionCode& ec) const } void TimeRanges::add(float start, float end) -{ - m_ranges.append(Range(start, end)); - // FIXME normalize +{ + ASSERT(start <= end); + unsigned int overlappingArcIndex; + Range addedRange(start, end); + + // For each present range check if we need to: + // - merge with the added range, in case we are overlapping or contiguous + // - Need to insert in place, we we are completely, not overlapping and not contiguous + // in between two ranges. + // + // TODO: Given that we assume that ranges are correctly ordered, this could be optimized. + + for (overlappingArcIndex = 0; overlappingArcIndex < m_ranges.size(); overlappingArcIndex++) { + if (addedRange.isOverlappingRange(m_ranges[overlappingArcIndex]) + || addedRange.isContiguousWithRange(m_ranges[overlappingArcIndex])) { + // We need to merge the addedRange and that range. + addedRange = addedRange.unionWithOverlappingOrContiguousRange(m_ranges[overlappingArcIndex]); + m_ranges.remove(overlappingArcIndex); + overlappingArcIndex--; + } else { + // Check the case for which there is no more to do + if (!overlappingArcIndex) { + if (addedRange.isBeforeRange(m_ranges[0])) { + // First index, and we are completely before that range (and not contiguous, nor overlapping). + // We just need to be inserted here. + break; + } + } else { + if (m_ranges[overlappingArcIndex - 1].isBeforeRange(addedRange) + && addedRange.isBeforeRange(m_ranges[overlappingArcIndex])) { + // We are exactly after the current previous range, and before the current range, while + // not overlapping with none of them. Insert here. + break; + } + } + } + } + + // Now that we are sure we don't overlap with any range, just add it. + m_ranges.insert(overlappingArcIndex, addedRange); } bool TimeRanges::contain(float time) const diff --git a/WebCore/html/TimeRanges.h b/WebCore/html/TimeRanges.h index eb54f6b..37820dc 100644 --- a/WebCore/html/TimeRanges.h +++ b/WebCore/html/TimeRanges.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,6 +27,8 @@ #define TimeRanges_h #include "ExceptionCode.h" + +#include <algorithm> #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> #include <wtf/Vector.h> @@ -44,6 +46,8 @@ public: return adoptRef(new TimeRanges(start, end)); } + PassRefPtr<TimeRanges> copy(); + unsigned length() const { return m_ranges.size(); } float start(unsigned index, ExceptionCode&) const; float end(unsigned index, ExceptionCode&) const; @@ -55,7 +59,9 @@ public: private: TimeRanges() { } TimeRanges(float start, float end); - + TimeRanges(const TimeRanges&); + + // We consider all the Ranges to be semi-bounded as follow: [start, end[ struct Range { Range() { } Range(float start, float end) { @@ -64,6 +70,36 @@ private: } float m_start; float m_end; + + inline bool isPointInRange(float point) const + { + return m_start <= point && point < m_end; + } + + inline bool isOverlappingRange(const Range& range) const + { + return isPointInRange(range.m_start) || isPointInRange(range.m_end) || range.isPointInRange(m_start); + } + + inline bool isContiguousWithRange(const Range& range) const + { + return range.m_start == m_end || range.m_end == m_start; + } + + inline Range unionWithOverlappingOrContiguousRange(const Range& range) const + { + Range ret; + + ret.m_start = std::min(m_start, range.m_start); + ret.m_end = std::max(m_end, range.m_end); + + return ret; + } + + inline bool isBeforeRange(const Range& range) const + { + return range.m_start >= m_end; + } }; Vector<Range> m_ranges; |