summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/html
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2011-05-24 11:24:40 +0100
committerBen Murdoch <benm@google.com>2011-06-02 09:53:15 +0100
commit81bc750723a18f21cd17d1b173cd2a4dda9cea6e (patch)
tree7a9e5ed86ff429fd347a25153107221543909b19 /Source/WebCore/html
parent94088a6d336c1dd80a1e734af51e96abcbb689a7 (diff)
downloadexternal_webkit-81bc750723a18f21cd17d1b173cd2a4dda9cea6e.zip
external_webkit-81bc750723a18f21cd17d1b173cd2a4dda9cea6e.tar.gz
external_webkit-81bc750723a18f21cd17d1b173cd2a4dda9cea6e.tar.bz2
Merge WebKit at r80534: Intial merge by Git
Change-Id: Ia7a83357124c9e1cdb1debf55d9661ec0bd09a61
Diffstat (limited to 'Source/WebCore/html')
-rw-r--r--Source/WebCore/html/HTMLAttributeNames.in2
-rw-r--r--Source/WebCore/html/HTMLBodyElement.cpp9
-rw-r--r--Source/WebCore/html/HTMLCanvasElement.cpp2
-rw-r--r--Source/WebCore/html/HTMLElement.cpp155
-rw-r--r--Source/WebCore/html/HTMLElement.h10
-rw-r--r--Source/WebCore/html/HTMLElementsAllInOne.cpp1
-rw-r--r--Source/WebCore/html/HTMLFormControlElement.cpp22
-rw-r--r--Source/WebCore/html/HTMLFormControlElement.h7
-rw-r--r--Source/WebCore/html/HTMLImageLoader.cpp4
-rw-r--r--Source/WebCore/html/HTMLInputElement.cpp36
-rw-r--r--Source/WebCore/html/HTMLInputElement.h10
-rw-r--r--Source/WebCore/html/HTMLMediaElement.cpp66
-rw-r--r--Source/WebCore/html/HTMLMediaElement.h33
-rw-r--r--Source/WebCore/html/HTMLMediaElement.idl4
-rw-r--r--Source/WebCore/html/HTMLScriptElement.cpp19
-rw-r--r--Source/WebCore/html/HTMLScriptElement.h4
-rw-r--r--Source/WebCore/html/HTMLSummaryElement.cpp41
-rw-r--r--Source/WebCore/html/HTMLSummaryElement.h38
-rw-r--r--Source/WebCore/html/HTMLTagNames.in2
-rw-r--r--Source/WebCore/html/HTMLVideoElement.cpp10
-rw-r--r--Source/WebCore/html/HTMLVideoElement.h4
-rw-r--r--Source/WebCore/html/HTMLVideoElement.idl4
-rw-r--r--Source/WebCore/html/HTMLViewSourceDocument.cpp2
-rw-r--r--Source/WebCore/html/ImageDocument.cpp6
-rw-r--r--Source/WebCore/html/ImageDocument.h2
-rw-r--r--Source/WebCore/html/InputType.cpp5
-rw-r--r--Source/WebCore/html/InputType.h2
-rw-r--r--Source/WebCore/html/NumberInputType.cpp53
-rw-r--r--Source/WebCore/html/NumberInputType.h2
-rw-r--r--Source/WebCore/html/TextFieldInputType.cpp2
-rw-r--r--Source/WebCore/html/ValidationMessage.cpp5
-rw-r--r--Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp11
-rw-r--r--Source/WebCore/html/canvas/Int32Array.h4
-rw-r--r--Source/WebCore/html/canvas/Int8Array.h4
-rw-r--r--Source/WebCore/html/canvas/IntegralTypedArrayBase.h8
-rw-r--r--Source/WebCore/html/canvas/OESVertexArrayObject.cpp116
-rw-r--r--Source/WebCore/html/canvas/OESVertexArrayObject.h63
-rw-r--r--Source/WebCore/html/canvas/OESVertexArrayObject.idl35
-rw-r--r--Source/WebCore/html/canvas/Uint16Array.h4
-rw-r--r--Source/WebCore/html/canvas/Uint32Array.h4
-rw-r--r--Source/WebCore/html/canvas/Uint8Array.h4
-rw-r--r--Source/WebCore/html/canvas/WebGLExtension.h1
-rw-r--r--Source/WebCore/html/canvas/WebGLGetInfo.cpp13
-rw-r--r--Source/WebCore/html/canvas/WebGLGetInfo.h7
-rw-r--r--Source/WebCore/html/canvas/WebGLRenderingContext.cpp218
-rw-r--r--Source/WebCore/html/canvas/WebGLRenderingContext.h48
-rw-r--r--Source/WebCore/html/canvas/WebGLVertexArrayObjectOES.cpp74
-rw-r--r--Source/WebCore/html/canvas/WebGLVertexArrayObjectOES.h98
-rw-r--r--Source/WebCore/html/canvas/WebGLVertexArrayObjectOES.idl29
-rw-r--r--Source/WebCore/html/canvas/WebKitLoseContext.cpp3
-rw-r--r--Source/WebCore/html/canvas/WebKitLoseContext.h1
-rw-r--r--Source/WebCore/html/parser/HTMLConstructionSite.cpp65
-rw-r--r--Source/WebCore/html/parser/HTMLConstructionSite.h2
-rw-r--r--Source/WebCore/html/parser/HTMLDocumentParser.cpp126
-rw-r--r--Source/WebCore/html/parser/HTMLDocumentParser.h10
-rw-r--r--Source/WebCore/html/parser/HTMLElementStack.cpp184
-rw-r--r--Source/WebCore/html/parser/HTMLElementStack.h29
-rw-r--r--Source/WebCore/html/parser/HTMLParserScheduler.cpp15
-rw-r--r--Source/WebCore/html/parser/HTMLParserScheduler.h39
-rw-r--r--Source/WebCore/html/parser/HTMLScriptRunner.cpp49
-rw-r--r--Source/WebCore/html/parser/HTMLTreeBuilder.cpp133
-rw-r--r--Source/WebCore/html/parser/HTMLTreeBuilder.h5
-rw-r--r--Source/WebCore/html/parser/NestingLevelIncrementer.h2
-rw-r--r--Source/WebCore/html/parser/XSSFilter.cpp22
-rw-r--r--Source/WebCore/html/parser/XSSFilter.h2
-rwxr-xr-xSource/WebCore/html/parser/create-html-entity-table47
-rw-r--r--Source/WebCore/html/shadow/MediaControls.cpp4
-rw-r--r--Source/WebCore/html/shadow/TextControlInnerElements.cpp503
-rw-r--r--Source/WebCore/html/shadow/TextControlInnerElements.h158
69 files changed, 2112 insertions, 590 deletions
diff --git a/Source/WebCore/html/HTMLAttributeNames.in b/Source/WebCore/html/HTMLAttributeNames.in
index d195a6f..956812d 100644
--- a/Source/WebCore/html/HTMLAttributeNames.in
+++ b/Source/WebCore/html/HTMLAttributeNames.in
@@ -216,6 +216,7 @@ onseeked
onseeking
onselect
onselectstart
+onselectionchange
onwebkitspeechchange
onstalled
onstorage
@@ -240,6 +241,7 @@ open
optimum
pattern
placeholder
+pluginspage
pluginurl
ping
poster
diff --git a/Source/WebCore/html/HTMLBodyElement.cpp b/Source/WebCore/html/HTMLBodyElement.cpp
index 84f81c3..3cc4cd8 100644
--- a/Source/WebCore/html/HTMLBodyElement.cpp
+++ b/Source/WebCore/html/HTMLBodyElement.cpp
@@ -171,6 +171,8 @@ void HTMLBodyElement::parseMappedAttribute(Attribute* attr)
document()->setWindowAttributeEventListener(eventNames().resizeEvent, createAttributeEventListener(document()->frame(), attr));
else if (attr->name() == onscrollAttr)
document()->setWindowAttributeEventListener(eventNames().scrollEvent, createAttributeEventListener(document()->frame(), attr));
+ else if (attr->name() == onselectionchangeAttr)
+ document()->setAttributeEventListener(eventNames().selectionchangeEvent, createAttributeEventListener(document()->frame(), attr));
else if (attr->name() == onstorageAttr)
document()->setWindowAttributeEventListener(eventNames().storageEvent, createAttributeEventListener(document()->frame(), attr));
else if (attr->name() == ononlineAttr)
@@ -286,7 +288,8 @@ void HTMLBodyElement::setVLink(const String& value)
static int adjustForZoom(int value, Document* document)
{
- float zoomFactor = document->frame()->pageZoomFactor();
+ Frame* frame = document->frame();
+ float zoomFactor = frame->pageZoomFactor() * frame->pageScaleFactor();
if (zoomFactor == 1)
return value;
// Needed because of truncation (rather than rounding) when scaling up.
@@ -314,7 +317,7 @@ void HTMLBodyElement::setScrollLeft(int scrollLeft)
FrameView* view = frame->view();
if (!view)
return;
- view->setScrollPosition(IntPoint(static_cast<int>(scrollLeft * frame->pageZoomFactor()), view->scrollY()));
+ view->setScrollPosition(IntPoint(static_cast<int>(scrollLeft * frame->pageZoomFactor() * frame->pageScaleFactor()), view->scrollY()));
}
int HTMLBodyElement::scrollTop() const
@@ -336,7 +339,7 @@ void HTMLBodyElement::setScrollTop(int scrollTop)
FrameView* view = frame->view();
if (!view)
return;
- view->setScrollPosition(IntPoint(view->scrollX(), static_cast<int>(scrollTop * frame->pageZoomFactor())));
+ view->setScrollPosition(IntPoint(view->scrollX(), static_cast<int>(scrollTop * frame->pageZoomFactor() * frame->pageScaleFactor())));
}
int HTMLBodyElement::scrollHeight() const
diff --git a/Source/WebCore/html/HTMLCanvasElement.cpp b/Source/WebCore/html/HTMLCanvasElement.cpp
index 09e8d04..79ebdad 100644
--- a/Source/WebCore/html/HTMLCanvasElement.cpp
+++ b/Source/WebCore/html/HTMLCanvasElement.cpp
@@ -369,7 +369,7 @@ IntSize HTMLCanvasElement::convertToValidDeviceSize(float width, float height) c
if (width < 1 || height < 1 || width * height > MaxCanvasArea)
return IntSize();
-#if PLATFORM(SKIA)
+#if USE(SKIA)
if (width > MaxSkiaDim || height > MaxSkiaDim)
return IntSize();
#endif
diff --git a/Source/WebCore/html/HTMLElement.cpp b/Source/WebCore/html/HTMLElement.cpp
index 22fc2f2..b3981c8 100644
--- a/Source/WebCore/html/HTMLElement.cpp
+++ b/Source/WebCore/html/HTMLElement.cpp
@@ -124,7 +124,7 @@ bool HTMLElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry
}
if (attrName == dirAttr) {
result = hasLocalName(bdoTag) ? eBDO : eUniversal;
- return false;
+ return true;
}
return StyledElement::mapToEntry(attrName, result);
@@ -148,14 +148,18 @@ void HTMLElement::parseMappedAttribute(Attribute* attr)
} else if (attr->name() == tabindexAttr) {
indexstring = getAttribute(tabindexAttr);
int tabindex = 0;
- if (parseHTMLInteger(indexstring, tabindex)) {
+ if (!indexstring.length()) {
+ clearTabIndexExplicitly();
+ } else if (parseHTMLInteger(indexstring, tabindex)) {
// Clamp tabindex to the range of 'short' to match Firefox's behavior.
setTabIndexExplicitly(max(static_cast<int>(std::numeric_limits<short>::min()), min(tabindex, static_cast<int>(std::numeric_limits<short>::max()))));
}
} else if (attr->name() == langAttr) {
// FIXME: Implement
} else if (attr->name() == dirAttr) {
- addCSSProperty(attr, CSSPropertyDirection, attr->value());
+ if (!equalIgnoringCase(attr->value(), "auto"))
+ addCSSProperty(attr, CSSPropertyDirection, attr->value());
+ dirAttributeChanged(attr);
addCSSProperty(attr, CSSPropertyUnicodeBidi, hasLocalName(bdoTag) ? CSSValueBidiOverride : CSSValueEmbed);
} else if (attr->name() == draggableAttr) {
const AtomicString& value = attr->value();
@@ -655,7 +659,7 @@ bool HTMLElement::supportsFocus() const
bool HTMLElement::isContentEditable() const
{
- if (document()->frame() && document()->frame()->isContentEditable())
+ if (document()->inDesignMode())
return true;
// Ideally we'd call ASSERT!needsStyleRecalc()) here, but
@@ -674,7 +678,7 @@ bool HTMLElement::isContentEditable() const
bool HTMLElement::isContentRichlyEditable() const
{
- if (document()->frame() && document()->frame()->isContentEditable())
+ if (document()->inDesignMode())
return true;
if (!renderer()) {
@@ -878,6 +882,147 @@ void HTMLElement::dispatchInputEvents()
ownerForm->dispatchFormInput();
}
+static void setHasDirAutoFlagRecursively(Node* firstNode, bool flag, Node* lastNode = 0)
+{
+ firstNode->setSelfOrAncestorHasDirAutoAttribute(flag);
+
+ Node* node = firstNode->firstChild();
+
+ while (node) {
+ if (node->selfOrAncestorHasDirAutoAttribute() == flag)
+ return;
+
+ if (node->isHTMLElement() && toElement(node)->hasAttribute(dirAttr)) {
+ if (node == lastNode)
+ return;
+ node = node->traverseNextSibling(firstNode);
+ continue;
+ }
+ node->setSelfOrAncestorHasDirAutoAttribute(flag);
+ if (node == lastNode)
+ return;
+ node = node->traverseNextNode(firstNode);
+ }
+}
+
+void HTMLElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+ StyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+ adjustDirectionalityIfNeededAfterChildrenChanged(beforeChange, childCountDelta);
+}
+
+TextDirection HTMLElement::directionalityIfhasDirAutoAttribute(bool& isAuto) const
+{
+ if (!(selfOrAncestorHasDirAutoAttribute() && equalIgnoringCase(getAttribute(dirAttr), "auto"))) {
+ isAuto = false;
+ return LTR;
+ }
+
+ isAuto = true;
+ return directionality();
+}
+
+TextDirection HTMLElement::directionality(Node** strongDirectionalityTextNode) const
+{
+ Node* node = firstChild();
+ while (node) {
+ // Skip bdi, script and style elements
+ if (equalIgnoringCase(node->nodeName(), "bdi") || node->hasTagName(scriptTag) || node->hasTagName(styleTag)) {
+ node = node->traverseNextSibling(this);
+ continue;
+ }
+
+ // Skip elements with valid dir attribute
+ if (node->isElementNode()) {
+ AtomicString dirAttributeValue = toElement(node)->fastGetAttribute(dirAttr);
+ if (equalIgnoringCase(dirAttributeValue, "rtl") || equalIgnoringCase(dirAttributeValue, "ltr") || equalIgnoringCase(dirAttributeValue, "auto")) {
+ node = node->traverseNextSibling(this);
+ continue;
+ }
+ }
+
+ if (node->isTextNode()) {
+ bool hasStrongDirectionality;
+ WTF::Unicode::Direction textDirection = node->textContent(true).defaultWritingDirection(&hasStrongDirectionality);
+ if (hasStrongDirectionality) {
+ if (strongDirectionalityTextNode)
+ *strongDirectionalityTextNode = node;
+ return (textDirection == WTF::Unicode::LeftToRight) ? LTR : RTL;
+ }
+ }
+ node = node->traverseNextNode(this);
+ }
+ if (strongDirectionalityTextNode)
+ *strongDirectionalityTextNode = 0;
+ return LTR;
+}
+
+void HTMLElement::dirAttributeChanged(Attribute* attribute)
+{
+ Element* parent = parentElement();
+
+ if (parent && parent->isHTMLElement() && parent->selfOrAncestorHasDirAutoAttribute())
+ toHTMLElement(parent)->adjustDirectionalityIfNeededAfterChildAttributeChanged(this);
+
+ if (equalIgnoringCase(attribute->value(), "auto"))
+ calculateAndAdjustDirectionality();
+}
+
+void HTMLElement::adjustDirectionalityIfNeededAfterChildAttributeChanged(Element* child)
+{
+ ASSERT(selfOrAncestorHasDirAutoAttribute());
+ Node* strongDirectionalityTextNode;
+ TextDirection textDirection = directionality(&strongDirectionalityTextNode);
+ setHasDirAutoFlagRecursively(child, false);
+ if (renderer() && renderer()->style() && renderer()->style()->direction() != textDirection) {
+ Element* elementToAdjust = this;
+ for (; elementToAdjust; elementToAdjust = elementToAdjust->parentElement()) {
+ if (elementToAdjust->hasAttribute(dirAttr)) {
+ elementToAdjust->setNeedsStyleRecalc();
+ return;
+ }
+ }
+ }
+}
+
+void HTMLElement::calculateAndAdjustDirectionality()
+{
+ Node* strongDirectionalityTextNode;
+ TextDirection textDirection = directionality(&strongDirectionalityTextNode);
+ setHasDirAutoFlagRecursively(this, true, strongDirectionalityTextNode);
+ if (renderer() && renderer()->style() && renderer()->style()->direction() != textDirection)
+ setNeedsStyleRecalc();
+}
+
+void HTMLElement::adjustDirectionalityIfNeededAfterChildrenChanged(Node* beforeChange, int childCountDelta)
+{
+ if ((!document() || document()->renderer()) && childCountDelta < 0) {
+ Node* node = beforeChange ? beforeChange->traverseNextSibling() : 0;
+ for (int counter = 0; node && counter < childCountDelta; counter++, node = node->traverseNextSibling()) {
+ if (node->isElementNode() && toElement(node)->hasAttribute(dirAttr))
+ continue;
+
+ setHasDirAutoFlagRecursively(node, false);
+ }
+ }
+
+ if (!selfOrAncestorHasDirAutoAttribute())
+ return;
+
+ Node* oldMarkedNode = beforeChange ? beforeChange->traverseNextSibling() : 0;
+ while (oldMarkedNode && oldMarkedNode->isHTMLElement() && toHTMLElement(oldMarkedNode)->hasAttribute(dirAttr))
+ oldMarkedNode = oldMarkedNode->traverseNextSibling(this);
+ if (oldMarkedNode)
+ setHasDirAutoFlagRecursively(oldMarkedNode, false);
+
+ for (Element* elementToAdjust = this; elementToAdjust; elementToAdjust = elementToAdjust->parentElement()) {
+ if (elementToAdjust->isHTMLElement() && elementToAdjust->hasAttribute(dirAttr)) {
+ toHTMLElement(elementToAdjust)->calculateAndAdjustDirectionality();
+ return;
+ }
+ }
+}
+
} // namespace WebCore
#ifndef NDEBUG
diff --git a/Source/WebCore/html/HTMLElement.h b/Source/WebCore/html/HTMLElement.h
index 2f6bc41..73517df 100644
--- a/Source/WebCore/html/HTMLElement.h
+++ b/Source/WebCore/html/HTMLElement.h
@@ -87,6 +87,8 @@ public:
virtual void dispatchChangeEvents();
virtual void dispatchInputEvents();
+ TextDirection directionalityIfhasDirAutoAttribute(bool& isAuto) const;
+
protected:
HTMLElement(const QualifiedName& tagName, Document*);
@@ -95,6 +97,8 @@ protected:
virtual bool mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const;
virtual void parseMappedAttribute(Attribute*);
+ virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
+
private:
virtual String nodeName() const;
@@ -106,6 +110,12 @@ private:
PassRefPtr<DocumentFragment> textToFragment(const String&, ExceptionCode&);
HTMLFormElement* shadowAncestorOwnerForm();
+
+ void dirAttributeChanged(Attribute*);
+ void adjustDirectionalityIfNeededAfterChildAttributeChanged(Element* child);
+ void calculateAndAdjustDirectionality();
+ void adjustDirectionalityIfNeededAfterChildrenChanged(Node* beforeChange, int childCountDelta);
+ TextDirection directionality(Node** strongDirectionalityTextNode= 0) const;
};
inline HTMLElement* toHTMLElement(Node* node)
diff --git a/Source/WebCore/html/HTMLElementsAllInOne.cpp b/Source/WebCore/html/HTMLElementsAllInOne.cpp
index 785a94b..e4499c0 100644
--- a/Source/WebCore/html/HTMLElementsAllInOne.cpp
+++ b/Source/WebCore/html/HTMLElementsAllInOne.cpp
@@ -97,6 +97,7 @@
#include "HTMLSelectElement.cpp"
#include "HTMLSourceElement.cpp"
#include "HTMLStyleElement.cpp"
+#include "HTMLSummaryElement.cpp"
#include "HTMLTableCaptionElement.cpp"
#include "HTMLTableCellElement.cpp"
#include "HTMLTableColElement.cpp"
diff --git a/Source/WebCore/html/HTMLFormControlElement.cpp b/Source/WebCore/html/HTMLFormControlElement.cpp
index 2f3db08..4b3c48a 100644
--- a/Source/WebCore/html/HTMLFormControlElement.cpp
+++ b/Source/WebCore/html/HTMLFormControlElement.cpp
@@ -65,6 +65,7 @@ HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Doc
, m_willValidateInitialized(false)
, m_willValidate(true)
, m_isValid(true)
+ , m_wasChangedSinceLastFormControlChangeEvent(false)
{
if (!this->form())
setForm(findFormAncestor());
@@ -130,7 +131,7 @@ void HTMLFormControlElement::attach()
// on the renderer.
if (renderer())
renderer()->updateFromElement();
-
+
// Focus the element if it should honour its autofocus attribute.
// We have to determine if the element is a TextArea/Input/Button/Select,
// if input type hidden ignore autofocus. So if disabled or readonly.
@@ -188,13 +189,25 @@ void HTMLFormControlElement::setName(const AtomicString& value)
setAttribute(nameAttr, value);
}
+bool HTMLFormControlElement::wasChangedSinceLastFormControlChangeEvent() const
+{
+ return m_wasChangedSinceLastFormControlChangeEvent;
+}
+
+void HTMLFormControlElement::setChangedSinceLastFormControlChangeEvent(bool changed)
+{
+ m_wasChangedSinceLastFormControlChangeEvent = changed;
+}
+
void HTMLFormControlElement::dispatchFormControlChangeEvent()
{
HTMLElement::dispatchChangeEvents();
+ setChangedSinceLastFormControlChangeEvent(false);
}
void HTMLFormControlElement::dispatchFormControlInputEvent()
{
+ setChangedSinceLastFormControlChangeEvent(true);
HTMLElement::dispatchInputEvents();
}
@@ -251,7 +264,7 @@ bool HTMLFormControlElement::isKeyboardFocusable(KeyboardEvent* event) const
{
if (isFocusable())
if (document()->frame())
- return document()->frame()->eventHandler()->tabsToAllControls(event);
+ return document()->frame()->eventHandler()->tabsToAllFormControls(event);
return false;
}
@@ -451,13 +464,13 @@ PassRefPtr<NodeList> HTMLFormControlElement::labels()
return 0;
if (!document())
return 0;
-
+
NodeRareData* data = Node::ensureRareData();
if (!data->nodeLists()) {
data->setNodeLists(NodeListsNodeData::create());
document()->addNodeListCache();
}
-
+
return LabelsNodeList::create(this);
}
@@ -582,6 +595,7 @@ bool HTMLTextFormControlElement::placeholderShouldBeVisible() const
{
return supportsPlaceholder()
&& isEmptyValue()
+ && isEmptySuggestedValue()
&& !isPlaceholderEmpty()
&& (document()->focusedNode() != this || (renderer() && renderer()->theme()->shouldShowPlaceholderWhenFocused()));
}
diff --git a/Source/WebCore/html/HTMLFormControlElement.h b/Source/WebCore/html/HTMLFormControlElement.h
index 368dcfa..120313d 100644
--- a/Source/WebCore/html/HTMLFormControlElement.h
+++ b/Source/WebCore/html/HTMLFormControlElement.h
@@ -52,6 +52,9 @@ public:
virtual bool formControlValueMatchesRenderer() const { return m_valueMatchesRenderer; }
virtual void setFormControlValueMatchesRenderer(bool b) { m_valueMatchesRenderer = b; }
+ virtual bool wasChangedSinceLastFormControlChangeEvent() const;
+ virtual void setChangedSinceLastFormControlChangeEvent(bool);
+
virtual void dispatchFormControlChangeEvent();
virtual void dispatchFormControlInputEvent();
@@ -161,6 +164,8 @@ private:
// Cache of validity()->valid().
// But "candidate for constraint validation" doesn't affect m_isValid.
bool m_isValid : 1;
+
+ bool m_wasChangedSinceLastFormControlChangeEvent : 1;
};
// FIXME: Give this class its own header file.
@@ -223,6 +228,8 @@ private:
// Returns true if user-editable value is empty. Used to check placeholder visibility.
virtual bool isEmptyValue() const = 0;
+ // Returns true if suggested value is empty. Used to check placeholder visibility.
+ virtual bool isEmptySuggestedValue() const { return true; }
// Called in dispatchFocusEvent(), after placeholder process, before calling parent's dispatchFocusEvent().
virtual void handleFocusEvent() { }
// Called in dispatchBlurEvent(), after placeholder process, before calling parent's dispatchBlurEvent().
diff --git a/Source/WebCore/html/HTMLImageLoader.cpp b/Source/WebCore/html/HTMLImageLoader.cpp
index ab4ae29..77ee1e7 100644
--- a/Source/WebCore/html/HTMLImageLoader.cpp
+++ b/Source/WebCore/html/HTMLImageLoader.cpp
@@ -49,6 +49,10 @@ HTMLImageLoader::~HTMLImageLoader()
void HTMLImageLoader::dispatchLoadEvent()
{
+ // HTMLVideoElement uses this class to load the poster image, but it should not fire events for loading or failure.
+ if (element()->hasTagName(HTMLNames::videoTag))
+ return;
+
bool errorOccurred = image()->errorOccurred();
if (!errorOccurred && image()->response().httpStatusCode() >= 400)
errorOccurred = element()->hasTagName(HTMLNames::objectTag); // An <object> considers a 404 to be an error and should fire onerror.
diff --git a/Source/WebCore/html/HTMLInputElement.cpp b/Source/WebCore/html/HTMLInputElement.cpp
index 14dd149..c5f1ebc 100644
--- a/Source/WebCore/html/HTMLInputElement.cpp
+++ b/Source/WebCore/html/HTMLInputElement.cpp
@@ -501,6 +501,8 @@ void HTMLInputElement::updateType()
updateFocusAppearance(true);
}
+ setChangedSinceLastFormControlChangeEvent(false);
+
checkedRadioButtons().addButton(this);
setNeedsValidityCheck();
@@ -905,10 +907,14 @@ void HTMLInputElement::setValue(const String& value, bool sendChangeEvent)
}
m_inputType->valueChanged();
- // Don't dispatch the change event when focused, it will be dispatched
- // when the control loses focus.
- if (sendChangeEvent && document()->focusedNode() != this)
- dispatchFormControlChangeEvent();
+ if (sendChangeEvent) {
+ // If the user is still editing this field, dispatch an input event rather than a change event.
+ // The change event will be dispatched when editing finishes.
+ if (isTextField() && focused())
+ dispatchFormControlInputEvent();
+ else
+ dispatchFormControlChangeEvent();
+ }
InputElement::notifyFormStateChanged(this);
}
@@ -977,6 +983,10 @@ void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths)
void* HTMLInputElement::preDispatchEventHandler(Event* event)
{
+ if (event->type() == eventNames().textInputEvent && m_inputType->shouldSubmitImplicitly(event)) {
+ event->stopPropagation();
+ return 0;
+ }
if (event->type() != eventNames().clickEvent)
return 0;
if (!event->isMouseEvent() || static_cast<MouseEvent*>(event)->button() != LeftButton)
@@ -1045,15 +1055,10 @@ void HTMLInputElement::defaultEventHandler(Event* evt)
addSearchResult();
onSearch();
}
- // Fire onChange for text fields.
- RenderObject* r = renderer();
- if (r && r->isTextField() && toRenderTextControl(r)->wasChangedSinceLastChangeEvent()) {
+ // Form submission finishes editing, just as loss of focus does.
+ // If there was a change, send the event now.
+ if (wasChangedSinceLastFormControlChangeEvent())
dispatchFormControlChangeEvent();
- // Refetch the renderer since arbitrary JS code run during onchange can do anything, including destroying it.
- r = renderer();
- if (r && r->isTextField())
- toRenderTextControl(r)->setChangedSinceLastChangeEvent(false);
- }
RefPtr<HTMLFormElement> formForSubmission = m_inputType->formForSubmission();
// Form may never have been present, or may have been destroyed by code responding to the change event.
@@ -1170,6 +1175,11 @@ String HTMLInputElement::visibleValue() const
return m_inputType->visibleValue();
}
+String HTMLInputElement::convertFromVisibleValue(const String& visibleValue) const
+{
+ return m_inputType->convertFromVisibleValue(visibleValue);
+}
+
bool HTMLInputElement::isAcceptableValue(const String& proposedValue) const
{
return m_inputType->isAcceptableValue(proposedValue);
@@ -1430,8 +1440,6 @@ void HTMLInputElement::stepUpFromRenderer(int n)
}
if (currentStringValue != value()) {
- if (renderer() && renderer()->isTextField())
- toRenderTextControl(renderer())->setChangedSinceLastChangeEvent(true);
if (m_inputType->isRangeControl())
dispatchFormControlChangeEvent();
else
diff --git a/Source/WebCore/html/HTMLInputElement.h b/Source/WebCore/html/HTMLInputElement.h
index 757992a..27d556b 100644
--- a/Source/WebCore/html/HTMLInputElement.h
+++ b/Source/WebCore/html/HTMLInputElement.h
@@ -196,7 +196,7 @@ public:
CheckedRadioButtons& checkedRadioButtons() const;
void handleBeforeTextInsertedEvent(Event*);
void updateCheckedRadioButtons();
-
+
protected:
HTMLInputElement(const QualifiedName&, Document*, HTMLFormElement*, bool createdByParser);
@@ -217,11 +217,11 @@ private:
virtual bool shouldUseInputMethod() const;
virtual const AtomicString& formControlName() const;
-
+
// isChecked is used by the rendering tree/CSS while checked() is used by JS to determine checked state
virtual bool isChecked() const;
virtual bool isIndeterminate() const { return indeterminate(); }
-
+
virtual bool isTextFormControl() const { return isTextField(); }
virtual bool hasSpinButton() const;
@@ -235,7 +235,7 @@ private:
virtual void restoreFormControlState(const String&);
virtual bool canStartSelection() const;
-
+
virtual void accessKeyAction(bool sendToAnyElement);
virtual bool mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const;
@@ -260,6 +260,7 @@ private:
virtual void cacheSelection(int start, int end);
virtual String visibleValue() const;
+ virtual String convertFromVisibleValue(const String&) const;
virtual bool isAcceptableValue(const String&) const;
virtual String sanitizeValue(const String&) const;
virtual bool hasUnacceptableValue() const;
@@ -280,6 +281,7 @@ private:
virtual bool supportsPlaceholder() const;
virtual bool isEmptyValue() const { return value().isEmpty(); }
+ virtual bool isEmptySuggestedValue() const { return suggestedValue().isEmpty(); }
virtual void handleFocusEvent();
virtual void handleBlurEvent();
virtual int cachedSelectionStart() const { return m_data.cachedSelectionStart(); }
diff --git a/Source/WebCore/html/HTMLMediaElement.cpp b/Source/WebCore/html/HTMLMediaElement.cpp
index 04d0a1d..a2506d0 100644
--- a/Source/WebCore/html/HTMLMediaElement.cpp
+++ b/Source/WebCore/html/HTMLMediaElement.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -139,7 +139,7 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* docum
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
, m_proxyWidget(0)
#endif
- , m_restrictions(NoRestrictions)
+ , m_restrictions(RequireUserGestureForFullScreenRestriction)
, m_preload(MediaPlayer::Auto)
, m_displayMode(Unknown)
, m_processingMediaPlayerCallback(0)
@@ -171,10 +171,14 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* docum
LOG(Media, "HTMLMediaElement::HTMLMediaElement");
document->registerForDocumentActivationCallbacks(this);
document->registerForMediaVolumeCallbacks(this);
+<<<<<<< HEAD
#if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS)
// Enable the Media Element to listen to all the touch events
document->addListenerTypeIfNeeded(eventNames().touchstartEvent);
#endif
+=======
+ document->registerForPrivateBrowsingStateChangedCallbacks(this);
+>>>>>>> WebKit at r80534
}
HTMLMediaElement::~HTMLMediaElement()
@@ -185,6 +189,7 @@ HTMLMediaElement::~HTMLMediaElement()
setShouldDelayLoadEvent(false);
document()->unregisterForDocumentActivationCallbacks(this);
document()->unregisterForMediaVolumeCallbacks(this);
+ document()->unregisterForPrivateBrowsingStateChangedCallbacks(this);
}
void HTMLMediaElement::willMoveToNewOwnerDocument()
@@ -700,6 +705,10 @@ void HTMLMediaElement::loadResource(const KURL& initialURL, ContentType& content
if (m_sendProgressEvents)
startProgressEventTimer();
+ Settings* settings = document()->settings();
+ bool privateMode = !settings || settings->privateBrowsingEnabled();
+ m_player->setPrivateBrowsingMode(privateMode);
+
if (!autoplay())
m_player->setPreload(m_preload);
m_player->setPreservesPitch(m_webkitPreservesPitch);
@@ -1480,6 +1489,10 @@ bool HTMLMediaElement::controls() const
if (frame && !frame->script()->canExecuteScripts(NotAboutToExecuteScript))
return true;
+ // always show controls for video when fullscreen playback is required.
+ if (isVideo() && document()->page() && document()->page()->chrome()->requiresFullscreenForVideoPlayback())
+ return true;
+
return hasAttribute(controlsAttr);
}
@@ -1527,8 +1540,7 @@ void HTMLMediaElement::setMuted(bool muted)
m_player->setMuted(m_muted);
if (renderer())
renderer()->updateFromElement();
- } else
- updateVolume();
+ }
}
scheduleEvent(eventNames().volumechangeEvent);
}
@@ -1868,9 +1880,14 @@ void HTMLMediaElement::mediaPlayerVolumeChanged(MediaPlayer*)
LOG(Media, "HTMLMediaElement::mediaPlayerVolumeChanged");
beginProcessingMediaPlayerCallback();
- if (m_player)
- m_volume = m_player->volume();
- updateVolume();
+ if (m_player) {
+ float vol = m_player->volume();
+ if (vol != m_volume) {
+ m_volume = vol;
+ updateVolume();
+ scheduleEvent(eventNames().volumechangeEvent);
+ }
+ }
endProcessingMediaPlayerCallback();
}
@@ -2496,18 +2513,18 @@ bool HTMLMediaElement::webkitHasClosedCaptions() const
}
#if ENABLE(MEDIA_STATISTICS)
-unsigned long HTMLMediaElement::webkitAudioBytesDecoded() const
+unsigned HTMLMediaElement::webkitAudioDecodedByteCount() const
{
if (!m_player)
return 0;
- return m_player->audioBytesDecoded();
+ return m_player->audioDecodedByteCount();
}
-unsigned long HTMLMediaElement::webkitVideoBytesDecoded() const
+unsigned HTMLMediaElement::webkitVideoDecodedByteCount() const
{
if (!m_player)
return 0;
- return m_player->videoBytesDecoded();
+ return m_player->videoDecodedByteCount();
}
#endif
@@ -2539,6 +2556,33 @@ void HTMLMediaElement::setShouldDelayLoadEvent(bool shouldDelay)
document()->decrementLoadEventDelayCount();
}
+
+void HTMLMediaElement::getSitesInMediaCache(Vector<String>& sites)
+{
+ MediaPlayer::getSitesInMediaCache(sites);
+}
+
+void HTMLMediaElement::clearMediaCache()
+{
+ MediaPlayer::clearMediaCache();
+}
+
+void HTMLMediaElement::clearMediaCacheForSite(const String& site)
+{
+ MediaPlayer::clearMediaCacheForSite(site);
+}
+
+void HTMLMediaElement::privateBrowsingStateDidChange()
+{
+ if (!m_player)
+ return;
+
+ Settings* settings = document()->settings();
+ bool privateMode = !settings || settings->privateBrowsingEnabled();
+ LOG(Media, "HTMLMediaElement::privateBrowsingStateDidChange(%s)", boolString(privateMode));
+ m_player->setPrivateBrowsingMode(privateMode);
+}
+
}
#endif
diff --git a/Source/WebCore/html/HTMLMediaElement.h b/Source/WebCore/html/HTMLMediaElement.h
index 9778fd4..f870586 100644
--- a/Source/WebCore/html/HTMLMediaElement.h
+++ b/Source/WebCore/html/HTMLMediaElement.h
@@ -131,8 +131,8 @@ public:
#if ENABLE(MEDIA_STATISTICS)
// Statistics
- unsigned long webkitAudioBytesDecoded() const;
- unsigned long webkitVideoBytesDecoded() const;
+ unsigned webkitAudioDecodedByteCount() const;
+ unsigned webkitVideoDecodedByteCount() const;
#endif
// controls
@@ -176,6 +176,27 @@ public:
void sourceWillBeRemoved(HTMLSourceElement*);
void sourceWasAdded(HTMLSourceElement*);
+ void privateBrowsingStateDidChange();
+
+ // Restrictions to change default behaviors.
+ enum BehaviorRestrictions {
+ NoRestrictions = 0,
+ RequireUserGestureForLoadRestriction = 1 << 0,
+ RequireUserGestureForRateChangeRestriction = 1 << 1,
+ RequireUserGestureForFullScreenRestriction = 1 << 2
+ };
+
+ bool requireUserGestureForLoad() const { return m_restrictions & RequireUserGestureForLoadRestriction; }
+ bool requireUserGestureForRateChange() const { return m_restrictions & RequireUserGestureForRateChangeRestriction; }
+ bool requireUserGestureForFullScreen() const { return m_restrictions & RequireUserGestureForFullScreenRestriction; }
+
+ void setBehaviorRestrictions(BehaviorRestrictions restrictions) { m_restrictions = restrictions; }
+
+ // Media cache management.
+ static void getSitesInMediaCache(Vector<String>&);
+ static void clearMediaCache();
+ static void clearMediaCacheForSite(const String&);
+
protected:
HTMLMediaElement(const QualifiedName&, Document*);
virtual ~HTMLMediaElement();
@@ -298,14 +319,6 @@ private:
void invalidateCachedTime();
void refreshCachedTime() const;
- // Restrictions to change default behaviors. This is effectively a compile time choice at the moment
- // because there are no accessor functions.
- enum BehaviorRestrictions {
- NoRestrictions = 0,
- RequireUserGestureForLoadRestriction = 1 << 0,
- RequireUserGestureForRateChangeRestriction = 1 << 1,
- };
-
Timer<HTMLMediaElement> m_loadTimer;
Timer<HTMLMediaElement> m_asyncEventTimer;
Timer<HTMLMediaElement> m_progressEventTimer;
diff --git a/Source/WebCore/html/HTMLMediaElement.idl b/Source/WebCore/html/HTMLMediaElement.idl
index 9d4602d..c7e6b07 100644
--- a/Source/WebCore/html/HTMLMediaElement.idl
+++ b/Source/WebCore/html/HTMLMediaElement.idl
@@ -84,8 +84,8 @@ interface [Conditional=VIDEO] HTMLMediaElement : HTMLElement {
#if defined(ENABLE_MEDIA_STATISTICS) && ENABLE_MEDIA_STATISTICS
// The number of bytes consumed by the media decoder.
- readonly attribute unsigned long webkitAudioBytesDecoded;
- readonly attribute unsigned long webkitVideoBytesDecoded;
+ readonly attribute unsigned long webkitAudioDecodedByteCount;
+ readonly attribute unsigned long webkitVideoDecodedByteCount;
#endif
};
}
diff --git a/Source/WebCore/html/HTMLScriptElement.cpp b/Source/WebCore/html/HTMLScriptElement.cpp
index 603b2a8..8e708d1 100644
--- a/Source/WebCore/html/HTMLScriptElement.cpp
+++ b/Source/WebCore/html/HTMLScriptElement.cpp
@@ -35,9 +35,9 @@ namespace WebCore {
using namespace HTMLNames;
-inline HTMLScriptElement::HTMLScriptElement(const QualifiedName& tagName, Document* document, bool wasInsertedByParser, bool wasAlreadyStarted)
+inline HTMLScriptElement::HTMLScriptElement(const QualifiedName& tagName, Document* document, bool wasInsertedByParser, bool alreadyStarted)
: HTMLElement(tagName, document)
- , ScriptElement(this, wasInsertedByParser, wasAlreadyStarted)
+ , ScriptElement(this, wasInsertedByParser, alreadyStarted)
{
ASSERT(hasTagName(scriptTag));
}
@@ -74,16 +74,10 @@ void HTMLScriptElement::parseMappedAttribute(Attribute* attr)
HTMLElement::parseMappedAttribute(attr);
}
-void HTMLScriptElement::finishParsingChildren()
-{
- ScriptElement::finishParsingChildren(sourceAttributeValue());
- HTMLElement::finishParsingChildren();
-}
-
void HTMLScriptElement::insertedIntoDocument()
{
HTMLElement::insertedIntoDocument();
- ScriptElement::insertedIntoDocument(sourceAttributeValue());
+ ScriptElement::insertedIntoDocument();
}
void HTMLScriptElement::removedFromDocument()
@@ -160,6 +154,11 @@ bool HTMLScriptElement::deferAttributeValue() const
return fastHasAttribute(deferAttr);
}
+bool HTMLScriptElement::hasSourceAttribute() const
+{
+ return fastHasAttribute(srcAttr);
+}
+
void HTMLScriptElement::dispatchLoadEvent()
{
ASSERT(!haveFiredLoadEvent());
@@ -175,7 +174,7 @@ void HTMLScriptElement::dispatchErrorEvent()
PassRefPtr<Element> HTMLScriptElement::cloneElementWithoutAttributesAndChildren() const
{
- return adoptRef(new HTMLScriptElement(tagQName(), document(), false, wasAlreadyStarted()));
+ return adoptRef(new HTMLScriptElement(tagQName(), document(), false, alreadyStarted()));
}
}
diff --git a/Source/WebCore/html/HTMLScriptElement.h b/Source/WebCore/html/HTMLScriptElement.h
index 09773c5..efe6a6a 100644
--- a/Source/WebCore/html/HTMLScriptElement.h
+++ b/Source/WebCore/html/HTMLScriptElement.h
@@ -39,7 +39,7 @@ public:
KURL src() const;
private:
- HTMLScriptElement(const QualifiedName&, Document*, bool wasInsertedByParser, bool wasAlreadyStarted);
+ HTMLScriptElement(const QualifiedName&, Document*, bool wasInsertedByParser, bool alreadyStarted);
virtual void parseMappedAttribute(Attribute*);
virtual void insertedIntoDocument();
@@ -47,7 +47,6 @@ private:
virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
virtual bool isURLAttribute(Attribute*) const;
- virtual void finishParsingChildren();
virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const;
@@ -59,6 +58,7 @@ private:
virtual String eventAttributeValue() const;
virtual bool asyncAttributeValue() const;
virtual bool deferAttributeValue() const;
+ virtual bool hasSourceAttribute() const;
virtual void dispatchLoadEvent();
virtual void dispatchErrorEvent();
diff --git a/Source/WebCore/html/HTMLSummaryElement.cpp b/Source/WebCore/html/HTMLSummaryElement.cpp
new file mode 100644
index 0000000..96e3d74
--- /dev/null
+++ b/Source/WebCore/html/HTMLSummaryElement.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "HTMLSummaryElement.h"
+
+#include "HTMLNames.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+PassRefPtr<HTMLSummaryElement> HTMLSummaryElement::create(const QualifiedName& tagName, Document* document)
+{
+ return adoptRef(new HTMLSummaryElement(tagName, document));
+}
+
+HTMLSummaryElement::HTMLSummaryElement(const QualifiedName& tagName, Document* document)
+ : HTMLElement(tagName, document)
+{
+ ASSERT(hasTagName(summaryTag));
+}
+
+}
diff --git a/Source/WebCore/html/HTMLSummaryElement.h b/Source/WebCore/html/HTMLSummaryElement.h
new file mode 100644
index 0000000..1b24c67
--- /dev/null
+++ b/Source/WebCore/html/HTMLSummaryElement.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef HTMLSummaryElement_h
+#define HTMLSummaryElement_h
+
+#include "HTMLElement.h"
+
+namespace WebCore {
+
+class HTMLSummaryElement : public HTMLElement {
+public:
+ static PassRefPtr<HTMLSummaryElement> create(const QualifiedName&, Document*);
+
+private:
+ HTMLSummaryElement(const QualifiedName&, Document*);
+};
+
+}
+
+#endif // HTMLSummaryElement_h
diff --git a/Source/WebCore/html/HTMLTagNames.in b/Source/WebCore/html/HTMLTagNames.in
index 83d41de..bea63e4 100644
--- a/Source/WebCore/html/HTMLTagNames.in
+++ b/Source/WebCore/html/HTMLTagNames.in
@@ -115,7 +115,7 @@ strike interfaceName=HTMLElement
strong interfaceName=HTMLElement
style constructorNeedsCreatedByParser
sub interfaceName=HTMLElement
-summary interfaceName=HTMLElement
+summary interfaceName=HTMLSummaryElement, JSInterfaceName=HTMLElement
sup interfaceName=HTMLElement
table
tbody interfaceName=HTMLTableSectionElement
diff --git a/Source/WebCore/html/HTMLVideoElement.cpp b/Source/WebCore/html/HTMLVideoElement.cpp
index 2004e48..4ddcdfe 100644
--- a/Source/WebCore/html/HTMLVideoElement.cpp
+++ b/Source/WebCore/html/HTMLVideoElement.cpp
@@ -232,7 +232,7 @@ void HTMLVideoElement::webkitEnterFullscreen(bool isUserGesture, ExceptionCode&
// Generate an exception if this isn't called in response to a user gesture, or if the
// element does not support fullscreen.
- if (!isUserGesture || !supportsFullscreen()) {
+ if ((requireUserGestureForFullScreen() && !isUserGesture) || !supportsFullscreen()) {
ec = INVALID_STATE_ERR;
return;
}
@@ -264,20 +264,20 @@ void HTMLVideoElement::willMoveToNewOwnerDocument()
}
#if ENABLE(MEDIA_STATISTICS)
-unsigned long HTMLVideoElement::webkitDecodedFrames() const
+unsigned HTMLVideoElement::webkitDecodedFrameCount() const
{
if (!player())
return 0;
- return player()->decodedFrames();
+ return player()->decodedFrameCount();
}
-unsigned long HTMLVideoElement::webkitDroppedFrames() const
+unsigned HTMLVideoElement::webkitDroppedFrameCount() const
{
if (!player())
return 0;
- return player()->droppedFrames();
+ return player()->droppedFrameCount();
}
#endif
diff --git a/Source/WebCore/html/HTMLVideoElement.h b/Source/WebCore/html/HTMLVideoElement.h
index dd38a59..714fcaa 100644
--- a/Source/WebCore/html/HTMLVideoElement.h
+++ b/Source/WebCore/html/HTMLVideoElement.h
@@ -57,8 +57,8 @@ public:
#if ENABLE(MEDIA_STATISTICS)
// Statistics
- unsigned long webkitDecodedFrames() const;
- unsigned long webkitDroppedFrames() const;
+ unsigned webkitDecodedFrameCount() const;
+ unsigned webkitDroppedFrameCount() const;
#endif
// Used by canvas to gain raw pixel access
diff --git a/Source/WebCore/html/HTMLVideoElement.idl b/Source/WebCore/html/HTMLVideoElement.idl
index 50513d4..68c1aa7 100644
--- a/Source/WebCore/html/HTMLVideoElement.idl
+++ b/Source/WebCore/html/HTMLVideoElement.idl
@@ -46,11 +46,11 @@ module html {
#if defined(ENABLE_MEDIA_STATISTICS) && ENABLE_MEDIA_STATISTICS
// The number of frames that have been decoded and made available for
// playback.
- readonly attribute unsigned long webkitDecodedFrames;
+ readonly attribute unsigned long webkitDecodedFrameCount;
// The number of decoded frames that have been dropped by the player
// for performance reasons during playback.
- readonly attribute unsigned long webkitDroppedFrames;
+ readonly attribute unsigned long webkitDroppedFrameCount;
#endif
};
}
diff --git a/Source/WebCore/html/HTMLViewSourceDocument.cpp b/Source/WebCore/html/HTMLViewSourceDocument.cpp
index 27eaf51..b0633eb 100644
--- a/Source/WebCore/html/HTMLViewSourceDocument.cpp
+++ b/Source/WebCore/html/HTMLViewSourceDocument.cpp
@@ -52,6 +52,8 @@ HTMLViewSourceDocument::HTMLViewSourceDocument(Frame* frame, const KURL& url, co
, m_type(mimeType)
{
setUsesBeforeAfterRules(true);
+ setUsesViewSourceStyles(true);
+
setCompatibilityMode(QuirksMode);
lockCompatibilityMode();
}
diff --git a/Source/WebCore/html/ImageDocument.cpp b/Source/WebCore/html/ImageDocument.cpp
index a42ccc8..d03e37e 100644
--- a/Source/WebCore/html/ImageDocument.cpp
+++ b/Source/WebCore/html/ImageDocument.cpp
@@ -134,7 +134,7 @@ void ImageDocumentParser::appendBytes(DocumentWriter*, const char*, int, bool)
CachedImage* cachedImage = document()->cachedImage();
cachedImage->data(frame->loader()->documentLoader()->mainResourceData(), false);
- document()->imageChanged();
+ document()->imageUpdated();
}
void ImageDocumentParser::finish()
@@ -165,7 +165,7 @@ void ImageDocumentParser::finish()
document()->setTitle(imageTitle(fileName, size));
}
- document()->imageChanged();
+ document()->imageUpdated();
}
document()->finishedParsing();
@@ -282,7 +282,7 @@ void ImageDocument::imageClicked(int x, int y)
}
}
-void ImageDocument::imageChanged()
+void ImageDocument::imageUpdated()
{
ASSERT(m_imageElement);
diff --git a/Source/WebCore/html/ImageDocument.h b/Source/WebCore/html/ImageDocument.h
index 5d00bd6..9d281f1 100644
--- a/Source/WebCore/html/ImageDocument.h
+++ b/Source/WebCore/html/ImageDocument.h
@@ -43,7 +43,7 @@ public:
void disconnectImageElement() { m_imageElement = 0; }
void windowSizeChanged();
- void imageChanged();
+ void imageUpdated();
void imageClicked(int x, int y);
private:
diff --git a/Source/WebCore/html/InputType.cpp b/Source/WebCore/html/InputType.cpp
index 21ba7c2..d944909 100644
--- a/Source/WebCore/html/InputType.cpp
+++ b/Source/WebCore/html/InputType.cpp
@@ -521,6 +521,11 @@ String InputType::visibleValue() const
return element()->value();
}
+String InputType::convertFromVisibleValue(const String& visibleValue) const
+{
+ return visibleValue;
+}
+
bool InputType::isAcceptableValue(const String&)
{
return true;
diff --git a/Source/WebCore/html/InputType.h b/Source/WebCore/html/InputType.h
index 8c35af3..1b34717 100644
--- a/Source/WebCore/html/InputType.h
+++ b/Source/WebCore/html/InputType.h
@@ -153,7 +153,9 @@ public:
virtual String valueMissingText() const;
virtual bool canSetStringValue() const;
virtual String visibleValue() const;
+ virtual String convertFromVisibleValue(const String&) const;
virtual bool isAcceptableValue(const String&);
+ // Returing the null string means "use the default value."
virtual String sanitizeValue(const String&);
virtual bool hasUnacceptableValue();
diff --git a/Source/WebCore/html/NumberInputType.cpp b/Source/WebCore/html/NumberInputType.cpp
index 0011115..3397248 100644
--- a/Source/WebCore/html/NumberInputType.cpp
+++ b/Source/WebCore/html/NumberInputType.cpp
@@ -53,18 +53,6 @@ using namespace std;
static const double numberDefaultStep = 1.0;
static const double numberStepScaleFactor = 1.0;
-// Returns true if the specified character can be a part of 'valid floating
-// point number' of HTML5.
-static bool isHTMLNumberCharacter(UChar ch)
-{
- return ch == '+' || ch == '-' || ch == '.' || ch == 'e' || ch == 'E' || isASCIIDigit(ch);
-}
-
-static bool isNumberCharacter(UChar ch)
-{
- return isLocalizedNumberCharacter(ch) || isHTMLNumberCharacter(ch);
-}
-
PassOwnPtr<InputType> NumberInputType::create(HTMLInputElement* element)
{
return adoptPtr(new NumberInputType(element));
@@ -183,30 +171,6 @@ void NumberInputType::handleKeydownEvent(KeyboardEvent* event)
TextFieldInputType::handleKeydownEvent(event);
}
-void NumberInputType::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent* event)
-{
- unsigned length = event->text().length();
- bool hasInvalidChar = false;
- for (unsigned i = 0; i < length; ++i) {
- if (!isNumberCharacter(event->text()[i])) {
- hasInvalidChar = true;
- break;
- }
- }
- if (hasInvalidChar) {
- Vector<UChar> stripped;
- stripped.reserveCapacity(length);
- for (unsigned i = 0; i < length; ++i) {
- UChar ch = event->text()[i];
- if (!isNumberCharacter(ch))
- continue;
- stripped.append(ch);
- }
- event->setText(String::adopt(stripped));
- }
- TextFieldInputType::handleBeforeTextInsertedEvent(event);
-}
-
void NumberInputType::handleWheelEvent(WheelEvent* event)
{
handleWheelEventForSpinButton(event);
@@ -264,6 +228,14 @@ String NumberInputType::visibleValue() const
return localized.isEmpty() ? currentValue : localized;
}
+String NumberInputType::convertFromVisibleValue(const String& visibleValue) const
+{
+ if (visibleValue.isEmpty())
+ return visibleValue;
+ double parsedNumber = parseLocalizedNumber(visibleValue);
+ return isfinite(parsedNumber) ? serializeForNumberType(parsedNumber) : visibleValue;
+}
+
bool NumberInputType::isAcceptableValue(const String& proposedValue)
{
return proposedValue.isEmpty() || isfinite(parseLocalizedNumber(proposedValue)) || parseToDoubleForNumberType(proposedValue, 0);
@@ -271,12 +243,9 @@ bool NumberInputType::isAcceptableValue(const String& proposedValue)
String NumberInputType::sanitizeValue(const String& proposedValue)
{
- // Try to parse the value as a localized number, then try to parse it as
- // the standard format.
- double parsedValue = parseLocalizedNumber(proposedValue);
- if (isfinite(parsedValue))
- return serializeForNumberType(parsedValue);
- return parseToDoubleForNumberType(proposedValue, 0) ? proposedValue : String();
+ if (proposedValue.isEmpty())
+ return proposedValue;
+ return parseToDoubleForNumberType(proposedValue, 0) ? proposedValue : emptyAtom.string();
}
bool NumberInputType::hasUnacceptableValue()
diff --git a/Source/WebCore/html/NumberInputType.h b/Source/WebCore/html/NumberInputType.h
index 9d97134..ea5dc10 100644
--- a/Source/WebCore/html/NumberInputType.h
+++ b/Source/WebCore/html/NumberInputType.h
@@ -57,7 +57,6 @@ private:
virtual double defaultStep() const;
virtual double stepScaleFactor() const;
virtual void handleKeydownEvent(KeyboardEvent*);
- virtual void handleBeforeTextInsertedEvent(BeforeTextInsertedEvent*);
virtual void handleWheelEvent(WheelEvent*);
virtual double parseToDouble(const String&, double) const;
virtual double parseToDoubleWithDecimalPlaces(const String&, double, unsigned*) const;
@@ -65,6 +64,7 @@ private:
virtual double acceptableError(double) const;
virtual void handleBlurEvent();
virtual String visibleValue() const;
+ virtual String convertFromVisibleValue(const String&) const;
virtual bool isAcceptableValue(const String&);
virtual String sanitizeValue(const String&);
virtual bool hasUnacceptableValue();
diff --git a/Source/WebCore/html/TextFieldInputType.cpp b/Source/WebCore/html/TextFieldInputType.cpp
index 1d06be3..ffea2f4 100644
--- a/Source/WebCore/html/TextFieldInputType.cpp
+++ b/Source/WebCore/html/TextFieldInputType.cpp
@@ -85,7 +85,7 @@ void TextFieldInputType::handleKeydownEventForSpinButton(KeyboardEvent* event)
void TextFieldInputType::handleWheelEventForSpinButton(WheelEvent* event)
{
- if (element()->disabled() || element()->readOnly())
+ if (element()->disabled() || element()->readOnly() || !element()->focused())
return;
int step = 0;
if (event->wheelDeltaY() > 0)
diff --git a/Source/WebCore/html/ValidationMessage.cpp b/Source/WebCore/html/ValidationMessage.cpp
index f772b92..70aa02d 100644
--- a/Source/WebCore/html/ValidationMessage.cpp
+++ b/Source/WebCore/html/ValidationMessage.cpp
@@ -121,11 +121,8 @@ void ValidationMessage::buildBubbleTree(Timer<ValidationMessage>*)
// to inherit an existing shadow tree.
if (host->shadowRoot())
host->shadowRoot()->appendChild(m_bubble.get(), ec);
- else {
+ else
host->setShadowRoot(m_bubble);
- // FIXME: The following attach() should be unnecessary.
- m_bubble->attach();
- }
m_bubble->appendChild(ElementWithPseudoId::create(doc, "-webkit-validation-bubble-top-outer-arrow"), ec);
m_bubble->appendChild(ElementWithPseudoId::create(doc, "-webkit-validation-bubble-top-inner-arrow"), ec);
diff --git a/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp b/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp
index 9ef2dba..a549782 100644
--- a/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp
+++ b/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp
@@ -174,6 +174,11 @@ void CanvasRenderingContext2D::reset()
if (m_context3D && m_drawingBuffer) {
m_drawingBuffer->reset(IntSize(canvas()->width(), canvas()->height()));
c->setSharedGraphicsContext3D(m_context3D.get(), m_drawingBuffer.get(), IntSize(canvas()->width(), canvas()->height()));
+#if USE(ACCELERATED_COMPOSITING)
+ RenderBox* renderBox = canvas()->renderBox();
+ if (renderBox && renderBox->hasLayer() && renderBox->layer()->hasAcceleratedCompositing())
+ renderBox->layer()->contentChanged(RenderLayer::CanvasChanged);
+#endif
}
}
#endif
@@ -446,7 +451,7 @@ void CanvasRenderingContext2D::setGlobalCompositeOperation(const String& operati
if (!c)
return;
c->setCompositeOperation(op);
-#if ENABLE(ACCELERATED_2D_CANVAS)
+#if ENABLE(ACCELERATED_2D_CANVAS) && !ENABLE(SKIA_GPU)
if (isAccelerated() && op != CompositeSourceOver) {
c->setSharedGraphicsContext3D(0, 0, IntSize());
m_drawingBuffer.clear();
@@ -877,6 +882,8 @@ bool CanvasRenderingContext2D::isPointInPath(const float x, const float y)
FloatPoint point(x, y);
AffineTransform ctm = state().m_transform;
FloatPoint transformedPoint = ctm.inverse().mapPoint(point);
+ if (!isfinite(transformedPoint.x()) || !isfinite(transformedPoint.y()))
+ return false;
return m_path.contains(transformedPoint);
}
@@ -1771,7 +1778,7 @@ void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, flo
unsigned length = text.length();
const UChar* string = text.characters();
- TextRun textRun(string, length, false, 0, 0, TextRun::AllowTrailingExpansion, rtl, override, false, false);
+ TextRun textRun(string, length, false, 0, 0, TextRun::AllowTrailingExpansion, rtl, override);
// Draw the item text at the correct point.
FloatPoint location(x, y);
diff --git a/Source/WebCore/html/canvas/Int32Array.h b/Source/WebCore/html/canvas/Int32Array.h
index c657300..3a98eed 100644
--- a/Source/WebCore/html/canvas/Int32Array.h
+++ b/Source/WebCore/html/canvas/Int32Array.h
@@ -38,8 +38,8 @@ public:
static PassRefPtr<Int32Array> create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length);
// Can’t use "using" here due to a bug in the RVCT compiler.
- void set(TypedArrayBase<int>* array, unsigned offset, ExceptionCode& ec) { return TypedArrayBase<int>::set(array, offset, ec); }
- void set(unsigned index, double value) { return IntegralTypedArrayBase<int>::set(index, value); }
+ void set(TypedArrayBase<int>* array, unsigned offset, ExceptionCode& ec) { TypedArrayBase<int>::set(array, offset, ec); }
+ void set(unsigned index, double value) { IntegralTypedArrayBase<int>::set(index, value); }
PassRefPtr<Int32Array> subarray(int start) const;
PassRefPtr<Int32Array> subarray(int start, int end) const;
diff --git a/Source/WebCore/html/canvas/Int8Array.h b/Source/WebCore/html/canvas/Int8Array.h
index aabdb97..2d3fc89 100644
--- a/Source/WebCore/html/canvas/Int8Array.h
+++ b/Source/WebCore/html/canvas/Int8Array.h
@@ -40,8 +40,8 @@ public:
static PassRefPtr<Int8Array> create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length);
// Can’t use "using" here due to a bug in the RVCT compiler.
- void set(TypedArrayBase<signed char>* array, unsigned offset, ExceptionCode& ec) { return TypedArrayBase<signed char>::set(array, offset, ec); }
- void set(unsigned index, double value) { return IntegralTypedArrayBase<signed char>::set(index, value); }
+ void set(TypedArrayBase<signed char>* array, unsigned offset, ExceptionCode& ec) { TypedArrayBase<signed char>::set(array, offset, ec); }
+ void set(unsigned index, double value) { IntegralTypedArrayBase<signed char>::set(index, value); }
PassRefPtr<Int8Array> subarray(int start) const;
PassRefPtr<Int8Array> subarray(int start, int end) const;
diff --git a/Source/WebCore/html/canvas/IntegralTypedArrayBase.h b/Source/WebCore/html/canvas/IntegralTypedArrayBase.h
index b87d832..0b26844 100644
--- a/Source/WebCore/html/canvas/IntegralTypedArrayBase.h
+++ b/Source/WebCore/html/canvas/IntegralTypedArrayBase.h
@@ -45,11 +45,9 @@ class IntegralTypedArrayBase : public TypedArrayBase<T> {
return;
if (isnan(value)) // Clamp NaN to 0
value = 0;
- if (value < std::numeric_limits<T>::min())
- value = std::numeric_limits<T>::min();
- else if (value > std::numeric_limits<T>::max())
- value = std::numeric_limits<T>::max();
- TypedArrayBase<T>::data()[index] = static_cast<T>(value);
+ // The double cast is necessary to get the correct wrapping
+ // for out-of-range values with Int32Array and Uint32Array.
+ TypedArrayBase<T>::data()[index] = static_cast<T>(static_cast<int64_t>(value));
}
// Invoked by the indexed getter. Does not perform range checks; caller
diff --git a/Source/WebCore/html/canvas/OESVertexArrayObject.cpp b/Source/WebCore/html/canvas/OESVertexArrayObject.cpp
new file mode 100644
index 0000000..5fb71c8
--- /dev/null
+++ b/Source/WebCore/html/canvas/OESVertexArrayObject.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEBGL)
+
+#include "OESVertexArrayObject.h"
+
+#include "Extensions3D.h"
+#include "WebGLRenderingContext.h"
+#include "WebGLVertexArrayObjectOES.h"
+
+namespace WebCore {
+
+OESVertexArrayObject::OESVertexArrayObject(WebGLRenderingContext* context)
+ : WebGLExtension()
+ , m_context(context)
+{
+}
+
+OESVertexArrayObject::~OESVertexArrayObject()
+{
+}
+
+WebGLExtension::ExtensionName OESVertexArrayObject::getName() const
+{
+ return OESVertexArrayObjectName;
+}
+
+PassRefPtr<OESVertexArrayObject> OESVertexArrayObject::create(WebGLRenderingContext* context)
+{
+ return adoptRef(new OESVertexArrayObject(context));
+}
+
+PassRefPtr<WebGLVertexArrayObjectOES> OESVertexArrayObject::createVertexArrayOES()
+{
+ if (m_context->isContextLost())
+ return 0;
+
+ RefPtr<WebGLVertexArrayObjectOES> o = WebGLVertexArrayObjectOES::create(m_context, WebGLVertexArrayObjectOES::VaoTypeUser);
+ m_context->addObject(o.get());
+ return o.release();
+}
+
+void OESVertexArrayObject::deleteVertexArrayOES(WebGLVertexArrayObjectOES* arrayObject)
+{
+ if (!arrayObject || m_context->isContextLost())
+ return;
+
+ arrayObject->deleteObject();
+}
+
+GC3Dboolean OESVertexArrayObject::isVertexArrayOES(WebGLVertexArrayObjectOES* arrayObject)
+{
+ if (!arrayObject || m_context->isContextLost())
+ return 0;
+
+ if (!arrayObject->hasEverBeenBound())
+ return 0;
+
+ Extensions3D* extensions = m_context->graphicsContext3D()->getExtensions();
+ return extensions->isVertexArrayOES(arrayObject->object());
+}
+
+void OESVertexArrayObject::bindVertexArrayOES(WebGLVertexArrayObjectOES* arrayObject, ExceptionCode& ec)
+{
+ UNUSED_PARAM(ec);
+ if (m_context->isContextLost())
+ return;
+
+ if (arrayObject && arrayObject->context() != m_context) {
+ m_context->graphicsContext3D()->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ return;
+ }
+
+ Extensions3D* extensions = m_context->graphicsContext3D()->getExtensions();
+ if (arrayObject && !arrayObject->isDefaultObject() && arrayObject->object()) {
+ extensions->bindVertexArrayOES(arrayObject->object());
+
+ arrayObject->setHasEverBeenBound();
+ m_context->setBoundVertexArrayObject(arrayObject);
+ } else {
+ extensions->bindVertexArrayOES(0);
+
+ m_context->setBoundVertexArrayObject(0);
+ }
+
+ m_context->cleanupAfterGraphicsCall(false);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEBGL)
diff --git a/Source/WebCore/html/canvas/OESVertexArrayObject.h b/Source/WebCore/html/canvas/OESVertexArrayObject.h
new file mode 100644
index 0000000..d9792da
--- /dev/null
+++ b/Source/WebCore/html/canvas/OESVertexArrayObject.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef OESVertexArrayObject_h
+#define OESVertexArrayObject_h
+
+#include "ExceptionCode.h"
+#include "GraphicsTypes3D.h"
+#include "WebGLExtension.h"
+#include "WebGLVertexArrayObjectOES.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/UnusedParam.h>
+
+namespace WebCore {
+
+class WebGLRenderingContext;
+class WebGLVertexArrayObjectOES;
+
+class OESVertexArrayObject : public WebGLExtension {
+public:
+ static PassRefPtr<OESVertexArrayObject> create(WebGLRenderingContext*);
+
+ virtual ~OESVertexArrayObject();
+ virtual ExtensionName getName() const;
+
+ PassRefPtr<WebGLVertexArrayObjectOES> createVertexArrayOES();
+ void deleteVertexArrayOES(WebGLVertexArrayObjectOES*);
+ GC3Dboolean isVertexArrayOES(WebGLVertexArrayObjectOES*);
+ void bindVertexArrayOES(WebGLVertexArrayObjectOES*, ExceptionCode&);
+
+private:
+ OESVertexArrayObject(WebGLRenderingContext*);
+
+ WebGLRenderingContext* m_context;
+};
+
+} // namespace WebCore
+
+#endif // OESVertexArrayObject_h
diff --git a/Source/WebCore/html/canvas/OESVertexArrayObject.idl b/Source/WebCore/html/canvas/OESVertexArrayObject.idl
new file mode 100644
index 0000000..911ebbc
--- /dev/null
+++ b/Source/WebCore/html/canvas/OESVertexArrayObject.idl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module html {
+ interface [Conditional=WEBGL, OmitConstructor, DontCheckEnums] OESVertexArrayObject {
+ const unsigned int VERTEX_ARRAY_BINDING_OES = 0x85B5;
+
+ [StrictTypeChecking] WebGLVertexArrayObjectOES createVertexArrayOES();
+ [StrictTypeChecking] void deleteVertexArrayOES(in WebGLVertexArrayObjectOES arrayObject);
+ [StrictTypeChecking] boolean isVertexArrayOES(in WebGLVertexArrayObjectOES arrayObject);
+ [StrictTypeChecking] void bindVertexArrayOES(in WebGLVertexArrayObjectOES arrayObject) raises(DOMException);
+ };
+}
diff --git a/Source/WebCore/html/canvas/Uint16Array.h b/Source/WebCore/html/canvas/Uint16Array.h
index 8ef04a4..0b02d09 100644
--- a/Source/WebCore/html/canvas/Uint16Array.h
+++ b/Source/WebCore/html/canvas/Uint16Array.h
@@ -40,8 +40,8 @@ public:
static PassRefPtr<Uint16Array> create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length);
// Can’t use "using" here due to a bug in the RVCT compiler.
- void set(TypedArrayBase<unsigned short>* array, unsigned offset, ExceptionCode& ec) { return TypedArrayBase<unsigned short>::set(array, offset, ec); }
- void set(unsigned index, double value) { return IntegralTypedArrayBase<unsigned short>::set(index, value); }
+ void set(TypedArrayBase<unsigned short>* array, unsigned offset, ExceptionCode& ec) { TypedArrayBase<unsigned short>::set(array, offset, ec); }
+ void set(unsigned index, double value) { IntegralTypedArrayBase<unsigned short>::set(index, value); }
PassRefPtr<Uint16Array> subarray(int start) const;
PassRefPtr<Uint16Array> subarray(int start, int end) const;
diff --git a/Source/WebCore/html/canvas/Uint32Array.h b/Source/WebCore/html/canvas/Uint32Array.h
index 196a67f..15a7ab6 100644
--- a/Source/WebCore/html/canvas/Uint32Array.h
+++ b/Source/WebCore/html/canvas/Uint32Array.h
@@ -40,8 +40,8 @@ public:
static PassRefPtr<Uint32Array> create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length);
// Can’t use "using" here due to a bug in the RVCT compiler.
- void set(TypedArrayBase<unsigned int>* array, unsigned offset, ExceptionCode& ec) { return TypedArrayBase<unsigned int>::set(array, offset, ec); }
- void set(unsigned index, double value) { return IntegralTypedArrayBase<unsigned int>::set(index, value); }
+ void set(TypedArrayBase<unsigned int>* array, unsigned offset, ExceptionCode& ec) { TypedArrayBase<unsigned int>::set(array, offset, ec); }
+ void set(unsigned index, double value) { IntegralTypedArrayBase<unsigned int>::set(index, value); }
PassRefPtr<Uint32Array> subarray(int start) const;
PassRefPtr<Uint32Array> subarray(int start, int end) const;
diff --git a/Source/WebCore/html/canvas/Uint8Array.h b/Source/WebCore/html/canvas/Uint8Array.h
index a3a42dc..3da1eaa 100644
--- a/Source/WebCore/html/canvas/Uint8Array.h
+++ b/Source/WebCore/html/canvas/Uint8Array.h
@@ -40,8 +40,8 @@ public:
static PassRefPtr<Uint8Array> create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length);
// Can’t use "using" here due to a bug in the RVCT compiler.
- void set(TypedArrayBase<unsigned char>* array, unsigned offset, ExceptionCode& ec) { return TypedArrayBase<unsigned char>::set(array, offset, ec); }
- void set(unsigned index, double value) { return IntegralTypedArrayBase<unsigned char>::set(index, value); }
+ void set(TypedArrayBase<unsigned char>* array, unsigned offset, ExceptionCode& ec) { TypedArrayBase<unsigned char>::set(array, offset, ec); }
+ void set(unsigned index, double value) { IntegralTypedArrayBase<unsigned char>::set(index, value); }
PassRefPtr<Uint8Array> subarray(int start) const;
PassRefPtr<Uint8Array> subarray(int start, int end) const;
diff --git a/Source/WebCore/html/canvas/WebGLExtension.h b/Source/WebCore/html/canvas/WebGLExtension.h
index d135c18..9a6753f 100644
--- a/Source/WebCore/html/canvas/WebGLExtension.h
+++ b/Source/WebCore/html/canvas/WebGLExtension.h
@@ -37,6 +37,7 @@ public:
WebKitLoseContextName,
OESTextureFloatName,
OESStandardDerivativesName,
+ OESVertexArrayObjectName,
};
virtual ~WebGLExtension();
diff --git a/Source/WebCore/html/canvas/WebGLGetInfo.cpp b/Source/WebCore/html/canvas/WebGLGetInfo.cpp
index d0c8c65..17be974 100644
--- a/Source/WebCore/html/canvas/WebGLGetInfo.cpp
+++ b/Source/WebCore/html/canvas/WebGLGetInfo.cpp
@@ -38,6 +38,7 @@
#include "WebGLProgram.h"
#include "WebGLRenderbuffer.h"
#include "WebGLTexture.h"
+#include "WebGLVertexArrayObjectOES.h"
namespace WebCore {
@@ -134,6 +135,12 @@ WebGLGetInfo::WebGLGetInfo(PassRefPtr<Uint8Array> value)
{
}
+WebGLGetInfo::WebGLGetInfo(PassRefPtr<WebGLVertexArrayObjectOES> value)
+ : m_type(kTypeWebGLVertexArrayObjectOES)
+ , m_webglVertexArrayObject(value)
+{
+}
+
WebGLGetInfo::~WebGLGetInfo()
{
}
@@ -227,6 +234,12 @@ PassRefPtr<Uint8Array> WebGLGetInfo::getWebGLUnsignedByteArray() const
return m_webglUnsignedByteArray;
}
+PassRefPtr<WebGLVertexArrayObjectOES> WebGLGetInfo::getWebGLVertexArrayObjectOES() const
+{
+ ASSERT(getType() == kTypeWebGLVertexArrayObjectOES);
+ return m_webglVertexArrayObject;
+}
+
} // namespace WebCore
#endif // ENABLE(WEBGL)
diff --git a/Source/WebCore/html/canvas/WebGLGetInfo.h b/Source/WebCore/html/canvas/WebGLGetInfo.h
index 91f9233..bc2aacc 100644
--- a/Source/WebCore/html/canvas/WebGLGetInfo.h
+++ b/Source/WebCore/html/canvas/WebGLGetInfo.h
@@ -36,6 +36,7 @@
#include "WebGLProgram.h"
#include "WebGLRenderbuffer.h"
#include "WebGLTexture.h"
+#include "WebGLVertexArrayObjectOES.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
@@ -65,7 +66,8 @@ public:
kTypeWebGLProgram,
kTypeWebGLRenderbuffer,
kTypeWebGLTexture,
- kTypeWebGLUnsignedByteArray
+ kTypeWebGLUnsignedByteArray,
+ kTypeWebGLVertexArrayObjectOES,
};
WebGLGetInfo(bool value);
@@ -86,6 +88,7 @@ public:
WebGLGetInfo(PassRefPtr<WebGLRenderbuffer> value);
WebGLGetInfo(PassRefPtr<WebGLTexture> value);
WebGLGetInfo(PassRefPtr<Uint8Array> value);
+ WebGLGetInfo(PassRefPtr<WebGLVertexArrayObjectOES> value);
virtual ~WebGLGetInfo();
@@ -107,6 +110,7 @@ public:
PassRefPtr<WebGLRenderbuffer> getWebGLRenderbuffer() const;
PassRefPtr<WebGLTexture> getWebGLTexture() const;
PassRefPtr<Uint8Array> getWebGLUnsignedByteArray() const;
+ PassRefPtr<WebGLVertexArrayObjectOES> getWebGLVertexArrayObjectOES() const;
private:
Type m_type;
@@ -126,6 +130,7 @@ private:
RefPtr<WebGLRenderbuffer> m_webglRenderbuffer;
RefPtr<WebGLTexture> m_webglTexture;
RefPtr<Uint8Array> m_webglUnsignedByteArray;
+ RefPtr<WebGLVertexArrayObjectOES> m_webglVertexArrayObject;
};
} // namespace WebCore
diff --git a/Source/WebCore/html/canvas/WebGLRenderingContext.cpp b/Source/WebCore/html/canvas/WebGLRenderingContext.cpp
index bd155c9..cc7a23b 100644
--- a/Source/WebCore/html/canvas/WebGLRenderingContext.cpp
+++ b/Source/WebCore/html/canvas/WebGLRenderingContext.cpp
@@ -46,6 +46,7 @@
#include "NotImplemented.h"
#include "OESStandardDerivatives.h"
#include "OESTextureFloat.h"
+#include "OESVertexArrayObject.h"
#include "RenderBox.h"
#include "RenderLayer.h"
#include "Settings.h"
@@ -66,6 +67,10 @@
#include <wtf/PassOwnArrayPtr.h>
#include <wtf/text/StringBuilder.h>
+#if PLATFORM(QT)
+#undef emit
+#endif
+
namespace WebCore {
const double secondsBetweenRestoreAttempts = 1.0;
@@ -398,7 +403,6 @@ void WebGLRenderingContext::initializeNewContext()
m_unpackPremultiplyAlpha = false;
m_unpackColorspaceConversion = GraphicsContext3D::BROWSER_DEFAULT_WEBGL;
m_boundArrayBuffer = 0;
- m_boundElementArrayBuffer = 0;
m_currentProgram = 0;
m_framebufferBinding = 0;
m_renderbufferBinding = 0;
@@ -408,7 +412,6 @@ void WebGLRenderingContext::initializeNewContext()
m_stencilFuncRefBack = 0;
m_stencilFuncMask = 0xFFFFFFFF;
m_stencilFuncMaskBack = 0xFFFFFFFF;
- m_vertexAttribState.clear();
GC3Dint numCombinedTextureImageUnits = 0;
m_context->getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numCombinedTextureImageUnits);
@@ -418,13 +421,19 @@ void WebGLRenderingContext::initializeNewContext()
GC3Dint numVertexAttribs = 0;
m_context->getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &numVertexAttribs);
m_maxVertexAttribs = numVertexAttribs;
-
+
m_maxTextureSize = 0;
m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize);
m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize);
m_maxCubeMapTextureSize = 0;
m_context->getIntegerv(GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE, &m_maxCubeMapTextureSize);
m_maxCubeMapTextureLevel = WebGLTexture::computeLevelCount(m_maxCubeMapTextureSize, m_maxCubeMapTextureSize);
+
+ m_defaultVertexArrayObject = WebGLVertexArrayObjectOES::create(this, WebGLVertexArrayObjectOES::VaoTypeDefault);
+ addObject(m_defaultVertexArrayObject.get());
+ m_boundVertexArrayObject = m_defaultVertexArrayObject;
+
+ m_vertexAttribValue.resize(m_maxVertexAttribs);
if (!isGLES2NPOTStrict())
createFallbackBlackTextures1x1();
@@ -457,6 +466,8 @@ WebGLRenderingContext::~WebGLRenderingContext()
{
detachAndRemoveAllObjects();
m_context->setContextLostCallback(0);
+ if (m_webkitLoseContext)
+ m_webkitLoseContext->contextDestroyed();
}
void WebGLRenderingContext::markContextChanged()
@@ -596,7 +607,7 @@ void WebGLRenderingContext::bindBuffer(GC3Denum target, WebGLBuffer* buffer, Exc
if (target == GraphicsContext3D::ARRAY_BUFFER)
m_boundArrayBuffer = buffer;
else if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
- m_boundElementArrayBuffer = buffer;
+ m_boundVertexArrayObject->setElementArrayBuffer(buffer);
else {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
return;
@@ -1112,10 +1123,11 @@ void WebGLRenderingContext::deleteBuffer(WebGLBuffer* buffer)
return;
if (m_boundArrayBuffer == buffer)
m_boundArrayBuffer = 0;
- if (m_boundElementArrayBuffer == buffer)
- m_boundElementArrayBuffer = 0;
+ RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
+ if (elementArrayBuffer == buffer)
+ m_boundVertexArrayObject->setElementArrayBuffer(0);
if (!isGLES2Compliant()) {
- VertexAttribState& state = m_vertexAttribState[0];
+ WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
if (buffer == state.bufferBinding) {
state.bufferBinding = m_vertexAttrib0Buffer;
state.bytesPerElement = 0;
@@ -1236,8 +1248,8 @@ void WebGLRenderingContext::disableVertexAttribArray(GC3Duint index, ExceptionCo
return;
}
- if (index < m_vertexAttribState.size())
- m_vertexAttribState[index].enabled = false;
+ WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
+ state.enabled = false;
if (index > 0 || isGLES2Compliant()) {
m_context->disableVertexAttribArray(index);
@@ -1247,7 +1259,9 @@ void WebGLRenderingContext::disableVertexAttribArray(GC3Duint index, ExceptionCo
bool WebGLRenderingContext::validateElementArraySize(GC3Dsizei count, GC3Denum type, GC3Dintptr offset)
{
- if (!m_boundElementArrayBuffer)
+ RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
+
+ if (!elementArrayBuffer)
return false;
if (offset < 0)
@@ -1261,11 +1275,11 @@ bool WebGLRenderingContext::validateElementArraySize(GC3Dsizei count, GC3Denum t
// Make uoffset an element offset.
offset /= 2;
- GC3Dsizeiptr n = m_boundElementArrayBuffer->byteLength() / 2;
+ GC3Dsizeiptr n = elementArrayBuffer->byteLength() / 2;
if (offset > n || count > n - offset)
return false;
} else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
- GC3Dsizeiptr n = m_boundElementArrayBuffer->byteLength();
+ GC3Dsizeiptr n = elementArrayBuffer->byteLength();
if (offset > n || count > n - offset)
return false;
}
@@ -1279,18 +1293,20 @@ bool WebGLRenderingContext::validateIndexArrayConservative(GC3Denum type, int& n
// array buffers have enough elements to satisfy that maximum
// index, skips the expensive per-draw-call iteration in
// validateIndexArrayPrecise.
+
+ RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
- if (!m_boundElementArrayBuffer)
+ if (!elementArrayBuffer)
return false;
- GC3Dsizeiptr numElements = m_boundElementArrayBuffer->byteLength();
+ GC3Dsizeiptr numElements = elementArrayBuffer->byteLength();
// The case count==0 is already dealt with in drawElements before validateIndexArrayConservative.
if (!numElements)
return false;
- const ArrayBuffer* buffer = m_boundElementArrayBuffer->elementArrayBuffer();
+ const ArrayBuffer* buffer = elementArrayBuffer->elementArrayBuffer();
ASSERT(buffer);
- int maxIndex = m_boundElementArrayBuffer->getCachedMaxIndex(type);
+ int maxIndex = elementArrayBuffer->getCachedMaxIndex(type);
if (maxIndex < 0) {
// Compute the maximum index in the entire buffer for the given type of index.
switch (type) {
@@ -1310,7 +1326,7 @@ bool WebGLRenderingContext::validateIndexArrayConservative(GC3Denum type, int& n
default:
return false;
}
- m_boundElementArrayBuffer->setCachedMaxIndex(type, maxIndex);
+ elementArrayBuffer->setCachedMaxIndex(type, maxIndex);
}
if (maxIndex >= 0) {
@@ -1327,8 +1343,10 @@ bool WebGLRenderingContext::validateIndexArrayPrecise(GC3Dsizei count, GC3Denum
{
ASSERT(count >= 0 && offset >= 0);
int lastIndex = -1;
+
+ RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
- if (!m_boundElementArrayBuffer)
+ if (!elementArrayBuffer)
return false;
if (!count) {
@@ -1336,7 +1354,7 @@ bool WebGLRenderingContext::validateIndexArrayPrecise(GC3Dsizei count, GC3Denum
return true;
}
- if (!m_boundElementArrayBuffer->elementArrayBuffer())
+ if (!elementArrayBuffer->elementArrayBuffer())
return false;
unsigned long uoffset = offset;
@@ -1345,14 +1363,14 @@ bool WebGLRenderingContext::validateIndexArrayPrecise(GC3Dsizei count, GC3Denum
if (type == GraphicsContext3D::UNSIGNED_SHORT) {
// Make uoffset an element offset.
uoffset /= sizeof(GC3Dushort);
- const GC3Dushort* p = static_cast<const GC3Dushort*>(m_boundElementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
+ const GC3Dushort* p = static_cast<const GC3Dushort*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
while (n-- > 0) {
if (*p > lastIndex)
lastIndex = *p;
++p;
}
} else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
- const GC3Dubyte* p = static_cast<const GC3Dubyte*>(m_boundElementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
+ const GC3Dubyte* p = static_cast<const GC3Dubyte*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
while (n-- > 0) {
if (*p > lastIndex)
lastIndex = *p;
@@ -1370,12 +1388,11 @@ bool WebGLRenderingContext::validateRenderingState(int numElementsRequired)
if (!m_currentProgram)
return false;
- int numAttribStates = static_cast<int>(m_vertexAttribState.size());
-
// Look in each enabled vertex attrib and check if they've been bound to a buffer.
- for (int i = 0; i < numAttribStates; ++i) {
- if (m_vertexAttribState[i].enabled
- && (!m_vertexAttribState[i].bufferBinding || !m_vertexAttribState[i].bufferBinding->object()))
+ for (unsigned i = 0; i < m_maxVertexAttribs; ++i) {
+ const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(i);
+ if (state.enabled
+ && (!state.bufferBinding || !state.bufferBinding->object()))
return false;
}
@@ -1387,8 +1404,8 @@ bool WebGLRenderingContext::validateRenderingState(int numElementsRequired)
int numActiveAttribLocations = m_currentProgram->numActiveAttribLocations();
for (int i = 0; i < numActiveAttribLocations; ++i) {
int loc = m_currentProgram->getActiveAttribLocation(i);
- if (loc >=0 && loc < numAttribStates) {
- const VertexAttribState& state = m_vertexAttribState[loc];
+ if (loc >= 0 && loc < static_cast<int>(m_maxVertexAttribs)) {
+ const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(loc);
if (state.enabled) {
// Avoid off-by-one errors in numElements computation.
// For the last element, we will only touch the data for the
@@ -1502,7 +1519,7 @@ void WebGLRenderingContext::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denu
if (!count)
return;
- if (!m_boundElementArrayBuffer) {
+ if (!m_boundVertexArrayObject->getElementArrayBuffer()) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
return;
}
@@ -1568,10 +1585,8 @@ void WebGLRenderingContext::enableVertexAttribArray(GC3Duint index, ExceptionCod
return;
}
- if (index >= m_vertexAttribState.size())
- m_vertexAttribState.resize(index + 1);
-
- m_vertexAttribState[index].enabled = true;
+ WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
+ state.enabled = true;
m_context->enableVertexAttribArray(index);
cleanupAfterGraphicsCall(false);
@@ -1845,6 +1860,14 @@ WebGLExtension* WebGLRenderingContext::getExtension(const String& name)
}
return m_oesTextureFloat.get();
}
+ if (equalIgnoringCase(name, "OES_vertex_array_object")
+ && m_context->getExtensions()->supports("GL_OES_vertex_array_object")) {
+ if (!m_oesVertexArrayObject) {
+ m_context->getExtensions()->ensureEnabled("GL_OES_vertex_array_object");
+ m_oesVertexArrayObject = OESVertexArrayObject::create(this);
+ }
+ return m_oesVertexArrayObject.get();
+ }
if (equalIgnoringCase(name, "WEBKIT_lose_context")) {
if (!m_webkitLoseContext)
m_webkitLoseContext = WebKitLoseContext::create(this);
@@ -1965,7 +1988,7 @@ WebGLGetInfo WebGLRenderingContext::getParameter(GC3Denum pname, ExceptionCode&
case GraphicsContext3D::DITHER:
return getBooleanParameter(pname);
case GraphicsContext3D::ELEMENT_ARRAY_BUFFER_BINDING:
- return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundElementArrayBuffer));
+ return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundVertexArrayObject->getElementArrayBuffer()));
case GraphicsContext3D::FRAMEBUFFER_BINDING:
return WebGLGetInfo(PassRefPtr<WebGLFramebuffer>(m_framebufferBinding));
case GraphicsContext3D::FRONT_FACE:
@@ -2091,6 +2114,14 @@ WebGLGetInfo WebGLRenderingContext::getParameter(GC3Denum pname, ExceptionCode&
return getUnsignedIntParameter(Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
return WebGLGetInfo();
+ case Extensions3D::VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object
+ if (m_oesVertexArrayObject) {
+ if (!m_boundVertexArrayObject->isDefaultObject())
+ return WebGLGetInfo(PassRefPtr<WebGLVertexArrayObjectOES>(m_boundVertexArrayObject));
+ return WebGLGetInfo();
+ }
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
+ return WebGLGetInfo();
default:
m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
return WebGLGetInfo();
@@ -2252,6 +2283,8 @@ Vector<String> WebGLRenderingContext::getSupportedExtensions()
result.append("OES_texture_float");
if (m_context->getExtensions()->supports("GL_OES_standard_derivatives"))
result.append("OES_standard_derivatives");
+ if (m_context->getExtensions()->supports("GL_OES_vertex_array_object"))
+ result.append("OES_vertex_array_object");
result.append("WEBKIT_lose_context");
return result;
}
@@ -2447,40 +2480,26 @@ WebGLGetInfo WebGLRenderingContext::getVertexAttrib(GC3Duint index, GC3Denum pna
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return WebGLGetInfo();
}
+ const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
switch (pname) {
case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
- if ((!isGLES2Compliant() && !index && m_vertexAttribState[0].bufferBinding == m_vertexAttrib0Buffer)
- || index >= m_vertexAttribState.size()
- || !m_vertexAttribState[index].bufferBinding
- || !m_vertexAttribState[index].bufferBinding->object())
+ if ((!isGLES2Compliant() && !index && m_boundVertexArrayObject->getVertexAttribState(0).bufferBinding == m_vertexAttrib0Buffer)
+ || !state.bufferBinding
+ || !state.bufferBinding->object())
return WebGLGetInfo();
- return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_vertexAttribState[index].bufferBinding));
+ return WebGLGetInfo(PassRefPtr<WebGLBuffer>(state.bufferBinding));
case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_ENABLED:
- if (index >= m_vertexAttribState.size())
- return WebGLGetInfo(false);
- return WebGLGetInfo(m_vertexAttribState[index].enabled);
+ return WebGLGetInfo(state.enabled);
case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_NORMALIZED:
- if (index >= m_vertexAttribState.size())
- return WebGLGetInfo(false);
- return WebGLGetInfo(m_vertexAttribState[index].normalized);
+ return WebGLGetInfo(state.normalized);
case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_SIZE:
- if (index >= m_vertexAttribState.size())
- return WebGLGetInfo(static_cast<int>(4));
- return WebGLGetInfo(m_vertexAttribState[index].size);
+ return WebGLGetInfo(state.size);
case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_STRIDE:
- if (index >= m_vertexAttribState.size())
- return WebGLGetInfo(static_cast<int>(0));
- return WebGLGetInfo(m_vertexAttribState[index].originalStride);
+ return WebGLGetInfo(state.originalStride);
case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_TYPE:
- if (index >= m_vertexAttribState.size())
- return WebGLGetInfo(static_cast<unsigned int>(GraphicsContext3D::FLOAT));
- return WebGLGetInfo(m_vertexAttribState[index].type);
+ return WebGLGetInfo(state.type);
case GraphicsContext3D::CURRENT_VERTEX_ATTRIB:
- if (index >= m_vertexAttribState.size()) {
- float value[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
- return WebGLGetInfo(Float32Array::create(value, 4));
- }
- return WebGLGetInfo(Float32Array::create(m_vertexAttribState[index].value, 4));
+ return WebGLGetInfo(Float32Array::create(m_vertexAttribValue[index].value, 4));
default:
m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
return WebGLGetInfo();
@@ -3718,19 +3737,17 @@ void WebGLRenderingContext::vertexAttribPointer(GC3Duint index, GC3Dint size, GC
}
GC3Dsizei bytesPerElement = size * typeSize;
- if (index >= m_vertexAttribState.size())
- m_vertexAttribState.resize(index + 1);
-
GC3Dsizei validatedStride = stride ? stride : bytesPerElement;
- m_vertexAttribState[index].bufferBinding = m_boundArrayBuffer;
- m_vertexAttribState[index].bytesPerElement = bytesPerElement;
- m_vertexAttribState[index].size = size;
- m_vertexAttribState[index].type = type;
- m_vertexAttribState[index].normalized = normalized;
- m_vertexAttribState[index].stride = validatedStride;
- m_vertexAttribState[index].originalStride = stride;
- m_vertexAttribState[index].offset = offset;
+ WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
+ state.bufferBinding = m_boundArrayBuffer;
+ state.bytesPerElement = bytesPerElement;
+ state.size = size;
+ state.type = type;
+ state.normalized = normalized;
+ state.stride = validatedStride;
+ state.originalStride = stride;
+ state.offset = offset;
m_context->vertexAttribPointer(index, size, type, normalized, stride, offset);
cleanupAfterGraphicsCall(false);
}
@@ -4467,7 +4484,7 @@ WebGLBuffer* WebGLRenderingContext::validateBufferDataParameters(GC3Denum target
WebGLBuffer* buffer = 0;
switch (target) {
case GraphicsContext3D::ELEMENT_ARRAY_BUFFER:
- buffer = m_boundElementArrayBuffer.get();
+ buffer = m_boundVertexArrayObject->getElementArrayBuffer().get();
break;
case GraphicsContext3D::ARRAY_BUFFER:
buffer = m_boundArrayBuffer.get();
@@ -4516,12 +4533,11 @@ void WebGLRenderingContext::vertexAttribfImpl(GC3Duint index, GC3Dsizei expected
}
cleanupAfterGraphicsCall(false);
}
- if (index >= m_vertexAttribState.size())
- m_vertexAttribState.resize(index + 1);
- m_vertexAttribState[index].value[0] = v0;
- m_vertexAttribState[index].value[1] = v1;
- m_vertexAttribState[index].value[2] = v2;
- m_vertexAttribState[index].value[3] = v3;
+ VertexAttribValue& attribValue = m_vertexAttribValue[index];
+ attribValue.value[0] = v0;
+ attribValue.value[1] = v1;
+ attribValue.value[2] = v2;
+ attribValue.value[3] = v3;
}
void WebGLRenderingContext::vertexAttribfvImpl(GC3Duint index, Float32Array* v, GC3Dsizei expectedSize)
@@ -4569,21 +4585,21 @@ void WebGLRenderingContext::vertexAttribfvImpl(GC3Duint index, GC3Dfloat* v, GC3
}
cleanupAfterGraphicsCall(false);
}
- if (index >= m_vertexAttribState.size())
- m_vertexAttribState.resize(index + 1);
- m_vertexAttribState[index].initValue();
+ VertexAttribValue& attribValue = m_vertexAttribValue[index];
+ attribValue.initValue();
for (int ii = 0; ii < expectedSize; ++ii)
- m_vertexAttribState[index].value[ii] = v[ii];
+ attribValue.value[ii] = v[ii];
}
void WebGLRenderingContext::initVertexAttrib0()
{
- m_vertexAttribState.resize(1);
+ WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
+
m_vertexAttrib0Buffer = createBuffer();
m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer->object());
m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, 0, GraphicsContext3D::DYNAMIC_DRAW);
m_context->vertexAttribPointer(0, 4, GraphicsContext3D::FLOAT, false, 0, 0);
- m_vertexAttribState[0].bufferBinding = m_vertexAttrib0Buffer;
+ state.bufferBinding = m_vertexAttrib0Buffer;
m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, 0);
m_context->enableVertexAttribArray(0);
m_vertexAttrib0BufferSize = 0;
@@ -4597,7 +4613,8 @@ void WebGLRenderingContext::initVertexAttrib0()
bool WebGLRenderingContext::simulateVertexAttrib0(GC3Dsizei numVertex)
{
- const VertexAttribState& state = m_vertexAttribState[0];
+ const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
+ const VertexAttribValue& attribValue = m_vertexAttribValue[0];
if (!m_currentProgram)
return false;
bool usingVertexAttrib0 = m_currentProgram->isUsingVertexAttrib0();
@@ -4617,21 +4634,21 @@ bool WebGLRenderingContext::simulateVertexAttrib0(GC3Dsizei numVertex)
}
if (usingVertexAttrib0
&& (m_forceAttrib0BufferRefill
- || state.value[0] != m_vertexAttrib0BufferValue[0]
- || state.value[1] != m_vertexAttrib0BufferValue[1]
- || state.value[2] != m_vertexAttrib0BufferValue[2]
- || state.value[3] != m_vertexAttrib0BufferValue[3])) {
+ || attribValue.value[0] != m_vertexAttrib0BufferValue[0]
+ || attribValue.value[1] != m_vertexAttrib0BufferValue[1]
+ || attribValue.value[2] != m_vertexAttrib0BufferValue[2]
+ || attribValue.value[3] != m_vertexAttrib0BufferValue[3])) {
OwnArrayPtr<GC3Dfloat> bufferData = adoptArrayPtr(new GC3Dfloat[(numVertex + 1) * 4]);
for (GC3Dsizei ii = 0; ii < numVertex + 1; ++ii) {
- bufferData[ii * 4] = state.value[0];
- bufferData[ii * 4 + 1] = state.value[1];
- bufferData[ii * 4 + 2] = state.value[2];
- bufferData[ii * 4 + 3] = state.value[3];
+ bufferData[ii * 4] = attribValue.value[0];
+ bufferData[ii * 4 + 1] = attribValue.value[1];
+ bufferData[ii * 4 + 2] = attribValue.value[2];
+ bufferData[ii * 4 + 3] = attribValue.value[3];
}
- m_vertexAttrib0BufferValue[0] = state.value[0];
- m_vertexAttrib0BufferValue[1] = state.value[1];
- m_vertexAttrib0BufferValue[2] = state.value[2];
- m_vertexAttrib0BufferValue[3] = state.value[3];
+ m_vertexAttrib0BufferValue[0] = attribValue.value[0];
+ m_vertexAttrib0BufferValue[1] = attribValue.value[1];
+ m_vertexAttrib0BufferValue[2] = attribValue.value[2];
+ m_vertexAttrib0BufferValue[3] = attribValue.value[3];
m_forceAttrib0BufferRefill = false;
m_context->bufferSubData(GraphicsContext3D::ARRAY_BUFFER, 0, bufferDataSize, bufferData.get());
}
@@ -4641,7 +4658,7 @@ bool WebGLRenderingContext::simulateVertexAttrib0(GC3Dsizei numVertex)
void WebGLRenderingContext::restoreStatesAfterVertexAttrib0Simulation()
{
- const VertexAttribState& state = m_vertexAttribState[0];
+ const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
if (state.bufferBinding != m_vertexAttrib0Buffer) {
m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, objectOrZero(state.bufferBinding.get()));
m_context->vertexAttribPointer(0, state.size, state.type, state.normalized, state.originalStride, state.offset);
@@ -4651,11 +4668,16 @@ void WebGLRenderingContext::restoreStatesAfterVertexAttrib0Simulation()
int WebGLRenderingContext::getNumberOfExtensions()
{
- return (m_oesStandardDerivatives ? 1 : 0) + (m_webkitLoseContext ? 1 : 0) + (m_oesTextureFloat ? 1 : 0);
+ return (m_oesVertexArrayObject ? 1 : 0) + (m_oesStandardDerivatives ? 1 : 0) + (m_webkitLoseContext ? 1 : 0) + (m_oesTextureFloat ? 1 : 0);
}
WebGLExtension* WebGLRenderingContext::getExtensionNumber(int i)
{
+ if (m_oesVertexArrayObject) {
+ if (!i)
+ return m_oesVertexArrayObject.get();
+ --i;
+ }
if (m_oesStandardDerivatives) {
if (!i)
return m_oesStandardDerivatives.get();
diff --git a/Source/WebCore/html/canvas/WebGLRenderingContext.h b/Source/WebCore/html/canvas/WebGLRenderingContext.h
index dd71620..13145c8 100644
--- a/Source/WebCore/html/canvas/WebGLRenderingContext.h
+++ b/Source/WebCore/html/canvas/WebGLRenderingContext.h
@@ -59,6 +59,8 @@ class ImageData;
class IntSize;
class OESStandardDerivatives;
class OESTextureFloat;
+class OESVertexArrayObject;
+class WebGLVertexArrayObjectOES;
class WebGLRenderingContext : public CanvasRenderingContext {
public:
@@ -286,6 +288,8 @@ public:
virtual void paintRenderingResultsToCanvas();
void removeObject(WebGLObject*);
+
+ unsigned getMaxVertexAttribs() const { return m_maxVertexAttribs; }
// Helpers for JSC bindings.
int getNumberOfExtensions();
@@ -293,6 +297,7 @@ public:
private:
friend class WebGLObject;
+ friend class OESVertexArrayObject;
WebGLRenderingContext(HTMLCanvasElement*, PassRefPtr<GraphicsContext3D>, GraphicsContext3D::Attributes);
void initializeNewContext();
@@ -362,24 +367,24 @@ public:
// List of bound VBO's. Used to maintain info about sizes for ARRAY_BUFFER and stored values for ELEMENT_ARRAY_BUFFER
RefPtr<WebGLBuffer> m_boundArrayBuffer;
- RefPtr<WebGLBuffer> m_boundElementArrayBuffer;
-
- // Cached values for vertex attrib range checks
- class VertexAttribState {
+
+ RefPtr<WebGLVertexArrayObjectOES> m_defaultVertexArrayObject;
+ RefPtr<WebGLVertexArrayObjectOES> m_boundVertexArrayObject;
+ void setBoundVertexArrayObject(PassRefPtr<WebGLVertexArrayObjectOES> arrayObject)
+ {
+ if (arrayObject)
+ m_boundVertexArrayObject = arrayObject;
+ else
+ m_boundVertexArrayObject = m_defaultVertexArrayObject;
+ }
+
+ class VertexAttribValue {
public:
- VertexAttribState()
- : enabled(false)
- , bytesPerElement(0)
- , size(4)
- , type(GraphicsContext3D::FLOAT)
- , normalized(false)
- , stride(16)
- , originalStride(0)
- , offset(0)
+ VertexAttribValue()
{
initValue();
}
-
+
void initValue()
{
value[0] = 0.0f;
@@ -387,20 +392,10 @@ public:
value[2] = 0.0f;
value[3] = 1.0f;
}
-
- bool enabled;
- RefPtr<WebGLBuffer> bufferBinding;
- GC3Dsizei bytesPerElement;
- GC3Dint size;
- GC3Denum type;
- bool normalized;
- GC3Dsizei stride;
- GC3Dsizei originalStride;
- GC3Dintptr offset;
+
GC3Dfloat value[4];
};
-
- Vector<VertexAttribState> m_vertexAttribState;
+ Vector<VertexAttribValue> m_vertexAttribValue;
unsigned m_maxVertexAttribs;
RefPtr<WebGLBuffer> m_vertexAttrib0Buffer;
long m_vertexAttrib0BufferSize;
@@ -462,6 +457,7 @@ public:
// Enabled extension objects.
RefPtr<OESTextureFloat> m_oesTextureFloat;
RefPtr<OESStandardDerivatives> m_oesStandardDerivatives;
+ RefPtr<OESVertexArrayObject> m_oesVertexArrayObject;
RefPtr<WebKitLoseContext> m_webkitLoseContext;
// Helpers for getParameter and others
diff --git a/Source/WebCore/html/canvas/WebGLVertexArrayObjectOES.cpp b/Source/WebCore/html/canvas/WebGLVertexArrayObjectOES.cpp
new file mode 100644
index 0000000..d14c96c
--- /dev/null
+++ b/Source/WebCore/html/canvas/WebGLVertexArrayObjectOES.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEBGL)
+
+#include "WebGLVertexArrayObjectOES.h"
+
+#include "Extensions3D.h"
+#include "WebGLRenderingContext.h"
+
+namespace WebCore {
+
+PassRefPtr<WebGLVertexArrayObjectOES> WebGLVertexArrayObjectOES::create(WebGLRenderingContext* ctx, VaoType type)
+{
+ return adoptRef(new WebGLVertexArrayObjectOES(ctx, type));
+}
+
+WebGLVertexArrayObjectOES::WebGLVertexArrayObjectOES(WebGLRenderingContext* ctx, VaoType type)
+ : WebGLObject(ctx)
+ , m_type(type)
+ , m_hasEverBeenBound(false)
+ , m_boundElementArrayBuffer(0)
+{
+ m_vertexAttribState.resize(ctx->getMaxVertexAttribs());
+
+ Extensions3D* extensions = context()->graphicsContext3D()->getExtensions();
+ switch (m_type) {
+ case VaoTypeDefault:
+ break;
+ default:
+ setObject(extensions->createVertexArrayOES());
+ break;
+ }
+}
+
+void WebGLVertexArrayObjectOES::deleteObjectImpl(Platform3DObject object)
+{
+ Extensions3D* extensions = context()->graphicsContext3D()->getExtensions();
+ switch (m_type) {
+ case VaoTypeDefault:
+ break;
+ default:
+ extensions->deleteVertexArrayOES(object);
+ break;
+ }
+}
+
+}
+
+#endif // ENABLE(WEBGL)
diff --git a/Source/WebCore/html/canvas/WebGLVertexArrayObjectOES.h b/Source/WebCore/html/canvas/WebGLVertexArrayObjectOES.h
new file mode 100644
index 0000000..f49a780
--- /dev/null
+++ b/Source/WebCore/html/canvas/WebGLVertexArrayObjectOES.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WebGLVertexArrayObjectOES_h
+#define WebGLVertexArrayObjectOES_h
+
+#include "WebGLBuffer.h"
+#include "WebGLObject.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class WebGLVertexArrayObjectOES : public WebGLObject {
+public:
+ enum VaoType {
+ VaoTypeDefault,
+ VaoTypeUser,
+ };
+
+ virtual ~WebGLVertexArrayObjectOES() { deleteObject(); }
+
+ static PassRefPtr<WebGLVertexArrayObjectOES> create(WebGLRenderingContext*, VaoType);
+
+ // Cached values for vertex attrib range checks
+ struct VertexAttribState {
+ VertexAttribState()
+ : enabled(false)
+ , bytesPerElement(0)
+ , size(4)
+ , type(GraphicsContext3D::FLOAT)
+ , normalized(false)
+ , stride(16)
+ , originalStride(0)
+ , offset(0)
+ {
+ }
+
+ bool enabled;
+ RefPtr<WebGLBuffer> bufferBinding;
+ GC3Dsizei bytesPerElement;
+ GC3Dint size;
+ GC3Denum type;
+ bool normalized;
+ GC3Dsizei stride;
+ GC3Dsizei originalStride;
+ GC3Dintptr offset;
+ };
+
+ bool isDefaultObject() const { return m_type == VaoTypeDefault; }
+
+ bool hasEverBeenBound() const { return object() && m_hasEverBeenBound; }
+ void setHasEverBeenBound() { m_hasEverBeenBound = true; }
+
+ PassRefPtr<WebGLBuffer> getElementArrayBuffer() const { return m_boundElementArrayBuffer; }
+ void setElementArrayBuffer(PassRefPtr<WebGLBuffer> buffer) { m_boundElementArrayBuffer = buffer; }
+
+ VertexAttribState& getVertexAttribState(int index) { return m_vertexAttribState[index]; }
+
+private:
+ WebGLVertexArrayObjectOES(WebGLRenderingContext*, VaoType);
+
+ virtual void deleteObjectImpl(Platform3DObject);
+
+ virtual bool isVertexArray() const { return true; }
+
+ VaoType m_type;
+ bool m_hasEverBeenBound;
+ RefPtr<WebGLBuffer> m_boundElementArrayBuffer;
+ Vector<VertexAttribState> m_vertexAttribState;
+};
+
+} // namespace WebCore
+
+#endif // WebGLVertexArrayObjectOES_h
diff --git a/Source/WebCore/html/canvas/WebGLVertexArrayObjectOES.idl b/Source/WebCore/html/canvas/WebGLVertexArrayObjectOES.idl
new file mode 100644
index 0000000..8582b36
--- /dev/null
+++ b/Source/WebCore/html/canvas/WebGLVertexArrayObjectOES.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module html {
+ interface [Conditional=WEBGL] WebGLVertexArrayObjectOES {
+ };
+}
diff --git a/Source/WebCore/html/canvas/WebKitLoseContext.cpp b/Source/WebCore/html/canvas/WebKitLoseContext.cpp
index 05e82f4..c594e32 100644
--- a/Source/WebCore/html/canvas/WebKitLoseContext.cpp
+++ b/Source/WebCore/html/canvas/WebKitLoseContext.cpp
@@ -55,7 +55,8 @@ PassRefPtr<WebKitLoseContext> WebKitLoseContext::create(WebGLRenderingContext* c
void WebKitLoseContext::loseContext()
{
- m_context->forceLostContext();
+ if (m_context)
+ m_context->forceLostContext();
}
} // namespace WebCore
diff --git a/Source/WebCore/html/canvas/WebKitLoseContext.h b/Source/WebCore/html/canvas/WebKitLoseContext.h
index e25e084..b713bef 100644
--- a/Source/WebCore/html/canvas/WebKitLoseContext.h
+++ b/Source/WebCore/html/canvas/WebKitLoseContext.h
@@ -42,6 +42,7 @@ public:
virtual ExtensionName getName() const;
void loseContext();
+ void contextDestroyed() { m_context = 0; }
private:
WebKitLoseContext(WebGLRenderingContext*);
diff --git a/Source/WebCore/html/parser/HTMLConstructionSite.cpp b/Source/WebCore/html/parser/HTMLConstructionSite.cpp
index a026ef9..2be6039 100644
--- a/Source/WebCore/html/parser/HTMLConstructionSite.cpp
+++ b/Source/WebCore/html/parser/HTMLConstructionSite.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -58,16 +59,16 @@ using namespace HTMLNames;
namespace {
-bool hasImpliedEndTag(Element* element)
+bool hasImpliedEndTag(ContainerNode* node)
{
- return element->hasTagName(ddTag)
- || element->hasTagName(dtTag)
- || element->hasTagName(liTag)
- || element->hasTagName(optionTag)
- || element->hasTagName(optgroupTag)
- || element->hasTagName(pTag)
- || element->hasTagName(rpTag)
- || element->hasTagName(rtTag);
+ return node->hasTagName(ddTag)
+ || node->hasTagName(dtTag)
+ || node->hasTagName(liTag)
+ || node->hasTagName(optionTag)
+ || node->hasTagName(optgroupTag)
+ || node->hasTagName(pTag)
+ || node->hasTagName(rpTag)
+ || node->hasTagName(rtTag);
}
bool causesFosterParenting(const QualifiedName& tagName)
@@ -204,6 +205,12 @@ void HTMLConstructionSite::mergeAttributesFromTokenIntoElement(AtomicHTMLToken&
void HTMLConstructionSite::insertHTMLHtmlStartTagInBody(AtomicHTMLToken& token)
{
// FIXME: parse error
+
+ // Fragments do not have a root HTML element, so any additional HTML elements
+ // encountered during fragment parsing should be ignored.
+ if (m_isParsingFragment)
+ return;
+
mergeAttributesFromTokenIntoElement(token, m_openElements.htmlElement());
}
@@ -236,7 +243,7 @@ void HTMLConstructionSite::insertDoctype(AtomicHTMLToken& token)
void HTMLConstructionSite::insertComment(AtomicHTMLToken& token)
{
ASSERT(token.type() == HTMLToken::Comment);
- attach(currentElement(), Comment::create(currentElement()->document(), token.comment()));
+ attach(currentNode(), Comment::create(currentNode()->document(), token.comment()));
}
void HTMLConstructionSite::insertCommentOnDocument(AtomicHTMLToken& token)
@@ -248,13 +255,13 @@ void HTMLConstructionSite::insertCommentOnDocument(AtomicHTMLToken& token)
void HTMLConstructionSite::insertCommentOnHTMLHtmlElement(AtomicHTMLToken& token)
{
ASSERT(token.type() == HTMLToken::Comment);
- Element* parent = m_openElements.htmlElement();
+ ContainerNode* parent = m_openElements.rootNode();
attach(parent, Comment::create(parent->document(), token.comment()));
}
PassRefPtr<Element> HTMLConstructionSite::attachToCurrent(PassRefPtr<Element> child)
{
- return attach(currentElement(), child);
+ return attach(currentNode(), child);
}
void HTMLConstructionSite::insertHTMLHeadElement(AtomicHTMLToken& token)
@@ -310,7 +317,7 @@ void HTMLConstructionSite::insertFormattingElement(AtomicHTMLToken& token)
void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken& token)
{
- RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(scriptTag, currentElement()->document(), true);
+ RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(scriptTag, currentNode()->document(), true);
if (m_fragmentScriptingPermission == FragmentScriptingAllowed)
element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission);
m_openElements.push(attachToCurrent(element.release()));
@@ -329,27 +336,40 @@ void HTMLConstructionSite::insertForeignElement(AtomicHTMLToken& token, const At
void HTMLConstructionSite::insertTextNode(const String& characters)
{
AttachmentSite site;
- site.parent = currentElement();
+ site.parent = currentNode();
site.nextChild = 0;
if (shouldFosterParent())
findFosterSite(site);
+ unsigned currentPosition = 0;
+
+ // FIXME: Splitting text nodes into smaller chunks contradicts HTML5 spec, but is currently necessary
+ // for performance, see <https://bugs.webkit.org/show_bug.cgi?id=55898>.
+
Node* previousChild = site.nextChild ? site.nextChild->previousSibling() : site.parent->lastChild();
if (previousChild && previousChild->isTextNode()) {
// FIXME: We're only supposed to append to this text node if it
// was the last text node inserted by the parser.
CharacterData* textNode = static_cast<CharacterData*>(previousChild);
- textNode->parserAppendData(characters);
- return;
+ currentPosition = textNode->parserAppendData(characters.characters(), characters.length(), Text::defaultLengthLimit);
}
- attachAtSite(site, Text::create(site.parent->document(), characters));
+ while (currentPosition < characters.length()) {
+ RefPtr<Text> textNode = Text::createWithLengthLimit(site.parent->document(), characters, currentPosition);
+ // If we have a whole string of unbreakable characters the above could lead to an infinite loop. Exceeding the length limit is the lesser evil.
+ if (!textNode->length())
+ textNode = Text::create(site.parent->document(), characters.substring(currentPosition));
+
+ currentPosition += textNode->length();
+ ASSERT(currentPosition <= characters.length());
+ attachAtSite(site, textNode.release());
+ }
}
PassRefPtr<Element> HTMLConstructionSite::createElement(AtomicHTMLToken& token, const AtomicString& namespaceURI)
{
QualifiedName tagName(nullAtom, token.name(), namespaceURI);
- RefPtr<Element> element = currentElement()->document()->createElement(tagName, true);
+ RefPtr<Element> element = currentNode()->document()->createElement(tagName, true);
element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission);
return element.release();
}
@@ -360,7 +380,7 @@ PassRefPtr<Element> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken& tok
// FIXME: This can't use HTMLConstructionSite::createElement because we
// have to pass the current form element. We should rework form association
// to occur after construction to allow better code sharing here.
- RefPtr<Element> element = HTMLElementFactory::createHTMLElement(tagName, currentElement()->document(), form(), true);
+ RefPtr<Element> element = HTMLElementFactory::createHTMLElement(tagName, currentNode()->document(), form(), true);
element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission);
ASSERT(element->isHTMLElement());
return element.release();
@@ -439,13 +459,13 @@ void HTMLConstructionSite::reconstructTheActiveFormattingElements()
void HTMLConstructionSite::generateImpliedEndTagsWithExclusion(const AtomicString& tagName)
{
- while (hasImpliedEndTag(currentElement()) && !currentElement()->hasLocalName(tagName))
+ while (hasImpliedEndTag(currentNode()) && !currentNode()->hasLocalName(tagName))
m_openElements.pop();
}
void HTMLConstructionSite::generateImpliedEndTags()
{
- while (hasImpliedEndTag(currentElement()))
+ while (hasImpliedEndTag(currentNode()))
m_openElements.pop();
}
@@ -464,13 +484,14 @@ void HTMLConstructionSite::findFosterSite(AttachmentSite& site)
return;
}
// Fragment case
- site.parent = m_openElements.bottom(); // <html> element
+ site.parent = m_openElements.rootNode(); // DocumentFragment
site.nextChild = 0;
}
bool HTMLConstructionSite::shouldFosterParent() const
{
return m_redirectAttachToFosterParent
+ && currentNode()->isElementNode()
&& causesFosterParenting(currentElement()->tagQName());
}
diff --git a/Source/WebCore/html/parser/HTMLConstructionSite.h b/Source/WebCore/html/parser/HTMLConstructionSite.h
index 0298503..380e487 100644
--- a/Source/WebCore/html/parser/HTMLConstructionSite.h
+++ b/Source/WebCore/html/parser/HTMLConstructionSite.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -80,6 +81,7 @@ public:
void generateImpliedEndTagsWithExclusion(const AtomicString& tagName);
Element* currentElement() const { return m_openElements.top(); }
+ ContainerNode* currentNode() const { return m_openElements.topNode(); }
Element* oneBelowTop() const { return m_openElements.oneBelowTop(); }
HTMLElementStack* openElements() const { return &m_openElements; }
diff --git a/Source/WebCore/html/parser/HTMLDocumentParser.cpp b/Source/WebCore/html/parser/HTMLDocumentParser.cpp
index 2fe9486..843df45 100644
--- a/Source/WebCore/html/parser/HTMLDocumentParser.cpp
+++ b/Source/WebCore/html/parser/HTMLDocumentParser.cpp
@@ -86,7 +86,7 @@ HTMLDocumentParser::HTMLDocumentParser(HTMLDocument* document, bool reportErrors
, m_parserScheduler(HTMLParserScheduler::create(this))
, m_xssFilter(this)
, m_endWasDelayed(false)
- , m_writeNestingLevel(0)
+ , m_pumpSessionNestingLevel(0)
{
}
@@ -98,7 +98,7 @@ HTMLDocumentParser::HTMLDocumentParser(DocumentFragment* fragment, Element* cont
, m_treeBuilder(HTMLTreeBuilder::create(this, fragment, contextElement, scriptingPermission, usePreHTML5ParserQuirks(fragment->document())))
, m_xssFilter(this)
, m_endWasDelayed(false)
- , m_writeNestingLevel(0)
+ , m_pumpSessionNestingLevel(0)
{
bool reportErrors = false; // For now document fragment parsing never reports errors.
m_tokenizer->setState(tokenizerStateForContextElement(contextElement, reportErrors));
@@ -107,7 +107,7 @@ HTMLDocumentParser::HTMLDocumentParser(DocumentFragment* fragment, Element* cont
HTMLDocumentParser::~HTMLDocumentParser()
{
ASSERT(!m_parserScheduler);
- ASSERT(!m_writeNestingLevel);
+ ASSERT(!m_pumpSessionNestingLevel);
ASSERT(!m_preloadScanner);
}
@@ -155,9 +155,14 @@ void HTMLDocumentParser::prepareToStopParsing()
attemptToRunDeferredScriptsAndEnd();
}
+bool HTMLDocumentParser::isParsingFragment() const
+{
+ return m_treeBuilder->isParsingFragment();
+}
+
bool HTMLDocumentParser::processingData() const
{
- return isScheduledForResume() || inWrite();
+ return isScheduledForResume() || inPumpSession();
}
void HTMLDocumentParser::pumpTokenizerIfPossible(SynchronousMode mode)
@@ -204,6 +209,36 @@ bool HTMLDocumentParser::runScriptsForPausedTreeBuilder()
return m_scriptRunner->execute(scriptElement.release(), scriptStartPosition);
}
+bool HTMLDocumentParser::canTakeNextToken(SynchronousMode mode, PumpSession& session)
+{
+ if (isStopped())
+ return false;
+
+ // The parser will pause itself when waiting on a script to load or run.
+ if (m_treeBuilder->isPaused()) {
+ // If we're paused waiting for a script, we try to execute scripts before continuing.
+ bool shouldContinueParsing = runScriptsForPausedTreeBuilder();
+ m_treeBuilder->setPaused(!shouldContinueParsing);
+ if (!shouldContinueParsing || isStopped())
+ return false;
+ }
+
+ // FIXME: It's wrong for the HTMLDocumentParser to reach back to the
+ // Frame, but this approach is how the old parser handled
+ // stopping when the page assigns window.location. What really
+ // should happen is that assigning window.location causes the
+ // parser to stop parsing cleanly. The problem is we're not
+ // perpared to do that at every point where we run JavaScript.
+ if (!isParsingFragment()
+ && document()->frame() && document()->frame()->navigationScheduler()->locationChangePending())
+ return false;
+
+ if (mode == AllowYield)
+ m_parserScheduler->checkForYieldBeforeToken(session);
+
+ return true;
+}
+
void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
{
ASSERT(!isStopped());
@@ -212,6 +247,8 @@ void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
// ASSERT that this object is both attached to the Document and protected.
ASSERT(refCount() >= 2);
+ PumpSession session(m_pumpSessionNestingLevel);
+
// We tell the InspectorInstrumentation about every pump, even if we
// end up pumping nothing. It can filter out empty pumps itself.
// FIXME: m_input.current().length() is only accurate if we
@@ -219,53 +256,35 @@ void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
// much we parsed as part of didWriteHTML instead of willWriteHTML.
InspectorInstrumentationCookie cookie = InspectorInstrumentation::willWriteHTML(document(), m_input.current().length(), m_tokenizer->lineNumber());
- HTMLParserScheduler::PumpSession session;
- // FIXME: This loop body has is now too long and needs cleanup.
- while (mode == ForceSynchronous || m_parserScheduler->shouldContinueParsing(session)) {
- // FIXME: It's wrong for the HTMLDocumentParser to reach back to the
- // Frame, but this approach is how the old parser handled
- // stopping when the page assigns window.location. What really
- // should happen is that assigning window.location causes the
- // parser to stop parsing cleanly. The problem is we're not
- // perpared to do that at every point where we run JavaScript.
- if (!m_treeBuilder->isParsingFragment()
- && document()->frame() && document()->frame()->navigationScheduler()->locationChangePending())
- break;
+ while (canTakeNextToken(mode, session) && !session.needsYield) {
+ if (!isParsingFragment())
+ m_sourceTracker.start(m_input, m_token);
- m_sourceTracker.start(m_input, m_token);
if (!m_tokenizer->nextToken(m_input.current(), m_token))
break;
- m_sourceTracker.end(m_input, m_token);
- m_xssFilter.filterToken(m_token);
+ if (!isParsingFragment()) {
+ m_sourceTracker.end(m_input, m_token);
+
+ // We do not XSS filter innerHTML, which means we (intentionally) fail
+ // http/tests/security/xssAuditor/dom-write-innerHTML.html
+ m_xssFilter.filterToken(m_token);
+ }
m_treeBuilder->constructTreeFromToken(m_token);
m_token.clear();
-
- // JavaScript may have stopped or detached the parser.
- if (isStopped())
- return;
-
- // The parser will pause itself when waiting on a script to load or run.
- if (!m_treeBuilder->isPaused())
- continue;
-
- // If we're paused waiting for a script, we try to execute scripts before continuing.
- bool shouldContinueParsing = runScriptsForPausedTreeBuilder();
- m_treeBuilder->setPaused(!shouldContinueParsing);
-
- // JavaScript may have stopped or detached the parser.
- if (isStopped())
- return;
-
- if (!shouldContinueParsing)
- break;
}
// Ensure we haven't been totally deref'ed after pumping. Any caller of this
// function should be holding a RefPtr to this to ensure we weren't deleted.
ASSERT(refCount() >= 1);
+ if (isStopped())
+ return;
+
+ if (session.needsYield)
+ m_parserScheduler->scheduleForResume();
+
if (isWaitingForScripts()) {
ASSERT(m_tokenizer->state() == HTMLTokenizer::DataState);
if (!m_preloadScanner) {
@@ -301,14 +320,10 @@ void HTMLDocumentParser::insert(const SegmentedString& source)
// but we need to ensure it isn't deleted yet.
RefPtr<HTMLDocumentParser> protect(this);
- {
- NestingLevelIncrementer nestingLevelIncrementer(m_writeNestingLevel);
-
- SegmentedString excludedLineNumberSource(source);
- excludedLineNumberSource.setExcludeLineNumbers();
- m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource);
- pumpTokenizerIfPossible(ForceSynchronous);
- }
+ SegmentedString excludedLineNumberSource(source);
+ excludedLineNumberSource.setExcludeLineNumbers();
+ m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource);
+ pumpTokenizerIfPossible(ForceSynchronous);
endIfDelayed();
}
@@ -322,13 +337,11 @@ void HTMLDocumentParser::append(const SegmentedString& source)
// but we need to ensure it isn't deleted yet.
RefPtr<HTMLDocumentParser> protect(this);
- {
- NestingLevelIncrementer nestingLevelIncrementer(m_writeNestingLevel);
-
- m_input.appendToEnd(source);
- if (m_preloadScanner)
- m_preloadScanner->appendToEnd(source);
+ m_input.appendToEnd(source);
+ if (m_preloadScanner)
+ m_preloadScanner->appendToEnd(source);
+<<<<<<< HEAD
if (m_writeNestingLevel > 1) {
// We've gotten data off the network in a nested write.
// We don't want to consume any more of the input stream now. Do
@@ -340,8 +353,17 @@ void HTMLDocumentParser::append(const SegmentedString& source)
}
pumpTokenizerIfPossible(AllowYield);
+=======
+ if (inPumpSession()) {
+ // We've gotten data off the network in a nested write.
+ // We don't want to consume any more of the input stream now. Do
+ // not worry. We'll consume this data in a less-nested write().
+ return;
+>>>>>>> WebKit at r80534
}
+ pumpTokenizerIfPossible(AllowYield);
+
endIfDelayed();
#ifdef ANDROID_INSTRUMENT
android::TimeCounter::record(android::TimeCounter::ParsingTimeCounter, __FUNCTION__);
diff --git a/Source/WebCore/html/parser/HTMLDocumentParser.h b/Source/WebCore/html/parser/HTMLDocumentParser.h
index be2ca1b..4bc33e4 100644
--- a/Source/WebCore/html/parser/HTMLDocumentParser.h
+++ b/Source/WebCore/html/parser/HTMLDocumentParser.h
@@ -51,6 +51,8 @@ class HTMLPreloadScanner;
class ScriptController;
class ScriptSourceCode;
+class PumpSession;
+
class HTMLDocumentParser : public ScriptableDocumentParser, HTMLScriptRunnerHost, CachedResourceClient {
WTF_MAKE_FAST_ALLOCATED;
public:
@@ -116,6 +118,7 @@ private:
AllowYield,
ForceSynchronous,
};
+ bool canTakeNextToken(SynchronousMode, PumpSession&);
void pumpTokenizer(SynchronousMode);
void pumpTokenizerIfPossible(SynchronousMode);
@@ -128,10 +131,11 @@ private:
void attemptToRunDeferredScriptsAndEnd();
void end();
+ bool isParsingFragment() const;
bool isScheduledForResume() const;
bool inScriptExecution() const;
- bool inWrite() const { return m_writeNestingLevel > 0; }
- bool shouldDelayEnd() const { return inWrite() || isWaitingForScripts() || inScriptExecution() || isScheduledForResume(); }
+ bool inPumpSession() const { return m_pumpSessionNestingLevel > 0; }
+ bool shouldDelayEnd() const { return inPumpSession() || isWaitingForScripts() || inScriptExecution() || isScheduledForResume(); }
ScriptController* script() const;
@@ -149,7 +153,7 @@ private:
XSSFilter m_xssFilter;
bool m_endWasDelayed;
- unsigned m_writeNestingLevel;
+ unsigned m_pumpSessionNestingLevel;
};
}
diff --git a/Source/WebCore/html/parser/HTMLElementStack.cpp b/Source/WebCore/html/parser/HTMLElementStack.cpp
index 6aab0f7..6f5f9ed 100644
--- a/Source/WebCore/html/parser/HTMLElementStack.cpp
+++ b/Source/WebCore/html/parser/HTMLElementStack.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,6 +27,7 @@
#include "config.h"
#include "HTMLElementStack.h"
+#include "DocumentFragment.h"
#include "Element.h"
#include "HTMLNames.h"
#include "MathMLNames.h"
@@ -38,62 +40,68 @@ using namespace HTMLNames;
namespace {
-inline bool isNumberedHeaderElement(Element* element)
+inline bool isNumberedHeaderElement(ContainerNode* node)
{
- return element->hasTagName(h1Tag)
- || element->hasTagName(h2Tag)
- || element->hasTagName(h3Tag)
- || element->hasTagName(h4Tag)
- || element->hasTagName(h5Tag)
- || element->hasTagName(h6Tag);
+ return node->hasTagName(h1Tag)
+ || node->hasTagName(h2Tag)
+ || node->hasTagName(h3Tag)
+ || node->hasTagName(h4Tag)
+ || node->hasTagName(h5Tag)
+ || node->hasTagName(h6Tag);
+}
+
+inline bool isRootMarker(ContainerNode* node)
+{
+ return node->nodeType() == Node::DOCUMENT_FRAGMENT_NODE
+ || node->hasTagName(htmlTag);
}
-inline bool isScopeMarker(Element* element)
+inline bool isScopeMarker(ContainerNode* node)
{
- return element->hasTagName(appletTag)
- || element->hasTagName(captionTag)
- || element->hasTagName(htmlTag)
- || element->hasTagName(marqueeTag)
- || element->hasTagName(objectTag)
- || element->hasTagName(tableTag)
- || element->hasTagName(tdTag)
- || element->hasTagName(thTag)
- || element->hasTagName(MathMLNames::miTag)
- || element->hasTagName(MathMLNames::moTag)
- || element->hasTagName(MathMLNames::mnTag)
- || element->hasTagName(MathMLNames::msTag)
- || element->hasTagName(MathMLNames::mtextTag)
- || element->hasTagName(MathMLNames::annotation_xmlTag)
- || element->hasTagName(SVGNames::foreignObjectTag)
- || element->hasTagName(SVGNames::descTag)
- || element->hasTagName(SVGNames::titleTag);
+ return node->hasTagName(appletTag)
+ || node->hasTagName(captionTag)
+ || node->hasTagName(marqueeTag)
+ || node->hasTagName(objectTag)
+ || node->hasTagName(tableTag)
+ || node->hasTagName(tdTag)
+ || node->hasTagName(thTag)
+ || node->hasTagName(MathMLNames::miTag)
+ || node->hasTagName(MathMLNames::moTag)
+ || node->hasTagName(MathMLNames::mnTag)
+ || node->hasTagName(MathMLNames::msTag)
+ || node->hasTagName(MathMLNames::mtextTag)
+ || node->hasTagName(MathMLNames::annotation_xmlTag)
+ || node->hasTagName(SVGNames::foreignObjectTag)
+ || node->hasTagName(SVGNames::descTag)
+ || node->hasTagName(SVGNames::titleTag)
+ || isRootMarker(node);
}
-inline bool isListItemScopeMarker(Element* element)
+inline bool isListItemScopeMarker(ContainerNode* node)
{
- return isScopeMarker(element)
- || element->hasTagName(olTag)
- || element->hasTagName(ulTag);
+ return isScopeMarker(node)
+ || node->hasTagName(olTag)
+ || node->hasTagName(ulTag);
}
-inline bool isTableScopeMarker(Element* element)
+inline bool isTableScopeMarker(ContainerNode* node)
{
- return element->hasTagName(tableTag)
- || element->hasTagName(htmlTag);
+ return node->hasTagName(tableTag)
+ || isRootMarker(node);
}
-inline bool isTableBodyScopeMarker(Element* element)
+inline bool isTableBodyScopeMarker(ContainerNode* node)
{
- return element->hasTagName(tbodyTag)
- || element->hasTagName(tfootTag)
- || element->hasTagName(theadTag)
- || element->hasTagName(htmlTag);
+ return node->hasTagName(tbodyTag)
+ || node->hasTagName(tfootTag)
+ || node->hasTagName(theadTag)
+ || isRootMarker(node);
}
-inline bool isTableRowScopeMarker(Element* element)
+inline bool isTableRowScopeMarker(ContainerNode* node)
{
- return element->hasTagName(trTag)
- || element->hasTagName(htmlTag);
+ return node->hasTagName(trTag)
+ || isRootMarker(node);
}
inline bool isForeignContentScopeMarker(Element* element)
@@ -109,25 +117,25 @@ inline bool isForeignContentScopeMarker(Element* element)
|| element->namespaceURI() == HTMLNames::xhtmlNamespaceURI;
}
-inline bool isButtonScopeMarker(Element* element)
+inline bool isButtonScopeMarker(ContainerNode* node)
{
- return isScopeMarker(element)
- || element->hasTagName(buttonTag);
+ return isScopeMarker(node)
+ || node->hasTagName(buttonTag);
}
-inline bool isSelectScopeMarker(Element* element)
+inline bool isSelectScopeMarker(ContainerNode* node)
{
- return !element->hasTagName(optgroupTag)
- && !element->hasTagName(optionTag);
+ return !node->hasTagName(optgroupTag)
+ && !node->hasTagName(optionTag);
}
}
-HTMLElementStack::ElementRecord::ElementRecord(PassRefPtr<Element> element, PassOwnPtr<ElementRecord> next)
- : m_element(element)
+HTMLElementStack::ElementRecord::ElementRecord(PassRefPtr<ContainerNode> node, PassOwnPtr<ElementRecord> next)
+ : m_node(node)
, m_next(next)
{
- ASSERT(m_element);
+ ASSERT(m_node);
}
HTMLElementStack::ElementRecord::~ElementRecord()
@@ -137,8 +145,9 @@ HTMLElementStack::ElementRecord::~ElementRecord()
void HTMLElementStack::ElementRecord::replaceElement(PassRefPtr<Element> element)
{
ASSERT(element);
+ ASSERT(!m_node || m_node->isElementNode());
// FIXME: Should this call finishParsingChildren?
- m_element = element;
+ m_node = element;
}
bool HTMLElementStack::ElementRecord::isAbove(ElementRecord* other) const
@@ -151,7 +160,7 @@ bool HTMLElementStack::ElementRecord::isAbove(ElementRecord* other) const
}
HTMLElementStack::HTMLElementStack()
- : m_htmlElement(0)
+ : m_rootNode(0)
, m_headElement(0)
, m_bodyElement(0)
{
@@ -171,7 +180,7 @@ bool HTMLElementStack::secondElementIsHTMLBodyElement() const
// This is used the fragment case of <body> and <frameset> in the "in body"
// insertion mode.
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-inbody
- ASSERT(m_htmlElement);
+ ASSERT(m_rootNode);
// If we have a body element, it must always be the second element on the
// stack, as we always start with an html element, and any other element
// would cause the implicit creation of a body element.
@@ -194,11 +203,11 @@ void HTMLElementStack::popHTMLBodyElement()
void HTMLElementStack::popAll()
{
- m_htmlElement = 0;
+ m_rootNode = 0;
m_headElement = 0;
m_bodyElement = 0;
while (m_top) {
- top()->finishParsingChildren();
+ topNode()->finishParsingChildren();
m_top = m_top->releaseNext();
}
}
@@ -226,7 +235,7 @@ void HTMLElementStack::popUntilPopped(const AtomicString& tagName)
void HTMLElementStack::popUntilNumberedHeaderElementPopped()
{
- while (!isNumberedHeaderElement(top()))
+ while (!isNumberedHeaderElement(topNode()))
pop();
pop();
}
@@ -246,21 +255,21 @@ void HTMLElementStack::popUntilPopped(Element* element)
void HTMLElementStack::popUntilTableScopeMarker()
{
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#clear-the-stack-back-to-a-table-context
- while (!isTableScopeMarker(top()))
+ while (!isTableScopeMarker(topNode()))
pop();
}
void HTMLElementStack::popUntilTableBodyScopeMarker()
{
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#clear-the-stack-back-to-a-table-body-context
- while (!isTableBodyScopeMarker(top()))
+ while (!isTableBodyScopeMarker(topNode()))
pop();
}
void HTMLElementStack::popUntilTableRowScopeMarker()
{
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#clear-the-stack-back-to-a-table-row-context
- while (!isTableRowScopeMarker(top()))
+ while (!isTableRowScopeMarker(topNode()))
pop();
}
@@ -269,14 +278,25 @@ void HTMLElementStack::popUntilForeignContentScopeMarker()
while (!isForeignContentScopeMarker(top()))
pop();
}
+
+void HTMLElementStack::pushRootNode(PassRefPtr<ContainerNode> rootNode)
+{
+ ASSERT(rootNode->nodeType() == Node::DOCUMENT_FRAGMENT_NODE);
+ pushRootNodeCommon(rootNode);
+}
void HTMLElementStack::pushHTMLHtmlElement(PassRefPtr<Element> element)
{
- ASSERT(!m_top); // <html> should always be the bottom of the stack.
ASSERT(element->hasTagName(HTMLNames::htmlTag));
- ASSERT(!m_htmlElement);
- m_htmlElement = element.get();
- pushCommon(element);
+ pushRootNodeCommon(element);
+}
+
+void HTMLElementStack::pushRootNodeCommon(PassRefPtr<ContainerNode> rootNode)
+{
+ ASSERT(!m_top);
+ ASSERT(!m_rootNode);
+ m_rootNode = rootNode.get();
+ pushCommon(rootNode);
}
void HTMLElementStack::pushHTMLHeadElement(PassRefPtr<Element> element)
@@ -300,7 +320,7 @@ void HTMLElementStack::push(PassRefPtr<Element> element)
ASSERT(!element->hasTagName(HTMLNames::htmlTag));
ASSERT(!element->hasTagName(HTMLNames::headTag));
ASSERT(!element->hasTagName(HTMLNames::bodyTag));
- ASSERT(m_htmlElement);
+ ASSERT(m_rootNode);
pushCommon(element);
}
@@ -312,7 +332,7 @@ void HTMLElementStack::insertAbove(PassRefPtr<Element> element, ElementRecord* r
ASSERT(!element->hasTagName(HTMLNames::htmlTag));
ASSERT(!element->hasTagName(HTMLNames::headTag));
ASSERT(!element->hasTagName(HTMLNames::bodyTag));
- ASSERT(m_htmlElement);
+ ASSERT(m_rootNode);
if (recordBelow == m_top) {
push(element);
return;
@@ -372,7 +392,7 @@ void HTMLElementStack::remove(Element* element)
HTMLElementStack::ElementRecord* HTMLElementStack::find(Element* element) const
{
for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
- if (pos->element() == element)
+ if (pos->node() == element)
return pos;
}
return 0;
@@ -381,7 +401,7 @@ HTMLElementStack::ElementRecord* HTMLElementStack::find(Element* element) const
HTMLElementStack::ElementRecord* HTMLElementStack::topmost(const AtomicString& tagName) const
{
for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
- if (pos->element()->hasLocalName(tagName))
+ if (pos->node()->hasLocalName(tagName))
return pos;
}
return 0;
@@ -397,14 +417,14 @@ bool HTMLElementStack::contains(const AtomicString& tagName) const
return !!topmost(tagName);
}
-template <bool isMarker(Element*)>
+template <bool isMarker(ContainerNode*)>
bool inScopeCommon(HTMLElementStack::ElementRecord* top, const AtomicString& targetTag)
{
for (HTMLElementStack::ElementRecord* pos = top; pos; pos = pos->next()) {
- Element* element = pos->element();
- if (element->hasLocalName(targetTag))
+ ContainerNode* node = pos->node();
+ if (node->hasLocalName(targetTag))
return true;
- if (isMarker(element))
+ if (isMarker(node))
return false;
}
ASSERT_NOT_REACHED(); // <html> is always on the stack and is a scope marker.
@@ -427,10 +447,10 @@ bool HTMLElementStack::hasOnlyHTMLElementsInScope() const
bool HTMLElementStack::hasNumberedHeaderElementInScope() const
{
for (ElementRecord* record = m_top.get(); record; record = record->next()) {
- Element* element = record->element();
- if (isNumberedHeaderElement(element))
+ ContainerNode* node = record->node();
+ if (isNumberedHeaderElement(node))
return true;
- if (isScopeMarker(element))
+ if (isScopeMarker(node))
return false;
}
ASSERT_NOT_REACHED(); // <html> is always on the stack and is a scope marker.
@@ -507,8 +527,8 @@ bool HTMLElementStack::inSelectScope(const QualifiedName& tagName) const
Element* HTMLElementStack::htmlElement() const
{
- ASSERT(m_htmlElement);
- return m_htmlElement;
+ ASSERT(m_rootNode);
+ return toElement(m_rootNode);
}
Element* HTMLElementStack::headElement() const
@@ -522,12 +542,18 @@ Element* HTMLElementStack::bodyElement() const
ASSERT(m_bodyElement);
return m_bodyElement;
}
+
+ContainerNode* HTMLElementStack::rootNode() const
+{
+ ASSERT(m_rootNode);
+ return m_rootNode;
+}
-void HTMLElementStack::pushCommon(PassRefPtr<Element> element)
+void HTMLElementStack::pushCommon(PassRefPtr<ContainerNode> node)
{
- ASSERT(m_htmlElement);
- m_top = adoptPtr(new ElementRecord(element, m_top.release()));
- top()->beginParsingChildren();
+ ASSERT(m_rootNode);
+ m_top = adoptPtr(new ElementRecord(node, m_top.release()));
+ topNode()->beginParsingChildren();
}
void HTMLElementStack::popCommon()
diff --git a/Source/WebCore/html/parser/HTMLElementStack.h b/Source/WebCore/html/parser/HTMLElementStack.h
index ad8b941..a710932 100644
--- a/Source/WebCore/html/parser/HTMLElementStack.h
+++ b/Source/WebCore/html/parser/HTMLElementStack.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,6 +27,7 @@
#ifndef HTMLElementStack_h
#define HTMLElementStack_h
+#include "Element.h"
#include <wtf/Forward.h>
#include <wtf/Noncopyable.h>
#include <wtf/OwnPtr.h>
@@ -34,6 +36,8 @@
namespace WebCore {
+class ContainerNode;
+class DocumentFragment;
class Element;
class QualifiedName;
@@ -50,7 +54,8 @@ public:
public:
~ElementRecord(); // Public for ~PassOwnPtr()
- Element* element() const { return m_element.get(); }
+ Element* element() const { return toElement(m_node.get()); }
+ ContainerNode* node() const { return m_node.get(); }
void replaceElement(PassRefPtr<Element>);
bool isAbove(ElementRecord*) const;
@@ -60,12 +65,12 @@ public:
private:
friend class HTMLElementStack;
- ElementRecord(PassRefPtr<Element>, PassOwnPtr<ElementRecord>);
+ ElementRecord(PassRefPtr<ContainerNode>, PassOwnPtr<ElementRecord>);
PassOwnPtr<ElementRecord> releaseNext() { return m_next.release(); }
void setNext(PassOwnPtr<ElementRecord> next) { m_next = next; }
- RefPtr<Element> m_element;
+ RefPtr<ContainerNode> m_node;
OwnPtr<ElementRecord> m_next;
};
@@ -76,6 +81,12 @@ public:
ASSERT(m_top->element());
return m_top->element();
}
+
+ ContainerNode* topNode() const
+ {
+ ASSERT(m_top->node());
+ return m_top->node();
+ }
Element* oneBelowTop() const;
ElementRecord* topRecord() const;
@@ -86,6 +97,7 @@ public:
void insertAbove(PassRefPtr<Element>, ElementRecord*);
void push(PassRefPtr<Element>);
+ void pushRootNode(PassRefPtr<ContainerNode>);
void pushHTMLHtmlElement(PassRefPtr<Element>);
void pushHTMLHeadElement(PassRefPtr<Element>);
void pushHTMLBodyElement(PassRefPtr<Element>);
@@ -131,24 +143,27 @@ public:
Element* htmlElement() const;
Element* headElement() const;
Element* bodyElement() const;
+
+ ContainerNode* rootNode() const;
#ifndef NDEBUG
void show();
#endif
private:
- void pushCommon(PassRefPtr<Element>);
+ void pushCommon(PassRefPtr<ContainerNode>);
+ void pushRootNodeCommon(PassRefPtr<ContainerNode>);
void popCommon();
void removeNonTopCommon(Element*);
OwnPtr<ElementRecord> m_top;
- // We remember <html>, <head> and <body> as they are pushed. Their
- // ElementRecords keep them alive. <html> is never popped.
+ // We remember the root node, <head> and <body> as they are pushed. Their
+ // ElementRecords keep them alive. The root node is never popped.
// FIXME: We don't currently require type-specific information about
// these elements so we haven't yet bothered to plumb the types all the
// way down through createElement, etc.
- Element* m_htmlElement;
+ ContainerNode* m_rootNode;
Element* m_headElement;
Element* m_bodyElement;
};
diff --git a/Source/WebCore/html/parser/HTMLParserScheduler.cpp b/Source/WebCore/html/parser/HTMLParserScheduler.cpp
index 56db1aa..c4525c8 100644
--- a/Source/WebCore/html/parser/HTMLParserScheduler.cpp
+++ b/Source/WebCore/html/parser/HTMLParserScheduler.cpp
@@ -74,25 +74,24 @@ HTMLParserScheduler::~HTMLParserScheduler()
m_continueNextChunkTimer.stop();
}
-// FIXME: This belongs on Document.
-static bool isLayoutTimerActive(Document* doc)
-{
- ASSERT(doc);
- return doc->view() && doc->view()->layoutPending() && !doc->minimumLayoutDelay();
-}
-
void HTMLParserScheduler::continueNextChunkTimerFired(Timer<HTMLParserScheduler>* timer)
{
ASSERT_UNUSED(timer, timer == &m_continueNextChunkTimer);
// FIXME: The timer class should handle timer priorities instead of this code.
// If a layout is scheduled, wait again to let the layout timer run first.
- if (isLayoutTimerActive(m_parser->document())) {
+ if (m_parser->document()->isLayoutTimerActive()) {
m_continueNextChunkTimer.startOneShot(0);
return;
}
m_parser->resumeParsingAfterYield();
}
+void HTMLParserScheduler::scheduleForResume()
+{
+ m_continueNextChunkTimer.startOneShot(0);
+}
+
+
void HTMLParserScheduler::suspend()
{
ASSERT(!m_isSuspendedWithActiveTimer);
diff --git a/Source/WebCore/html/parser/HTMLParserScheduler.h b/Source/WebCore/html/parser/HTMLParserScheduler.h
index c415c62..9aa12eb 100644
--- a/Source/WebCore/html/parser/HTMLParserScheduler.h
+++ b/Source/WebCore/html/parser/HTMLParserScheduler.h
@@ -26,6 +26,7 @@
#ifndef HTMLParserScheduler_h
#define HTMLParserScheduler_h
+#include "NestingLevelIncrementer.h"
#include "Timer.h"
#include <wtf/CurrentTime.h>
#include <wtf/PassOwnPtr.h>
@@ -34,6 +35,21 @@ namespace WebCore {
class HTMLDocumentParser;
+class PumpSession : public NestingLevelIncrementer {
+public:
+ PumpSession(unsigned& nestingLevel)
+ : NestingLevelIncrementer(nestingLevel)
+ , processedTokens(0)
+ , startTime(currentTime())
+ , needsYield(false)
+ {
+ }
+
+ int processedTokens;
+ double startTime;
+ bool needsYield;
+};
+
class HTMLParserScheduler {
WTF_MAKE_NONCOPYABLE(HTMLParserScheduler); WTF_MAKE_FAST_ALLOCATED;
public:
@@ -43,34 +59,19 @@ public:
}
~HTMLParserScheduler();
- struct PumpSession {
- PumpSession()
- : processedTokens(0)
- , startTime(currentTime())
- {
- }
-
- int processedTokens;
- double startTime;
- };
-
// Inline as this is called after every token in the parser.
- bool shouldContinueParsing(PumpSession& session)
+ void checkForYieldBeforeToken(PumpSession& session)
{
if (session.processedTokens > m_parserChunkSize) {
session.processedTokens = 0;
double elapsedTime = currentTime() - session.startTime;
- if (elapsedTime > m_parserTimeLimit) {
- // Schedule the parser to continue and yield from the parser.
- m_continueNextChunkTimer.startOneShot(0);
- return false;
- }
+ if (elapsedTime > m_parserTimeLimit)
+ session.needsYield = true;
}
-
++session.processedTokens;
- return true;
}
+ void scheduleForResume();
bool isScheduledForResume() const { return m_isSuspendedWithActiveTimer || m_continueNextChunkTimer.isActive(); }
void suspend();
diff --git a/Source/WebCore/html/parser/HTMLScriptRunner.cpp b/Source/WebCore/html/parser/HTMLScriptRunner.cpp
index c99858d..99fff5e 100644
--- a/Source/WebCore/html/parser/HTMLScriptRunner.cpp
+++ b/Source/WebCore/html/parser/HTMLScriptRunner.cpp
@@ -262,17 +262,9 @@ void HTMLScriptRunner::requestDeferredScript(Element* element)
bool HTMLScriptRunner::requestPendingScript(PendingScript& pendingScript, Element* script) const
{
ASSERT(!pendingScript.element());
- const AtomicString& srcValue = script->getAttribute(srcAttr);
- // Allow the host to disllow script loads (using the XSSAuditor, etc.)
- // FIXME: this check should be performed on the final URL in a redirect chain.
- if (!m_host->shouldLoadExternalScriptFromSrc(srcValue))
- return false;
- // FIXME: We need to resolve the url relative to the element.
- if (!script->dispatchBeforeLoadEvent(srcValue))
- return false;
pendingScript.setElement(script);
// This should correctly return 0 for empty or invalid srcValues.
- CachedScript* cachedScript = m_document->cachedResourceLoader()->requestScript(srcValue, toScriptElement(script)->scriptCharset());
+ CachedScript* cachedScript = toScriptElement(script)->cachedScript().get();
if (!cachedScript) {
notImplemented(); // Dispatch error event.
return false;
@@ -293,29 +285,24 @@ void HTMLScriptRunner::runScript(Element* script, const TextPosition1& scriptSta
ScriptElement* scriptElement = toScriptElement(script);
ASSERT(scriptElement);
- if (!scriptElement->shouldExecuteAsJavaScript())
+
+ scriptElement->prepareScript(scriptStartPosition);
+
+ if (!scriptElement->willBeParserExecuted())
return;
-
- if (script->hasAttribute(srcAttr)) {
- if (script->hasAttribute(asyncAttr)) // Async takes precendence over defer.
- return; // Asynchronous scripts handle themselves.
-
- if (script->hasAttribute(deferAttr))
- requestDeferredScript(script);
- else
- requestParsingBlockingScript(script);
- } else if (!m_document->haveStylesheetsLoaded() && m_scriptNestingLevel == 1) {
- // Block inline script execution on stylesheet load, unless we are in document.write().
- // The latter case can only happen if a script both triggers a stylesheet load
- // and writes an inline script. Since write is blocking we have to execute the
- // written script immediately, ignoring the pending sheets.
- m_parsingBlockingScript.setElement(script);
- m_parsingBlockingScript.setStartingPosition(scriptStartPosition);
- } else {
- ASSERT(isExecutingScript());
- ScriptSourceCode sourceCode(script->textContent(), documentURLForScriptExecution(m_document), scriptStartPosition);
- scriptElement->executeScript(sourceCode);
- }
+
+ if (scriptElement->willExecuteWhenDocumentFinishedParsing())
+ requestDeferredScript(script);
+ else if (scriptElement->readyToBeParserExecuted()) {
+ if (m_scriptNestingLevel == 1) {
+ m_parsingBlockingScript.setElement(script);
+ m_parsingBlockingScript.setStartingPosition(scriptStartPosition);
+ } else {
+ ScriptSourceCode sourceCode(script->textContent(), documentURLForScriptExecution(m_document), scriptStartPosition);
+ scriptElement->executeScript(sourceCode);
+ }
+ } else
+ requestParsingBlockingScript(script);
}
}
diff --git a/Source/WebCore/html/parser/HTMLTreeBuilder.cpp b/Source/WebCore/html/parser/HTMLTreeBuilder.cpp
index d2931ac..8f9e3e1 100644
--- a/Source/WebCore/html/parser/HTMLTreeBuilder.cpp
+++ b/Source/WebCore/html/parser/HTMLTreeBuilder.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -122,6 +123,8 @@ bool isSpecialNode(Node* node)
|| node->hasTagName(SVGNames::descTag)
|| node->hasTagName(SVGNames::titleTag))
return true;
+ if (node->nodeType() == Node::DOCUMENT_FRAGMENT_NODE)
+ return true;
if (node->namespaceURI() != xhtmlNamespaceURI)
return false;
const AtomicString& tagName = node->localName();
@@ -375,7 +378,9 @@ HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser* parser, DocumentFragment* f
if (contextElement) {
// Steps 4.2-4.6 of the HTML5 Fragment Case parsing algorithm:
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#fragment-case
- processFakeStartTag(htmlTag);
+ // For efficiency, we skip step 4.2 ("Let root be a new html element with no attributes")
+ // and instead use the DocumentFragment as a root node.
+ m_tree.openElements()->pushRootNode(fragment);
resetInsertionModeAppropriately();
m_tree.setForm(closestFormAncestor(contextElement));
}
@@ -410,19 +415,6 @@ HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext(DocumentFragment
ASSERT(!fragment->hasChildNodes());
}
-void HTMLTreeBuilder::FragmentParsingContext::finished()
-{
- if (!m_contextElement)
- return;
-
- // The HTML5 spec says to return the children of the fragment's document
- // element when there is a context element (10.4.7).
- RefPtr<ContainerNode> documentElement = firstElementChild(m_fragment);
- m_fragment->removeChildren();
- ASSERT(documentElement);
- m_fragment->takeAllChildrenFrom(documentElement.get());
-}
-
HTMLTreeBuilder::FragmentParsingContext::~FragmentParsingContext()
{
}
@@ -453,7 +445,7 @@ void HTMLTreeBuilder::constructTreeFromAtomicToken(AtomicHTMLToken& token)
// the U+0000 characters into replacement characters has compatibility
// problems.
m_parser->tokenizer()->setForceNullCharacterReplacement(m_insertionMode == TextMode || m_insertionMode == InForeignContentMode);
- m_parser->tokenizer()->setShouldAllowCDATA(m_insertionMode == InForeignContentMode && m_tree.currentElement()->namespaceURI() != xhtmlNamespaceURI);
+ m_parser->tokenizer()->setShouldAllowCDATA(m_insertionMode == InForeignContentMode && m_tree.currentNode()->namespaceURI() != xhtmlNamespaceURI);
}
void HTMLTreeBuilder::processToken(AtomicHTMLToken& token)
@@ -574,12 +566,12 @@ void HTMLTreeBuilder::processIsindexStartTagForInBody(AtomicHTMLToken& token)
namespace {
-bool isLi(const Element* element)
+bool isLi(const ContainerNode* element)
{
return element->hasTagName(liTag);
}
-bool isDdOrDt(const Element* element)
+bool isDdOrDt(const ContainerNode* element)
{
return element->hasTagName(ddTag)
|| element->hasTagName(dtTag);
@@ -587,15 +579,16 @@ bool isDdOrDt(const Element* element)
}
-template <bool shouldClose(const Element*)>
+template <bool shouldClose(const ContainerNode*)>
void HTMLTreeBuilder::processCloseWhenNestedTag(AtomicHTMLToken& token)
{
m_framesetOk = false;
HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord();
while (1) {
- Element* node = nodeRecord->element();
+ ContainerNode* node = nodeRecord->node();
if (shouldClose(node)) {
- processFakeEndTag(node->tagQName());
+ ASSERT(node->isElementNode());
+ processFakeEndTag(toElement(node)->tagQName());
break;
}
if (isSpecialNode(node) && !node->hasTagName(addressTag) && !node->hasTagName(divTag) && !node->hasTagName(pTag))
@@ -786,7 +779,7 @@ void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken& token)
}
if (isNumberedHeaderTag(token.name())) {
processFakePEndTagIfPInButtonScope();
- if (isNumberedHeaderTag(m_tree.currentElement()->localName())) {
+ if (isNumberedHeaderTag(m_tree.currentNode()->localName())) {
parseError(token);
m_tree.openElements()->pop();
}
@@ -978,7 +971,7 @@ void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken& token)
if (token.name() == rpTag || token.name() == rtTag) {
if (m_tree.openElements()->inScope(rubyTag.localName())) {
m_tree.generateImpliedEndTags();
- if (!m_tree.currentElement()->hasTagName(rubyTag)) {
+ if (!m_tree.currentNode()->hasTagName(rubyTag)) {
parseError(token);
m_tree.openElements()->popUntil(rubyTag.localName());
}
@@ -1019,7 +1012,7 @@ void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken& token)
bool HTMLTreeBuilder::processColgroupEndTagForInColumnGroup()
{
- if (m_tree.currentElement() == m_tree.openElements()->htmlElement()) {
+ if (m_tree.currentNode() == m_tree.openElements()->rootNode()) {
ASSERT(isParsingFragment());
// FIXME: parse error
return false;
@@ -1115,7 +1108,7 @@ void HTMLTreeBuilder::processStartTagForInTable(AtomicHTMLToken& token)
namespace {
-bool shouldProcessForeignContentUsingInBodyInsertionMode(AtomicHTMLToken& token, Element* currentElement)
+bool shouldProcessForeignContentUsingInBodyInsertionMode(AtomicHTMLToken& token, ContainerNode* currentElement)
{
ASSERT(token.type() == HTMLToken::StartTag);
if (currentElement->hasTagName(MathMLNames::miTag)
@@ -1409,7 +1402,7 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token)
return;
}
if (token.name() == optionTag) {
- if (m_tree.currentElement()->hasTagName(optionTag)) {
+ if (m_tree.currentNode()->hasTagName(optionTag)) {
AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());
processEndTag(endOption);
}
@@ -1417,11 +1410,11 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token)
return;
}
if (token.name() == optgroupTag) {
- if (m_tree.currentElement()->hasTagName(optionTag)) {
+ if (m_tree.currentNode()->hasTagName(optionTag)) {
AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());
processEndTag(endOption);
}
- if (m_tree.currentElement()->hasTagName(optgroupTag)) {
+ if (m_tree.currentNode()->hasTagName(optgroupTag)) {
AtomicHTMLToken endOptgroup(HTMLToken::EndTag, optgroupTag.localName());
processEndTag(endOptgroup);
}
@@ -1543,20 +1536,24 @@ void HTMLTreeBuilder::processAnyOtherEndTagForInBody(AtomicHTMLToken& token)
ASSERT(token.type() == HTMLToken::EndTag);
HTMLElementStack::ElementRecord* record = m_tree.openElements()->topRecord();
while (1) {
- Element* node = record->element();
+ ContainerNode* node = record->node();
if (node->hasLocalName(token.name())) {
m_tree.generateImpliedEndTags();
- if (!m_tree.currentElement()->hasLocalName(token.name())) {
+ // FIXME: The ElementRecord pointed to by record might be deleted by
+ // the preceding call. Perhaps we should hold a RefPtr so that it
+ // stays alive for the duration of record's scope.
+ record = 0;
+ if (!m_tree.currentNode()->hasLocalName(token.name())) {
parseError(token);
// FIXME: This is either a bug in the spec, or a bug in our
// implementation. Filed a bug with HTML5:
// http://www.w3.org/Bugs/Public/show_bug.cgi?id=10080
// We might have already popped the node for the token in
// generateImpliedEndTags, just abort.
- if (!m_tree.openElements()->contains(node))
+ if (!m_tree.openElements()->contains(toElement(node)))
return;
}
- m_tree.openElements()->popUntilPopped(node);
+ m_tree.openElements()->popUntilPopped(toElement(node));
return;
}
if (isSpecialNode(node)) {
@@ -1616,7 +1613,7 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken& token)
}
// 4.
ASSERT(furthestBlock->isAbove(formattingElementRecord));
- Element* commonAncestor = formattingElementRecord->next()->element();
+ ContainerNode* commonAncestor = formattingElementRecord->next()->node();
// 5.
HTMLFormattingElementList::Bookmark bookmark = m_tree.activeFormattingElements()->bookmarkFor(formattingElement);
// 6.
@@ -1668,7 +1665,9 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken& token)
m_tree.fosterParent(lastNode->element());
else {
commonAncestor->parserAddChild(lastNode->element());
- if (lastNode->element()->parentElement()->attached() && !lastNode->element()->attached())
+ ASSERT(lastNode->node()->isElementNode());
+ ASSERT(lastNode->element()->parentNode());
+ if (lastNode->element()->parentNode()->attached() && !lastNode->element()->attached())
lastNode->element()->lazyAttach();
}
// 8
@@ -1700,8 +1699,8 @@ void HTMLTreeBuilder::resetInsertionModeAppropriately()
bool last = false;
HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord();
while (1) {
- Element* node = nodeRecord->element();
- if (node == m_tree.openElements()->bottom()) {
+ ContainerNode* node = nodeRecord->node();
+ if (node == m_tree.openElements()->rootNode()) {
ASSERT(isParsingFragment());
last = true;
node = m_fragmentContext.contextElement();
@@ -1831,7 +1830,7 @@ void HTMLTreeBuilder::processEndTagForInCell(AtomicHTMLToken& token)
return;
}
m_tree.generateImpliedEndTags();
- if (!m_tree.currentElement()->hasLocalName(token.name()))
+ if (!m_tree.currentNode()->hasLocalName(token.name()))
parseError(token);
m_tree.openElements()->popUntilPopped(token.name());
m_tree.activeFormattingElements()->clearToLastMarker();
@@ -1901,7 +1900,7 @@ void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken& token)
return;
}
m_tree.generateImpliedEndTags();
- if (!m_tree.currentElement()->hasLocalName(token.name()))
+ if (!m_tree.currentNode()->hasLocalName(token.name()))
parseError(token);
m_tree.openElements()->popUntilPopped(token.name());
return;
@@ -1926,7 +1925,7 @@ void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken& token)
return;
}
m_tree.generateImpliedEndTagsWithExclusion(token.name());
- if (!m_tree.currentElement()->hasLocalName(token.name()))
+ if (!m_tree.currentNode()->hasLocalName(token.name()))
parseError(token);
m_tree.openElements()->popUntilPopped(token.name());
return;
@@ -1937,7 +1936,7 @@ void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken& token)
return;
}
m_tree.generateImpliedEndTagsWithExclusion(token.name());
- if (!m_tree.currentElement()->hasLocalName(token.name()))
+ if (!m_tree.currentNode()->hasLocalName(token.name()))
parseError(token);
m_tree.openElements()->popUntilPopped(token.name());
return;
@@ -1949,7 +1948,7 @@ void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken& token)
return;
}
m_tree.generateImpliedEndTagsWithExclusion(token.name());
- if (!m_tree.currentElement()->hasLocalName(token.name()))
+ if (!m_tree.currentNode()->hasLocalName(token.name()))
parseError(token);
m_tree.openElements()->popUntilPopped(token.name());
return;
@@ -1960,7 +1959,7 @@ void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken& token)
return;
}
m_tree.generateImpliedEndTags();
- if (!m_tree.currentElement()->hasLocalName(token.name()))
+ if (!m_tree.currentNode()->hasLocalName(token.name()))
parseError(token);
m_tree.openElements()->popUntilNumberedHeaderElementPopped();
return;
@@ -1977,7 +1976,7 @@ void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken& token)
return;
}
m_tree.generateImpliedEndTags();
- if (!m_tree.currentElement()->hasLocalName(token.name()))
+ if (!m_tree.currentNode()->hasLocalName(token.name()))
parseError(token);
m_tree.openElements()->popUntilPopped(token.name());
m_tree.activeFormattingElements()->clearToLastMarker();
@@ -2221,7 +2220,7 @@ void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token)
case InFramesetMode:
ASSERT(insertionMode() == InFramesetMode);
if (token.name() == framesetTag) {
- if (m_tree.currentElement() == m_tree.openElements()->htmlElement()) {
+ if (m_tree.currentNode() == m_tree.openElements()->rootNode()) {
parseError(token);
return;
}
@@ -2261,9 +2260,9 @@ void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token)
case InSelectMode:
ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode);
if (token.name() == optgroupTag) {
- if (m_tree.currentElement()->hasTagName(optionTag) && m_tree.oneBelowTop()->hasTagName(optgroupTag))
+ if (m_tree.currentNode()->hasTagName(optionTag) && m_tree.oneBelowTop()->hasTagName(optgroupTag))
processFakeEndTag(optionTag);
- if (m_tree.currentElement()->hasTagName(optgroupTag)) {
+ if (m_tree.currentNode()->hasTagName(optgroupTag)) {
m_tree.openElements()->pop();
return;
}
@@ -2271,7 +2270,7 @@ void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token)
return;
}
if (token.name() == optionTag) {
- if (m_tree.currentElement()->hasTagName(optionTag)) {
+ if (m_tree.currentNode()->hasTagName(optionTag)) {
m_tree.openElements()->pop();
return;
}
@@ -2294,23 +2293,29 @@ void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token)
processEndTag(token);
break;
case InForeignContentMode:
- if (token.name() == SVGNames::scriptTag && m_tree.currentElement()->hasTagName(SVGNames::scriptTag)) {
+ if (token.name() == SVGNames::scriptTag && m_tree.currentNode()->hasTagName(SVGNames::scriptTag)) {
notImplemented();
return;
}
- if (m_tree.currentElement()->namespaceURI() != xhtmlNamespaceURI) {
+ if (m_tree.currentNode()->namespaceURI() != xhtmlNamespaceURI) {
// FIXME: This code just wants an Element* iterator, instead of an ElementRecord*
HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord();
- if (!nodeRecord->element()->hasLocalName(token.name()))
+ if (!nodeRecord->node()->hasLocalName(token.name()))
parseError(token);
while (1) {
- if (nodeRecord->element()->hasLocalName(token.name())) {
+ if (nodeRecord->node()->hasLocalName(token.name())) {
m_tree.openElements()->popUntilPopped(nodeRecord->element());
resetForeignInsertionMode();
return;
}
nodeRecord = nodeRecord->next();
- if (nodeRecord->element()->namespaceURI() == xhtmlNamespaceURI)
+
+ if (nodeRecord->node()->nodeType() == Node::DOCUMENT_FRAGMENT_NODE) {
+ ASSERT(isParsingFragment());
+ break;
+ }
+
+ if (nodeRecord->node()->namespaceURI() == xhtmlNamespaceURI)
break;
}
}
@@ -2609,11 +2614,11 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken& token)
case InSelectInTableMode:
case InSelectMode:
ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode || insertionMode() == InTableMode || insertionMode() == InFramesetMode || insertionMode() == InTableBodyMode);
- if (m_tree.currentElement() != m_tree.openElements()->htmlElement())
+ if (m_tree.currentNode() != m_tree.openElements()->rootNode())
parseError(token);
break;
case InColumnGroupMode:
- if (m_tree.currentElement() == m_tree.openElements()->htmlElement()) {
+ if (m_tree.currentNode() == m_tree.openElements()->rootNode()) {
ASSERT(isParsingFragment());
return; // FIXME: Should we break here instead of returning?
}
@@ -2634,7 +2639,7 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken& token)
return;
case TextMode:
parseError(token);
- if (m_tree.currentElement()->hasTagName(scriptTag))
+ if (m_tree.currentNode()->hasTagName(scriptTag))
notImplemented(); // mark the script element as "already started".
m_tree.openElements()->pop();
setInsertionMode(m_originalInsertionMode);
@@ -2642,7 +2647,7 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken& token)
processEndOfFile(token);
return;
}
- ASSERT(m_tree.openElements()->top());
+ ASSERT(m_tree.currentNode());
m_tree.openElements()->popAll();
}
@@ -2794,28 +2799,16 @@ void HTMLTreeBuilder::processScriptStartTag(AtomicHTMLToken& token)
void HTMLTreeBuilder::finished()
{
- ASSERT(m_document);
- if (isParsingFragment()) {
- m_fragmentContext.finished();
+ if (isParsingFragment())
return;
- }
-
+
+ ASSERT(m_document);
// Warning, this may detach the parser. Do not do anything else after this.
m_document->finishedParsing();
}
void HTMLTreeBuilder::parseError(AtomicHTMLToken&)
{
- DEFINE_STATIC_LOCAL(String, parseErrorMessage, ("HTML parse error (recovered gracefully)"));
-
- if (!m_reportErrors)
- return;
-
- DOMWindow* domWindow = m_document->domWindow();
- if (!domWindow)
- return;
-
- domWindow->console()->addMessage(HTMLMessageSource, LogMessageType, WarningMessageLevel, parseErrorMessage, m_parser->lineNumber(), m_document->url().string());
}
bool HTMLTreeBuilder::scriptEnabled(Frame* frame)
diff --git a/Source/WebCore/html/parser/HTMLTreeBuilder.h b/Source/WebCore/html/parser/HTMLTreeBuilder.h
index 0cec667..5bdc44b 100644
--- a/Source/WebCore/html/parser/HTMLTreeBuilder.h
+++ b/Source/WebCore/html/parser/HTMLTreeBuilder.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -178,7 +179,7 @@ private:
void closeTheCell();
- template <bool shouldClose(const Element*)>
+ template <bool shouldClose(const ContainerNode*)>
void processCloseWhenNestedTag(AtomicHTMLToken&);
bool m_framesetOk;
@@ -215,8 +216,6 @@ private:
Element* contextElement() const { ASSERT(m_fragment); return m_contextElement; }
FragmentScriptingPermission scriptingPermission() const { ASSERT(m_fragment); return m_scriptingPermission; }
- void finished();
-
private:
DocumentFragment* m_fragment;
Element* m_contextElement;
diff --git a/Source/WebCore/html/parser/NestingLevelIncrementer.h b/Source/WebCore/html/parser/NestingLevelIncrementer.h
index 8155635..bf08425 100644
--- a/Source/WebCore/html/parser/NestingLevelIncrementer.h
+++ b/Source/WebCore/html/parser/NestingLevelIncrementer.h
@@ -26,6 +26,8 @@
#ifndef NestingLevelIncrementer_h
#define NestingLevelIncrementer_h
+#include <wtf/Noncopyable.h>
+
namespace WebCore {
class NestingLevelIncrementer {
diff --git a/Source/WebCore/html/parser/XSSFilter.cpp b/Source/WebCore/html/parser/XSSFilter.cpp
index de31f76..ddc3318 100644
--- a/Source/WebCore/html/parser/XSSFilter.cpp
+++ b/Source/WebCore/html/parser/XSSFilter.cpp
@@ -245,10 +245,14 @@ bool XSSFilter::filterTokenInitial(HTMLToken& token)
didBlockScript |= filterEmbedToken(token);
else if (hasName(token, appletTag))
didBlockScript |= filterAppletToken(token);
+ else if (hasName(token, iframeTag))
+ didBlockScript |= filterIframeToken(token);
else if (hasName(token, metaTag))
didBlockScript |= filterMetaToken(token);
else if (hasName(token, baseTag))
didBlockScript |= filterBaseToken(token);
+ else if (hasName(token, formTag))
+ didBlockScript |= filterFormToken(token);
return didBlockScript;
}
@@ -351,6 +355,15 @@ bool XSSFilter::filterAppletToken(HTMLToken& token)
return didBlockScript;
}
+bool XSSFilter::filterIframeToken(HTMLToken& token)
+{
+ ASSERT(m_state == Initial);
+ ASSERT(token.type() == HTMLToken::StartTag);
+ ASSERT(hasName(token, iframeTag));
+
+ return eraseAttributeIfInjected(token, srcAttr);
+}
+
bool XSSFilter::filterMetaToken(HTMLToken& token)
{
ASSERT(m_state == Initial);
@@ -369,6 +382,15 @@ bool XSSFilter::filterBaseToken(HTMLToken& token)
return eraseAttributeIfInjected(token, hrefAttr);
}
+bool XSSFilter::filterFormToken(HTMLToken& token)
+{
+ ASSERT(m_state == Initial);
+ ASSERT(token.type() == HTMLToken::StartTag);
+ ASSERT(hasName(token, formTag));
+
+ return eraseAttributeIfInjected(token, actionAttr);
+}
+
bool XSSFilter::eraseDangerousAttributesIfInjected(HTMLToken& token)
{
DEFINE_STATIC_LOCAL(String, safeJavaScriptURL, ("javascript:void(0)"));
diff --git a/Source/WebCore/html/parser/XSSFilter.h b/Source/WebCore/html/parser/XSSFilter.h
index 2c7d428..c9ba12e 100644
--- a/Source/WebCore/html/parser/XSSFilter.h
+++ b/Source/WebCore/html/parser/XSSFilter.h
@@ -58,8 +58,10 @@ private:
bool filterParamToken(HTMLToken&);
bool filterEmbedToken(HTMLToken&);
bool filterAppletToken(HTMLToken&);
+ bool filterIframeToken(HTMLToken&);
bool filterMetaToken(HTMLToken&);
bool filterBaseToken(HTMLToken&);
+ bool filterFormToken(HTMLToken&);
bool eraseDangerousAttributesIfInjected(HTMLToken&);
bool eraseAttributeIfInjected(HTMLToken&, const QualifiedName&, const String& replacementValue = String());
diff --git a/Source/WebCore/html/parser/create-html-entity-table b/Source/WebCore/html/parser/create-html-entity-table
index e6132bc..92fb39c 100755
--- a/Source/WebCore/html/parser/create-html-entity-table
+++ b/Source/WebCore/html/parser/create-html-entity-table
@@ -58,7 +58,8 @@ def offset_table_entry(offset):
program_name = os.path.basename(__file__)
if len(sys.argv) < 4 or sys.argv[1] != "-o":
- print >> sys.stderr, "Usage: %s -o OUTPUT_FILE INPUT_FILE" % program_name
+ # Python 3, change to: print("Usage: %s -o OUTPUT_FILE INPUT_FILE" % program_name, file=sys.stderr)
+ sys.stderr.write("Usage: %s -o OUTPUT_FILE INPUT_FILE\n" % program_name)
exit(1)
output_path = sys.argv[2]
@@ -68,12 +69,12 @@ html_entity_names_file = open(input_path)
entries = list(csv.reader(html_entity_names_file))
html_entity_names_file.close()
-entries.sort(lambda a, b: cmp(a[ENTITY], b[ENTITY]))
+entries.sort(key = lambda entry: entry[ENTITY])
entity_count = len(entries)
output_file = open(output_path, "w")
-print >> output_file, """/*
+output_file.write("""/*
* Copyright (C) 2010 Google, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -107,15 +108,15 @@ print >> output_file, """/*
namespace WebCore {
namespace {
-"""
+""")
for entry in entries:
- print >> output_file, "const UChar %sEntityName[] = %s;" % (
+ output_file.write("const UChar %sEntityName[] = %s;" % (
convert_entity_to_cpp_name(entry[ENTITY]),
- convert_entity_to_uchar_array(entry[ENTITY]))
+ convert_entity_to_uchar_array(entry[ENTITY])))
-print >> output_file, """
-HTMLEntityTableEntry staticEntityTable[%s] = {""" % entity_count
+output_file.write("""
+HTMLEntityTableEntry staticEntityTable[%s] = {""" % entity_count)
index = {}
offset = 0
@@ -123,26 +124,26 @@ for entry in entries:
letter = entry[ENTITY][0]
if not index.get(letter):
index[letter] = offset
- print >> output_file, ' { %sEntityName, %s, %s },' % (
+ output_file.write(' { %sEntityName, %s, %s },' % (
convert_entity_to_cpp_name(entry[ENTITY]),
len(entry[ENTITY]),
- convert_value_to_int(entry[VALUE]))
+ convert_value_to_int(entry[VALUE])))
offset += 1
-print >> output_file, """};
-"""
+output_file.write("""};
+""")
-print >> output_file, "const HTMLEntityTableEntry* uppercaseOffset[] = {"
-for letter in string.uppercase:
- print >> output_file, offset_table_entry(index[letter])
-print >> output_file, offset_table_entry(index['a'])
-print >> output_file, """};
+output_file.write("const HTMLEntityTableEntry* uppercaseOffset[] = {")
+for letter in string.ascii_uppercase:
+ output_file.write(offset_table_entry(index[letter]))
+output_file.write(offset_table_entry(index['a']))
+output_file.write("""};
-const HTMLEntityTableEntry* lowercaseOffset[] = {"""
-for letter in string.lowercase:
- print >> output_file, offset_table_entry(index[letter])
-print >> output_file, offset_table_entry(entity_count)
-print >> output_file, """};
+const HTMLEntityTableEntry* lowercaseOffset[] = {""")
+for letter in string.ascii_lowercase:
+ output_file.write(offset_table_entry(index[letter]))
+output_file.write(offset_table_entry(entity_count))
+output_file.write("""};
}
@@ -175,4 +176,4 @@ const HTMLEntityTableEntry* HTMLEntityTable::lastEntry()
}
}
-""" % entity_count
+""" % entity_count)
diff --git a/Source/WebCore/html/shadow/MediaControls.cpp b/Source/WebCore/html/shadow/MediaControls.cpp
index a374e49..61a3684 100644
--- a/Source/WebCore/html/shadow/MediaControls.cpp
+++ b/Source/WebCore/html/shadow/MediaControls.cpp
@@ -254,7 +254,7 @@ void MediaControls::createPanel()
void MediaControls::createMuteButton()
{
ASSERT(!m_muteButton);
- m_muteButton = MediaControlMuteButtonElement::create(m_mediaElement);
+ m_muteButton = MediaControlPanelMuteButtonElement::create(m_mediaElement);
m_muteButton->attachToParent(m_panel.get());
}
@@ -482,7 +482,7 @@ void MediaControls::updateVolumeSliderContainer(bool visible)
RefPtr<RenderStyle> s = m_volumeSliderContainer->styleForElement();
int height = s->height().isPercent() ? 0 : s->height().value();
int width = s->width().isPercent() ? 0 : s->width().value();
- IntPoint offset = m_mediaElement->document()->page()->theme()->volumeSliderOffsetFromMuteButton(m_muteButton->renderer()->node(), IntSize(width, height));
+ IntPoint offset = m_mediaElement->document()->page()->theme()->volumeSliderOffsetFromMuteButton(m_muteButton->renderBox(), IntSize(width, height));
int x = offset.x() + m_muteButton->renderBox()->offsetLeft();
int y = offset.y() + m_muteButton->renderBox()->offsetTop();
diff --git a/Source/WebCore/html/shadow/TextControlInnerElements.cpp b/Source/WebCore/html/shadow/TextControlInnerElements.cpp
new file mode 100644
index 0000000..968c5e4
--- /dev/null
+++ b/Source/WebCore/html/shadow/TextControlInnerElements.cpp
@@ -0,0 +1,503 @@
+/*
+ * Copyright (C) 2006, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TextControlInnerElements.h"
+
+#include "BeforeTextInsertedEvent.h"
+#include "Document.h"
+#include "EventHandler.h"
+#include "EventNames.h"
+#include "Frame.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "HTMLTextAreaElement.h"
+#include "MouseEvent.h"
+#include "Page.h"
+#include "RenderLayer.h"
+#include "RenderTextControlSingleLine.h"
+#include "ScrollbarTheme.h"
+#include "SpeechInput.h"
+#include "SpeechInputEvent.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+TextControlInnerElement::TextControlInnerElement(Document* document, HTMLElement* shadowParent)
+ : HTMLDivElement(divTag, document)
+{
+ setShadowHost(shadowParent);
+}
+
+PassRefPtr<TextControlInnerElement> TextControlInnerElement::create(HTMLElement* shadowParent)
+{
+ return adoptRef(new TextControlInnerElement(shadowParent->document(), shadowParent));
+}
+
+void TextControlInnerElement::attachInnerElement(Node* parent, PassRefPtr<RenderStyle> style, RenderArena* arena)
+{
+ // When adding these elements, create the renderer & style first before adding to the DOM.
+ // Otherwise, the render tree will create some anonymous blocks that will mess up our layout.
+
+ // Create the renderer with the specified style
+ RenderObject* renderer = createRenderer(arena, style.get());
+ if (renderer) {
+ setRenderer(renderer);
+ renderer->setStyle(style);
+ }
+
+ // Set these explicitly since this normally happens during an attach()
+ setAttached();
+ setInDocument();
+
+ // For elements not yet in shadow DOM, add the node to the DOM normally.
+ if (!isShadowRoot()) {
+ // FIXME: This code seems very wrong. Why are we magically adding |this| to the DOM here?
+ // We shouldn't be calling parser API methods outside of the parser!
+ parent->deprecatedParserAddChild(this);
+ }
+
+ // Add the renderer to the render tree
+ if (renderer)
+ parent->renderer()->addChild(renderer);
+}
+
+void TextControlInnerElement::detach()
+{
+ HTMLDivElement::detach();
+ // FIXME: Remove once shadow DOM uses Element::setShadowRoot().
+ if (shadowHost())
+ setShadowHost(0);
+}
+
+// ----------------------------
+
+inline TextControlInnerTextElement::TextControlInnerTextElement(Document* document, HTMLElement* shadowParent)
+ : TextControlInnerElement(document, shadowParent)
+{
+}
+
+PassRefPtr<TextControlInnerTextElement> TextControlInnerTextElement::create(Document* document, HTMLElement* shadowParent)
+{
+ return adoptRef(new TextControlInnerTextElement(document, shadowParent));
+}
+
+void TextControlInnerTextElement::defaultEventHandler(Event* event)
+{
+ // FIXME: In the future, we should add a way to have default event listeners.
+ // Then we would add one to the text field's inner div, and we wouldn't need this subclass.
+ // Or possibly we could just use a normal event listener.
+ if (event->isBeforeTextInsertedEvent() || event->type() == eventNames().webkitEditableContentChangedEvent) {
+ Node* shadowAncestor = shadowAncestorNode();
+ // A TextControlInnerTextElement can be its own shadow ancestor if its been detached, but kept alive by an EditCommand.
+ // In this case, an undo/redo can cause events to be sent to the TextControlInnerTextElement.
+ // To prevent an infinite loop, we must check for this case before sending the event up the chain.
+ if (shadowAncestor && shadowAncestor != this)
+ shadowAncestor->defaultEventHandler(event);
+ }
+ if (!event->defaultHandled())
+ HTMLDivElement::defaultEventHandler(event);
+}
+
+RenderObject* TextControlInnerTextElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+ bool multiLine = false;
+ Node* shadowAncestor = shadowAncestorNode();
+ if (shadowAncestor && shadowAncestor->renderer()) {
+ ASSERT(shadowAncestor->renderer()->isTextField() || shadowAncestor->renderer()->isTextArea());
+ multiLine = shadowAncestor->renderer()->isTextArea();
+ }
+ return new (arena) RenderTextControlInnerBlock(this, multiLine);
+}
+
+// ----------------------------
+
+inline SearchFieldResultsButtonElement::SearchFieldResultsButtonElement(Document* document)
+ : TextControlInnerElement(document)
+{
+}
+
+PassRefPtr<SearchFieldResultsButtonElement> SearchFieldResultsButtonElement::create(Document* document)
+{
+ return adoptRef(new SearchFieldResultsButtonElement(document));
+}
+
+void SearchFieldResultsButtonElement::defaultEventHandler(Event* event)
+{
+ // On mousedown, bring up a menu, if needed
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode());
+ if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
+ input->focus();
+ input->select();
+ RenderTextControlSingleLine* renderer = toRenderTextControlSingleLine(input->renderer());
+ if (renderer->popupIsVisible())
+ renderer->hidePopup();
+ else if (input->maxResults() > 0)
+ renderer->showPopup();
+ event->setDefaultHandled();
+ }
+
+ if (!event->defaultHandled())
+ HTMLDivElement::defaultEventHandler(event);
+}
+
+// ----------------------------
+
+inline SearchFieldCancelButtonElement::SearchFieldCancelButtonElement(Document* document)
+ : TextControlInnerElement(document)
+ , m_capturing(false)
+{
+}
+
+PassRefPtr<SearchFieldCancelButtonElement> SearchFieldCancelButtonElement::create(Document* document)
+{
+ return adoptRef(new SearchFieldCancelButtonElement(document));
+}
+
+void SearchFieldCancelButtonElement::detach()
+{
+ if (m_capturing) {
+ if (Frame* frame = document()->frame())
+ frame->eventHandler()->setCapturingMouseEventsNode(0);
+ }
+ TextControlInnerElement::detach();
+}
+
+
+void SearchFieldCancelButtonElement::defaultEventHandler(Event* event)
+{
+ // If the element is visible, on mouseup, clear the value, and set selection
+ RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowAncestorNode()));
+ if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
+ if (renderer() && renderer()->visibleToHitTesting()) {
+ if (Frame* frame = document()->frame()) {
+ frame->eventHandler()->setCapturingMouseEventsNode(this);
+ m_capturing = true;
+ }
+ }
+ input->focus();
+ input->select();
+ event->setDefaultHandled();
+ }
+ if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
+ if (m_capturing) {
+ if (Frame* frame = document()->frame()) {
+ frame->eventHandler()->setCapturingMouseEventsNode(0);
+ m_capturing = false;
+ }
+ if (hovered()) {
+ String oldValue = input->value();
+ input->setValueForUser("");
+ input->onSearch();
+ event->setDefaultHandled();
+ }
+ }
+ }
+
+ if (!event->defaultHandled())
+ HTMLDivElement::defaultEventHandler(event);
+}
+
+// ----------------------------
+
+inline SpinButtonElement::SpinButtonElement(HTMLElement* shadowParent)
+ : TextControlInnerElement(shadowParent->document(), shadowParent)
+ , m_capturing(false)
+ , m_upDownState(Indeterminate)
+ , m_pressStartingState(Indeterminate)
+ , m_repeatingTimer(this, &SpinButtonElement::repeatingTimerFired)
+{
+}
+
+PassRefPtr<SpinButtonElement> SpinButtonElement::create(HTMLElement* shadowParent)
+{
+ return adoptRef(new SpinButtonElement(shadowParent));
+}
+
+void SpinButtonElement::detach()
+{
+ stopRepeatingTimer();
+ if (m_capturing) {
+ if (Frame* frame = document()->frame()) {
+ frame->eventHandler()->setCapturingMouseEventsNode(0);
+ m_capturing = false;
+ }
+ }
+ TextControlInnerElement::detach();
+}
+
+void SpinButtonElement::defaultEventHandler(Event* event)
+{
+ if (!event->isMouseEvent()) {
+ if (!event->defaultHandled())
+ HTMLDivElement::defaultEventHandler(event);
+ return;
+ }
+
+ RenderBox* box = renderBox();
+ if (!box) {
+ if (!event->defaultHandled())
+ HTMLDivElement::defaultEventHandler(event);
+ return;
+ }
+
+ RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowAncestorNode()));
+ if (input->disabled() || input->isReadOnlyFormControl()) {
+ if (!event->defaultHandled())
+ HTMLDivElement::defaultEventHandler(event);
+ return;
+ }
+
+ MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
+ IntPoint local = roundedIntPoint(box->absoluteToLocal(mouseEvent->absoluteLocation(), false, true));
+ if (mouseEvent->type() == eventNames().mousedownEvent && mouseEvent->button() == LeftButton) {
+ if (box->borderBoxRect().contains(local)) {
+ // The following functions of HTMLInputElement may run JavaScript
+ // code which detaches this shadow node. We need to take a reference
+ // and check renderer() after such function calls.
+ RefPtr<Node> protector(this);
+ input->focus();
+ input->select();
+ if (renderer()) {
+ input->stepUpFromRenderer(m_upDownState == Up ? 1 : -1);
+ if (renderer())
+ startRepeatingTimer();
+ }
+ event->setDefaultHandled();
+ }
+ } else if (mouseEvent->type() == eventNames().mouseupEvent && mouseEvent->button() == LeftButton)
+ stopRepeatingTimer();
+ else if (event->type() == eventNames().mousemoveEvent) {
+ if (box->borderBoxRect().contains(local)) {
+ if (!m_capturing) {
+ if (Frame* frame = document()->frame()) {
+ frame->eventHandler()->setCapturingMouseEventsNode(this);
+ m_capturing = true;
+ }
+ }
+ UpDownState oldUpDownState = m_upDownState;
+ m_upDownState = local.y() < box->height() / 2 ? Up : Down;
+ if (m_upDownState != oldUpDownState)
+ renderer()->repaint();
+ } else {
+ if (m_capturing) {
+ stopRepeatingTimer();
+ if (Frame* frame = document()->frame()) {
+ frame->eventHandler()->setCapturingMouseEventsNode(0);
+ m_capturing = false;
+ }
+ }
+ }
+ }
+
+ if (!event->defaultHandled())
+ HTMLDivElement::defaultEventHandler(event);
+}
+
+void SpinButtonElement::startRepeatingTimer()
+{
+ m_pressStartingState = m_upDownState;
+ ScrollbarTheme* theme = ScrollbarTheme::nativeTheme();
+ m_repeatingTimer.start(theme->initialAutoscrollTimerDelay(), theme->autoscrollTimerDelay());
+}
+
+void SpinButtonElement::stopRepeatingTimer()
+{
+ m_repeatingTimer.stop();
+}
+
+void SpinButtonElement::repeatingTimerFired(Timer<SpinButtonElement>*)
+{
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode());
+ if (input->disabled() || input->isReadOnlyFormControl())
+ return;
+ // On Mac OS, NSStepper updates the value for the button under the mouse
+ // cursor regardless of the button pressed at the beginning. So the
+ // following check is not needed for Mac OS.
+#if !OS(MAC_OS_X)
+ if (m_upDownState != m_pressStartingState)
+ return;
+#endif
+ input->stepUpFromRenderer(m_upDownState == Up ? 1 : -1);
+}
+
+void SpinButtonElement::setHovered(bool flag)
+{
+ if (!hovered() && flag)
+ m_upDownState = Indeterminate;
+ TextControlInnerElement::setHovered(flag);
+}
+
+
+// ----------------------------
+
+#if ENABLE(INPUT_SPEECH)
+
+inline InputFieldSpeechButtonElement::InputFieldSpeechButtonElement(HTMLElement* shadowParent)
+ : TextControlInnerElement(shadowParent->document(), shadowParent)
+ , m_capturing(false)
+ , m_state(Idle)
+ , m_listenerId(document()->page()->speechInput()->registerListener(this))
+{
+}
+
+InputFieldSpeechButtonElement::~InputFieldSpeechButtonElement()
+{
+ SpeechInput* speech = speechInput();
+ if (speech && m_listenerId) { // Could be null when page is unloading.
+ if (m_state != Idle)
+ speech->cancelRecognition(m_listenerId);
+ speech->unregisterListener(m_listenerId);
+ }
+}
+
+PassRefPtr<InputFieldSpeechButtonElement> InputFieldSpeechButtonElement::create(HTMLElement* shadowParent)
+{
+ return adoptRef(new InputFieldSpeechButtonElement(shadowParent));
+}
+
+void InputFieldSpeechButtonElement::defaultEventHandler(Event* event)
+{
+ // For privacy reasons, only allow clicks directly coming from the user.
+ if (!event->fromUserGesture()) {
+ HTMLDivElement::defaultEventHandler(event);
+ return;
+ }
+
+ // The call to focus() below dispatches a focus event, and an event handler in the page might
+ // remove the input element from DOM. To make sure it remains valid until we finish our work
+ // here, we take a temporary reference.
+ RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowAncestorNode()));
+
+ // On mouse down, select the text and set focus.
+ if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
+ if (renderer() && renderer()->visibleToHitTesting()) {
+ if (Frame* frame = document()->frame()) {
+ frame->eventHandler()->setCapturingMouseEventsNode(this);
+ m_capturing = true;
+ }
+ }
+ RefPtr<InputFieldSpeechButtonElement> holdRefButton(this);
+ input->focus();
+ input->select();
+ event->setDefaultHandled();
+ }
+ // On mouse up, release capture cleanly.
+ if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
+ if (m_capturing && renderer() && renderer()->visibleToHitTesting()) {
+ if (Frame* frame = document()->frame()) {
+ frame->eventHandler()->setCapturingMouseEventsNode(0);
+ m_capturing = false;
+ }
+ }
+ }
+
+ if (event->type() == eventNames().clickEvent) {
+ switch (m_state) {
+ case Idle: {
+ AtomicString language = input->computeInheritedLanguage();
+ String grammar = input->getAttribute(webkitgrammarAttr);
+ IntRect rect = input->renderer()->absoluteBoundingBoxRect();
+ if (speechInput()->startRecognition(m_listenerId, rect, language, grammar, document()->securityOrigin()))
+ setState(Recording);
+ }
+ break;
+ case Recording:
+ speechInput()->stopRecording(m_listenerId);
+ break;
+ case Recognizing:
+ // Nothing to do here, we will continue to wait for results.
+ break;
+ }
+ event->setDefaultHandled();
+ }
+
+ if (!event->defaultHandled())
+ HTMLDivElement::defaultEventHandler(event);
+}
+
+void InputFieldSpeechButtonElement::setState(SpeechInputState state)
+{
+ if (m_state != state) {
+ m_state = state;
+ shadowAncestorNode()->renderer()->repaint();
+ }
+}
+
+SpeechInput* InputFieldSpeechButtonElement::speechInput()
+{
+ return document()->page() ? document()->page()->speechInput() : 0;
+}
+
+void InputFieldSpeechButtonElement::didCompleteRecording(int)
+{
+ setState(Recognizing);
+}
+
+void InputFieldSpeechButtonElement::didCompleteRecognition(int)
+{
+ setState(Idle);
+}
+
+void InputFieldSpeechButtonElement::setRecognitionResult(int, const SpeechInputResultArray& results)
+{
+ m_results = results;
+
+ // The call to setValue() below dispatches an event, and an event handler in the page might
+ // remove the input element from DOM. To make sure it remains valid until we finish our work
+ // here, we take a temporary reference.
+ RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowAncestorNode()));
+ RefPtr<InputFieldSpeechButtonElement> holdRefButton(this);
+ input->setValue(results.isEmpty() ? "" : results[0]->utterance());
+ input->dispatchEvent(SpeechInputEvent::create(eventNames().webkitspeechchangeEvent, results));
+
+ // Check before accessing the renderer as the above event could have potentially turned off
+ // speech in the input element, hence removing this button and renderer from the hierarchy.
+ if (renderer())
+ renderer()->repaint();
+}
+
+void InputFieldSpeechButtonElement::detach()
+{
+ if (m_capturing) {
+ if (Frame* frame = document()->frame())
+ frame->eventHandler()->setCapturingMouseEventsNode(0);
+ }
+
+ if (m_listenerId) {
+ if (m_state != Idle)
+ speechInput()->cancelRecognition(m_listenerId);
+ speechInput()->unregisterListener(m_listenerId);
+ m_listenerId = 0;
+ }
+
+ TextControlInnerElement::detach();
+}
+
+#endif // ENABLE(INPUT_SPEECH)
+
+}
diff --git a/Source/WebCore/html/shadow/TextControlInnerElements.h b/Source/WebCore/html/shadow/TextControlInnerElements.h
new file mode 100644
index 0000000..4ba7857
--- /dev/null
+++ b/Source/WebCore/html/shadow/TextControlInnerElements.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2006, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TextControlInnerElements_h
+#define TextControlInnerElements_h
+
+#include "HTMLDivElement.h"
+#include "SpeechInputListener.h"
+#include "Timer.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class SpeechInput;
+
+class TextControlInnerElement : public HTMLDivElement {
+public:
+ static PassRefPtr<TextControlInnerElement> create(HTMLElement* shadowParent);
+ virtual void detach();
+
+ void attachInnerElement(Node*, PassRefPtr<RenderStyle>, RenderArena*);
+
+protected:
+ TextControlInnerElement(Document*, HTMLElement* shadowParent = 0);
+
+private:
+ virtual bool isMouseFocusable() const { return false; }
+};
+
+class TextControlInnerTextElement : public TextControlInnerElement {
+public:
+ static PassRefPtr<TextControlInnerTextElement> create(Document*, HTMLElement* shadowParent);
+
+ virtual void defaultEventHandler(Event*);
+
+private:
+ TextControlInnerTextElement(Document*, HTMLElement* shadowParent);
+ virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+};
+
+class SearchFieldResultsButtonElement : public TextControlInnerElement {
+public:
+ static PassRefPtr<SearchFieldResultsButtonElement> create(Document*);
+
+ virtual void defaultEventHandler(Event*);
+
+private:
+ SearchFieldResultsButtonElement(Document*);
+};
+
+class SearchFieldCancelButtonElement : public TextControlInnerElement {
+public:
+ static PassRefPtr<SearchFieldCancelButtonElement> create(Document*);
+
+ virtual void defaultEventHandler(Event*);
+
+private:
+ SearchFieldCancelButtonElement(Document*);
+
+ virtual void detach();
+
+ bool m_capturing;
+};
+
+class SpinButtonElement : public TextControlInnerElement {
+public:
+ enum UpDownState {
+ Indeterminate, // Hovered, but the event is not handled.
+ Down,
+ Up,
+ };
+
+ static PassRefPtr<SpinButtonElement> create(HTMLElement*);
+ UpDownState upDownState() const { return m_upDownState; }
+
+private:
+ SpinButtonElement(HTMLElement*);
+
+ virtual void detach();
+ virtual bool isSpinButtonElement() const { return true; }
+ // FIXME: shadowAncestorNode() should be const.
+ virtual bool isEnabledFormControl() const { return static_cast<Element*>(const_cast<SpinButtonElement*>(this)->shadowAncestorNode())->isEnabledFormControl(); }
+ virtual bool isReadOnlyFormControl() const { return static_cast<Element*>(const_cast<SpinButtonElement*>(this)->shadowAncestorNode())->isReadOnlyFormControl(); }
+ virtual void defaultEventHandler(Event*);
+ void startRepeatingTimer();
+ void stopRepeatingTimer();
+ void repeatingTimerFired(Timer<SpinButtonElement>*);
+ virtual void setHovered(bool = true);
+
+ bool m_capturing;
+ UpDownState m_upDownState;
+ UpDownState m_pressStartingState;
+ Timer<SpinButtonElement> m_repeatingTimer;
+};
+
+#if ENABLE(INPUT_SPEECH)
+
+class InputFieldSpeechButtonElement
+ : public TextControlInnerElement,
+ public SpeechInputListener {
+public:
+ enum SpeechInputState {
+ Idle,
+ Recording,
+ Recognizing,
+ };
+
+ static PassRefPtr<InputFieldSpeechButtonElement> create(HTMLElement*);
+ virtual ~InputFieldSpeechButtonElement();
+
+ virtual void detach();
+ virtual void defaultEventHandler(Event*);
+ SpeechInputState state() const { return m_state; }
+
+ // SpeechInputListener methods.
+ void didCompleteRecording(int);
+ void didCompleteRecognition(int);
+ void setRecognitionResult(int, const SpeechInputResultArray&);
+
+private:
+ InputFieldSpeechButtonElement(HTMLElement*);
+ SpeechInput* speechInput();
+ void setState(SpeechInputState state);
+
+ bool m_capturing;
+ SpeechInputState m_state;
+ int m_listenerId;
+ SpeechInputResultArray m_results;
+};
+
+#endif // ENABLE(INPUT_SPEECH)
+
+} // namespace
+
+#endif