diff options
Diffstat (limited to 'WebCore/html')
27 files changed, 1319 insertions, 228 deletions
diff --git a/WebCore/html/DOMSettableTokenList.cpp b/WebCore/html/DOMSettableTokenList.cpp index 2636bd3..3a86e9c 100644 --- a/WebCore/html/DOMSettableTokenList.cpp +++ b/WebCore/html/DOMSettableTokenList.cpp @@ -40,7 +40,7 @@ DOMSettableTokenList::~DOMSettableTokenList() const AtomicString DOMSettableTokenList::item(unsigned index) const { if (index >= length()) - return AtomicString(""); + return AtomicString(); return m_tokens[index]; } @@ -61,7 +61,10 @@ void DOMSettableTokenList::add(const AtomicString& token, ExceptionCode& ec) void DOMSettableTokenList::addInternal(const AtomicString& token) { m_value = addToken(m_value, token); - m_tokens.add(token); + if (m_tokens.isNull()) + m_tokens.set(token, false); + else + m_tokens.add(token); } void DOMSettableTokenList::remove(const AtomicString& token, ExceptionCode& ec) @@ -92,7 +95,7 @@ bool DOMSettableTokenList::toggle(const AtomicString& token, ExceptionCode& ec) void DOMSettableTokenList::setValue(const String& value) { m_value = value; - m_tokens.set(value, true); + m_tokens.set(value, false); } } // namespace WebCore diff --git a/WebCore/html/HTMLFormControlElement.cpp b/WebCore/html/HTMLFormControlElement.cpp index 710cda1..8fa000f 100644 --- a/WebCore/html/HTMLFormControlElement.cpp +++ b/WebCore/html/HTMLFormControlElement.cpp @@ -45,6 +45,7 @@ #include "RenderTextControl.h" #include "RenderTheme.h" #include "ScriptEventListener.h" +#include "ValidationMessage.h" #include "ValidityState.h" #include <limits> #include <wtf/Vector.h> @@ -77,6 +78,12 @@ HTMLFormControlElement::~HTMLFormControlElement() m_form->removeFormElement(this); } +void HTMLFormControlElement::detach() +{ + hideVisibleValidationMessage(); + HTMLElement::detach(); +} + bool HTMLFormControlElement::formNoValidate() const { return !getAttribute(formnovalidateAttr).isNull(); @@ -301,7 +308,8 @@ void HTMLFormControlElement::setNeedsWillValidateCheck() m_willValidateInitialized = true; m_willValidate = newWillValidate; setNeedsStyleRecalc(); - // FIXME: Show/hide a validation message. + if (!m_willValidate) + hideVisibleValidationMessage(); } String HTMLFormControlElement::validationMessage() @@ -309,6 +317,42 @@ String HTMLFormControlElement::validationMessage() return validity()->validationMessage(); } +void HTMLFormControlElement::updateVisibleValidationMessage() +{ + Page* page = document()->page(); + if (!page) + return; + String message; + if (renderer() && willValidate()) { + message = validationMessage().stripWhiteSpace(); + // HTML5 specification doesn't ask UA to show the title attribute value + // with the validationMessage. However, this behavior is same as Opera + // and the specification describes such behavior as an example. + const AtomicString& title = getAttribute(titleAttr); + if (!message.isEmpty() && !title.isEmpty()) { + message.append('\n'); + message.append(title); + } + } + if (!m_validationMessage) { + m_validationMessage = ValidationMessage::create(this); + m_validationMessage->setMessage(message); + } else if (message.isEmpty()) + hideVisibleValidationMessage(); + else if (m_validationMessage->message() != message) + m_validationMessage->setMessage(message); +} + +void HTMLFormControlElement::hideVisibleValidationMessage() +{ + m_validationMessage = 0; +} + +String HTMLFormControlElement::visibleValidationMessage() const +{ + return m_validationMessage ? m_validationMessage->message() : String(); +} + bool HTMLFormControlElement::checkValidity(Vector<RefPtr<HTMLFormControlElement> >* unhandledInvalidControls) { if (!willValidate() || isValidFormControlElement()) @@ -338,7 +382,13 @@ void HTMLFormControlElement::setNeedsValidityCheck() setNeedsStyleRecalc(); } m_isValid = newIsValid; - // FIXME: show/hide a validation message. + + // Updates only if this control already has a validtion message. + if (!visibleValidationMessage().isEmpty()) { + // Calls updateVisibleValidationMessage() even if m_isValid is not + // changed because a validation message can be chagned. + updateVisibleValidationMessage(); + } } void HTMLFormControlElement::setCustomValidity(const String& error) @@ -360,6 +410,7 @@ void HTMLFormControlElement::dispatchBlurEvent() document()->page()->chrome()->client()->formDidBlur(this); HTMLElement::dispatchBlurEvent(); + hideVisibleValidationMessage(); } HTMLFormElement* HTMLFormControlElement::virtualForm() const @@ -568,7 +619,7 @@ void HTMLTextFormControlElement::setSelectionRange(int start, int end) WebCore::setSelectionRange(this, start, end); } -int HTMLTextFormControlElement::selectionStart() +int HTMLTextFormControlElement::selectionStart() const { if (!isTextFormControl()) return 0; @@ -579,7 +630,7 @@ int HTMLTextFormControlElement::selectionStart() return toRenderTextControl(renderer())->selectionStart(); } -int HTMLTextFormControlElement::selectionEnd() +int HTMLTextFormControlElement::selectionEnd() const { if (!isTextFormControl()) return 0; diff --git a/WebCore/html/HTMLFormControlElement.h b/WebCore/html/HTMLFormControlElement.h index 8b721d8..1960fc3 100644 --- a/WebCore/html/HTMLFormControlElement.h +++ b/WebCore/html/HTMLFormControlElement.h @@ -31,6 +31,7 @@ namespace WebCore { class FormDataList; class HTMLFormElement; class RenderTextControl; +class ValidationMessage; class ValidityState; class VisibleSelection; @@ -84,6 +85,8 @@ public: virtual bool willValidate() const; String validationMessage(); + void updateVisibleValidationMessage(); + void hideVisibleValidationMessage(); bool checkValidity(Vector<RefPtr<HTMLFormControlElement> >* unhandledInvalidControls = 0); // This must be called when a validation constraint or control value is changed. void setNeedsValidityCheck(); @@ -111,6 +114,7 @@ protected: virtual void dispatchFocusEvent(); virtual void dispatchBlurEvent(); + virtual void detach(); void removeFromForm(); @@ -131,9 +135,11 @@ private: virtual HTMLFormElement* virtualForm() const; virtual bool isDefaultButtonForForm() const; virtual bool isValidFormControlElement(); + String visibleValidationMessage() const; HTMLFormElement* m_form; OwnPtr<ValidityState> m_validityState; + OwnPtr<ValidationMessage> m_validationMessage; bool m_disabled : 1; bool m_readOnly : 1; bool m_required : 1; @@ -182,8 +188,8 @@ public: String strippedPlaceholder() const; bool placeholderShouldBeVisible() const; - int selectionStart(); - int selectionEnd(); + int selectionStart() const; + int selectionEnd() const; void setSelectionStart(int); void setSelectionEnd(int); void select(); diff --git a/WebCore/html/HTMLFormElement.cpp b/WebCore/html/HTMLFormElement.cpp index 31a72bd..da388d5 100644 --- a/WebCore/html/HTMLFormElement.cpp +++ b/WebCore/html/HTMLFormElement.cpp @@ -205,6 +205,9 @@ bool HTMLFormElement::validateInteractively(Event* event) if (submitElement && submitElement->formNoValidate()) return true; + for (unsigned i = 0; i < m_associatedElements.size(); ++i) + m_associatedElements[i]->hideVisibleValidationMessage(); + Vector<RefPtr<HTMLFormControlElement> > unhandledInvalidControls; collectUnhandledInvalidControls(unhandledInvalidControls); if (unhandledInvalidControls.isEmpty()) @@ -212,7 +215,7 @@ bool HTMLFormElement::validateInteractively(Event* event) // If the form has invalid controls, abort submission. RefPtr<HTMLFormElement> protector(this); - // Focus on the first focusable control. + // Focus on the first focusable control and show a validation message. for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) { HTMLFormControlElement* unhandled = unhandledInvalidControls[i].get(); if (unhandled->isFocusable() && unhandled->inDocument()) { @@ -223,6 +226,7 @@ bool HTMLFormElement::validateInteractively(Event* event) // moved to another document. if (unhandled->isFocusable() && unhandled->inDocument() && originalDocument == unhandled->document()) { unhandled->focus(); + unhandled->updateVisibleValidationMessage(); break; } } diff --git a/WebCore/html/HTMLFrameElementBase.cpp b/WebCore/html/HTMLFrameElementBase.cpp index d153845..cba82a2 100644 --- a/WebCore/html/HTMLFrameElementBase.cpp +++ b/WebCore/html/HTMLFrameElementBase.cpp @@ -92,8 +92,6 @@ bool HTMLFrameElementBase::isURLAllowed() const void HTMLFrameElementBase::openURL(bool lockHistory, bool lockBackForwardList) { - ASSERT(!m_frameName.isEmpty()); - if (!isURLAllowed()) return; @@ -155,9 +153,6 @@ void HTMLFrameElementBase::setName() m_frameName = getAttribute(nameAttr); if (m_frameName.isNull()) m_frameName = getIdAttribute(); - - if (Frame* parentFrame = document()->frame()) - m_frameName = parentFrame->tree()->uniqueChildName(m_frameName); } void HTMLFrameElementBase::setNameAndOpenURL() diff --git a/WebCore/html/HTMLInputElement.cpp b/WebCore/html/HTMLInputElement.cpp index cd826bf..b7b05b1 100644 --- a/WebCore/html/HTMLInputElement.cpp +++ b/WebCore/html/HTMLInputElement.cpp @@ -338,7 +338,7 @@ bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const if (deprecatedInputType() == RADIO) { // When using Spatial Navigation, every radio button should be focusable. - if (document()->frame() && document()->frame()->settings() && document()->frame()->settings()->isSpatialNavigationEnabled()) + if (isSpatialNavigationEnabled(document()->frame())) return true; // Never allow keyboard tabbing to leave you in the same radio group. Always diff --git a/WebCore/html/HTMLLinkElement.cpp b/WebCore/html/HTMLLinkElement.cpp index 6a5c2f6..9303076 100644 --- a/WebCore/html/HTMLLinkElement.cpp +++ b/WebCore/html/HTMLLinkElement.cpp @@ -199,6 +199,7 @@ void HTMLLinkElement::process() if (m_relAttribute.m_isIcon && m_url.isValid() && !m_url.isEmpty()) document()->setIconURL(m_url.string(), type); +<<<<<<< HEAD #ifdef ANDROID_APPLE_TOUCH_ICON if ((m_relAttribute.m_isTouchIcon || m_relAttribute.m_isPrecomposedTouchIcon) && m_url.isValid() && !m_url.isEmpty() && document()->frame()) @@ -209,6 +210,15 @@ void HTMLLinkElement::process() if (m_relAttribute.m_isDNSPrefetch && document()->isDNSPrefetchEnabled() && m_url.isValid() && !m_url.isEmpty()) ResourceHandle::prepareForURL(m_url); +======= + if (m_relAttribute.m_isDNSPrefetch) { + Settings* settings = document()->settings(); + // FIXME: The href attribute of the link element can be in "//hostname" form, and we shouldn't attempt + // to complete that as URL <https://bugs.webkit.org/show_bug.cgi?id=48857>. + if (settings && settings->dnsPrefetchingEnabled() && m_url.isValid() && !m_url.isEmpty()) + ResourceHandle::prepareForURL(m_url); + } +>>>>>>> webkit.org at r71558 #if ENABLE(LINK_PREFETCH) if (m_relAttribute.m_isLinkPrefetch && m_url.isValid() && document()->frame()) diff --git a/WebCore/html/HTMLMediaElement.cpp b/WebCore/html/HTMLMediaElement.cpp index 3f6c286..5b75dde 100644 --- a/WebCore/html/HTMLMediaElement.cpp +++ b/WebCore/html/HTMLMediaElement.cpp @@ -1119,6 +1119,18 @@ void HTMLMediaElement::seek(float time, ExceptionCode& ec) float earliestTime = m_player->startTime(); time = max(time, earliestTime); + // Ask the media engine for the time value in the movie's time scale before comparing with current time. This + // is necessary because if the seek time is not equal to currentTime but the delta is less than the movie's + // time scale, we will ask the media engine to "seek" to the current movie time, which may be a noop and + // not generate a timechanged callback. This means m_seeking will never be cleared and we will never + // fire a 'seeked' event. +#if !LOG_DISABLED + float mediaTime = m_player->mediaTimeForTimeValue(time); + if (time != mediaTime) + LOG(Media, "HTMLMediaElement::seek(%f) - media timeline equivalent is %f", time, mediaTime); +#endif + time = m_player->mediaTimeForTimeValue(time); + // 7 - If the (possibly now changed) new playback position is not in one of the ranges given in the // seekable attribute, then let it be the position in one of the ranges given in the seekable attribute // that is the nearest to the new playback position. ... If there are no ranges given in the seekable diff --git a/WebCore/html/HTMLOutputElement.cpp b/WebCore/html/HTMLOutputElement.cpp new file mode 100644 index 0000000..dee21ae --- /dev/null +++ b/WebCore/html/HTMLOutputElement.cpp @@ -0,0 +1,137 @@ +/* + * 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "HTMLOutputElement.h" + +#include "HTMLFormElement.h" +#include "HTMLNames.h" + +namespace WebCore { + +inline HTMLOutputElement::HTMLOutputElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form) + : HTMLFormControlElement(tagName, document, form) + , m_isDefaultValueMode(true) + , m_isSetTextContentInProgress(false) + , m_defaultValue() + , m_tokens(DOMSettableTokenList::create()) +{ +} + +PassRefPtr<HTMLOutputElement> HTMLOutputElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form) +{ + return adoptRef(new HTMLOutputElement(tagName, document, form)); +} + +const AtomicString& HTMLOutputElement::formControlType() const +{ + DEFINE_STATIC_LOCAL(const AtomicString, output, ("output")); + return output; +} + +void HTMLOutputElement::parseMappedAttribute(Attribute* attr) +{ + // FIXME: Should handle the 'form' attribute here. + if (attr->name() == HTMLNames::forAttr) + setFor(attr->value()); + else + HTMLFormControlElement::parseMappedAttribute(attr); +} + +DOMSettableTokenList* HTMLOutputElement::htmlFor() const +{ + return m_tokens.get(); +} + +void HTMLOutputElement::setFor(const String& value) +{ + m_tokens->setValue(value); +} + +void HTMLOutputElement::setForm(const String& /*id*/) +{ + // FIXME: Implement this function. +} + +void HTMLOutputElement::childrenChanged(bool createdByParser, Node*, Node*, int) +{ + if (createdByParser || m_isSetTextContentInProgress) { + m_isSetTextContentInProgress = false; + return; + } + + if (m_isDefaultValueMode) + m_defaultValue = textContent(); +} + +void HTMLOutputElement::reset() +{ + // The reset algorithm for output elements is to set the element's + // value mode flag to "default" and then to set the element's textContent + // attribute to the default value. + m_isDefaultValueMode = true; + setTextContentInternal(m_defaultValue); +} + +String HTMLOutputElement::value() const +{ + return textContent(); +} + +void HTMLOutputElement::setValue(const String& value) +{ + // The value mode flag set to "value" when the value attribute is set. + m_isDefaultValueMode = false; + setTextContentInternal(value); +} + +String HTMLOutputElement::defaultValue() const +{ + return m_defaultValue; +} + +void HTMLOutputElement::setDefaultValue(const String& value) +{ + m_defaultValue = value; + // The spec requires the value attribute set to the default value + // when the element's value mode flag to "default". + if (m_isDefaultValueMode) + setTextContentInternal(value); +} + +void HTMLOutputElement::setTextContentInternal(const String& value) +{ + ASSERT(!m_isSetTextContentInProgress); + ExceptionCode ec; + m_isSetTextContentInProgress = true; + setTextContent(value, ec); +} + +} // namespace diff --git a/WebCore/html/HTMLOutputElement.h b/WebCore/html/HTMLOutputElement.h new file mode 100644 index 0000000..df807fb --- /dev/null +++ b/WebCore/html/HTMLOutputElement.h @@ -0,0 +1,73 @@ +/* + * 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HTMLOutputElement_h +#define HTMLOutputElement_h + +#include "DOMSettableTokenList.h" +#include "HTMLFormControlElement.h" +#include <wtf/OwnPtr.h> + +namespace WebCore { + +class HTMLOutputElement : public HTMLFormControlElement { +public: + static PassRefPtr<HTMLOutputElement> create(const QualifiedName&, Document*, HTMLFormElement*); + + virtual bool willValidate() const { return false; } + + void setForm(const String&); + String value() const; + void setValue(const String&); + String defaultValue() const; + void setDefaultValue(const String&); + void setFor(const String&); + DOMSettableTokenList* htmlFor() const; + +private: + HTMLOutputElement(const QualifiedName&, Document*, HTMLFormElement*); + + virtual void parseMappedAttribute(Attribute*); + virtual const AtomicString& formControlType() const; + virtual bool isEnumeratable() const { return true; } + virtual void childrenChanged(bool createdByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); + virtual void reset(); + + void setTextContentInternal(const String&); + + bool m_isDefaultValueMode; + bool m_isSetTextContentInProgress; + String m_defaultValue; + RefPtr<DOMSettableTokenList> m_tokens; +}; + +} // namespace + +#endif diff --git a/WebCore/html/HTMLOutputElement.idl b/WebCore/html/HTMLOutputElement.idl new file mode 100644 index 0000000..4e6cbfb --- /dev/null +++ b/WebCore/html/HTMLOutputElement.idl @@ -0,0 +1,43 @@ +/* + * 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 INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module html { + interface HTMLOutputElement : HTMLElement { + attribute [Custom] DOMSettableTokenList htmlFor; + readonly attribute HTMLFormElement form; + attribute [Reflect] DOMString name; + + readonly attribute DOMString type; + attribute [ConvertNullToNullString] DOMString defaultValue; + attribute [ConvertNullToNullString] DOMString value; + + readonly attribute boolean willValidate; + readonly attribute ValidityState validity; + readonly attribute DOMString validationMessage; + boolean checkValidity(); + void setCustomValidity(in [ConvertUndefinedOrNullToNullString] DOMString error); + + readonly attribute NodeList labels; + }; +} diff --git a/WebCore/html/HTMLTableElement.cpp b/WebCore/html/HTMLTableElement.cpp index fe823ea..f6344d4 100644 --- a/WebCore/html/HTMLTableElement.cpp +++ b/WebCore/html/HTMLTableElement.cpp @@ -424,8 +424,8 @@ void HTMLTableElement::parseMappedAttribute(Attribute* attr) } else if (attr->name() == alignAttr) { if (!attr->value().isEmpty()) { if (equalIgnoringCase(attr->value(), "center")) { - addCSSProperty(attr, CSSPropertyMarginLeft, CSSValueAuto); - addCSSProperty(attr, CSSPropertyMarginRight, CSSValueAuto); + addCSSProperty(attr, CSSPropertyWebkitMarginStart, CSSValueAuto); + addCSSProperty(attr, CSSPropertyWebkitMarginEnd, CSSValueAuto); } else addCSSProperty(attr, CSSPropertyFloat, attr->value()); } diff --git a/WebCore/html/HTMLTagNames.in b/WebCore/html/HTMLTagNames.in index 209636d..2b2c1fe 100644 --- a/WebCore/html/HTMLTagNames.in +++ b/WebCore/html/HTMLTagNames.in @@ -93,6 +93,7 @@ object constructorNeedsCreatedByParser ol interfaceName=HTMLOListElement optgroup interfaceName=HTMLOptGroupElement, constructorNeedsFormElement option constructorNeedsFormElement +output constructorNeedsFormElement p interfaceName=HTMLParagraphElement param plaintext interfaceName=HTMLElement diff --git a/WebCore/html/ValidationMessage.cpp b/WebCore/html/ValidationMessage.cpp new file mode 100644 index 0000000..d32917e --- /dev/null +++ b/WebCore/html/ValidationMessage.cpp @@ -0,0 +1,70 @@ +/* + * 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ValidationMessage.h" + +#include <wtf/PassOwnPtr.h> + +namespace WebCore { + +ALWAYS_INLINE ValidationMessage::ValidationMessage(HTMLFormControlElement* element) + : m_element(element) +{ +} + +ValidationMessage::~ValidationMessage() +{ + hideMessage(); +} + +PassOwnPtr<ValidationMessage> ValidationMessage::create(HTMLFormControlElement* element) +{ + return adoptPtr(new ValidationMessage(element)); +} + +void ValidationMessage::setMessage(const String& message) +{ + // FIXME: Construct validation message UI if m_message is empty. + + m_message = message; + + m_timer.set(new Timer<ValidationMessage>(this, &ValidationMessage::hideMessage)); + m_timer->startOneShot(6.0); // FIXME: should be <message length> * something. +} + +void ValidationMessage::hideMessage(Timer<ValidationMessage>*) +{ + // FIXME: Implement. + + m_message = String(); +} + +} // namespace WebCore diff --git a/WebCore/html/ValidationMessage.h b/WebCore/html/ValidationMessage.h new file mode 100644 index 0000000..fe18b6b --- /dev/null +++ b/WebCore/html/ValidationMessage.h @@ -0,0 +1,61 @@ +/* + * 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ValidationMessage_h +#define ValidationMessage_h + +#include "Timer.h" +#include <wtf/Noncopyable.h> +#include <wtf/OwnPtr.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class HTMLFormControlElement; + +class ValidationMessage : public Noncopyable { +public: + static PassOwnPtr<ValidationMessage> create(HTMLFormControlElement*); + ~ValidationMessage(); + String message() const { return m_message; } + void setMessage(const String&); + +private: + ValidationMessage(HTMLFormControlElement*); + void hideMessage(Timer<ValidationMessage>* = 0); + + HTMLFormControlElement* m_element; + String m_message; + OwnPtr<Timer<ValidationMessage> > m_timer; +}; + +} // namespace WebCore + +#endif // ValidationMessage_h diff --git a/WebCore/html/canvas/CanvasRenderingContext2D.cpp b/WebCore/html/canvas/CanvasRenderingContext2D.cpp index b1d7b23..a2d9e98 100644 --- a/WebCore/html/canvas/CanvasRenderingContext2D.cpp +++ b/WebCore/html/canvas/CanvasRenderingContext2D.cpp @@ -1582,6 +1582,15 @@ PassRefPtr<ImageData> CanvasRenderingContext2D::getImageData(float sx, float sy, return 0; } + if (sw < 0) { + sx += sw; + sw = -sw; + } + if (sh < 0) { + sy += sh; + sh = -sh; + } + FloatRect unscaledRect(sx, sy, sw, sh); IntRect scaledRect = canvas()->convertLogicalToDevice(unscaledRect); if (scaledRect.width() < 1) diff --git a/WebCore/html/canvas/WebGLContextEvent.cpp b/WebCore/html/canvas/WebGLContextEvent.cpp new file mode 100644 index 0000000..b7a277f --- /dev/null +++ b/WebCore/html/canvas/WebGLContextEvent.cpp @@ -0,0 +1,54 @@ +/* + * 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 AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebGLContextEvent.h" + +namespace WebCore { + +WebGLContextEvent::WebGLContextEvent() +{ +} + +WebGLContextEvent::WebGLContextEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& statusMessage) + : Event(type, canBubble, cancelable) + , m_statusMessage(statusMessage) +{ +} + +WebGLContextEvent::~WebGLContextEvent() +{ +} + +void WebGLContextEvent::initEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& statusMessage) +{ + if (dispatched()) + return; + + Event::initEvent(type, canBubble, cancelable); + m_statusMessage = statusMessage; +} + +} // namespace WebCore diff --git a/WebCore/html/canvas/WebGLContextEvent.h b/WebCore/html/canvas/WebGLContextEvent.h new file mode 100644 index 0000000..348769b --- /dev/null +++ b/WebCore/html/canvas/WebGLContextEvent.h @@ -0,0 +1,58 @@ +/* + * 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 AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WebGLContextEvent_h +#define WebGLContextEvent_h + +#include "Event.h" + +namespace WebCore { + +class WebGLContextEvent : public Event { +public: + static PassRefPtr<WebGLContextEvent> create() + { + return adoptRef(new WebGLContextEvent); + } + static PassRefPtr<WebGLContextEvent> create(const AtomicString& type, bool canBubble, bool cancelable, const String& statusMessage) + { + return adoptRef(new WebGLContextEvent(type, canBubble, cancelable, statusMessage)); + } + virtual ~WebGLContextEvent(); + + void initEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& statusMessage); + + const String& statusMessage() const { return m_statusMessage; } + +private: + WebGLContextEvent(); + WebGLContextEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& statusMessage); + + String m_statusMessage; +}; + +} // namespace WebCore + +#endif // WebGLContextEvent_h diff --git a/WebCore/html/canvas/WebGLContextEvent.idl b/WebCore/html/canvas/WebGLContextEvent.idl new file mode 100644 index 0000000..30973a9 --- /dev/null +++ b/WebCore/html/canvas/WebGLContextEvent.idl @@ -0,0 +1,36 @@ +/* + * 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 AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module html { + interface [ + Conditional=3D_CANVAS, + ] WebGLContextEvent : Event { + readonly attribute DOMString statusMessage; + [StrictTypeChecking] void initEvent(in DOMString eventTypeArg, + in boolean canBubbleArg, + in boolean cancelableArg, + in DOMString statusMessageArg); + }; +} diff --git a/WebCore/html/canvas/WebGLFramebuffer.cpp b/WebCore/html/canvas/WebGLFramebuffer.cpp index 0fdcb99..5bf3779 100644 --- a/WebCore/html/canvas/WebGLFramebuffer.cpp +++ b/WebCore/html/canvas/WebGLFramebuffer.cpp @@ -32,7 +32,42 @@ #include "WebGLRenderingContext.h" namespace WebCore { - + +namespace { + + // This function is only for depth/stencil/depth_stencil attachment. + // Currently we assume these attachments are all renderbuffers. + unsigned long getInternalFormat(WebGLObject* buffer) + { + ASSERT(buffer && buffer->isRenderbuffer()); + return (reinterpret_cast<WebGLRenderbuffer*>(buffer))->getInternalFormat(); + } + + bool isUninitialized(WebGLObject* attachedObject) + { + if (attachedObject && attachedObject->object() && attachedObject->isRenderbuffer() + && !(reinterpret_cast<WebGLRenderbuffer*>(attachedObject))->isInitialized()) + return true; + return false; + } + + void setInitialized(WebGLObject* attachedObject) + { + if (attachedObject && attachedObject->object() && attachedObject->isRenderbuffer()) + (reinterpret_cast<WebGLRenderbuffer*>(attachedObject))->setInitialized(); + } + + bool isValid(WebGLObject* attachedObject) + { + if (attachedObject && attachedObject->object() && attachedObject->isRenderbuffer()) { + if (!(reinterpret_cast<WebGLRenderbuffer*>(attachedObject))->isValid()) + return false; + } + return true; + } + +} // anonymous namespace + PassRefPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContext* ctx) { return adoptRef(new WebGLFramebuffer(ctx)); @@ -66,7 +101,24 @@ void WebGLFramebuffer::setAttachment(unsigned long attachment, WebGLObject* atta default: return; } - initializeRenderbuffers(); +} + +WebGLObject* WebGLFramebuffer::getAttachment(unsigned long attachment) const +{ + if (!object()) + return 0; + switch (attachment) { + case GraphicsContext3D::COLOR_ATTACHMENT0: + return m_colorAttachment.get(); + case GraphicsContext3D::DEPTH_ATTACHMENT: + return m_depthAttachment.get(); + case GraphicsContext3D::STENCIL_ATTACHMENT: + return m_stencilAttachment.get(); + case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT: + return m_depthStencilAttachment.get(); + default: + return 0; + } } void WebGLFramebuffer::removeAttachment(WebGLObject* attachment) @@ -83,25 +135,9 @@ void WebGLFramebuffer::removeAttachment(WebGLObject* attachment) m_depthStencilAttachment = 0; else return; - initializeRenderbuffers(); -} - -void WebGLFramebuffer::onBind() -{ - initializeRenderbuffers(); } -void WebGLFramebuffer::onAttachedObjectChange(WebGLObject* object) -{ - // Currently object == 0 is not considered, but this might change if the - // lifespan of WebGLObject changes. - if (object - && (object == m_colorAttachment.get() || object == m_depthAttachment.get() - || object == m_stencilAttachment.get() || object == m_depthStencilAttachment.get())) - initializeRenderbuffers(); -} - -unsigned long WebGLFramebuffer::getColorBufferFormat() +unsigned long WebGLFramebuffer::getColorBufferFormat() const { if (object() && m_colorAttachment && m_colorAttachment->object()) { if (m_colorAttachment->isRenderbuffer()) { @@ -119,6 +155,38 @@ unsigned long WebGLFramebuffer::getColorBufferFormat() return 0; } +bool WebGLFramebuffer::isIncomplete(bool checkInternalFormat) const +{ + unsigned int count = 0; + if (isDepthAttached()) { + if (checkInternalFormat && getInternalFormat(m_depthAttachment.get()) != GraphicsContext3D::DEPTH_COMPONENT16) + return true; + count++; + } + if (isStencilAttached()) { + if (checkInternalFormat && getInternalFormat(m_stencilAttachment.get()) != GraphicsContext3D::STENCIL_INDEX8) + return true; + count++; + } + if (isDepthStencilAttached()) { + if (checkInternalFormat && getInternalFormat(m_depthStencilAttachment.get()) != GraphicsContext3D::DEPTH_STENCIL) + return true; + if (!isValid(m_depthStencilAttachment.get())) + return true; + count++; + } + if (count > 1) + return true; + return false; +} + +bool WebGLFramebuffer::onAccess() +{ + if (isIncomplete(true)) + return false; + return initializeRenderbuffers(); +} + void WebGLFramebuffer::deleteObjectImpl(Platform3DObject object) { if (!isDeleted()) @@ -129,24 +197,11 @@ void WebGLFramebuffer::deleteObjectImpl(Platform3DObject object) m_depthStencilAttachment = 0; } -bool WebGLFramebuffer::isUninitialized(WebGLObject* attachedObject) +bool WebGLFramebuffer::initializeRenderbuffers() { - if (attachedObject && attachedObject->object() && attachedObject->isRenderbuffer() - && !(reinterpret_cast<WebGLRenderbuffer*>(attachedObject))->isInitialized()) - return true; - return false; -} - -void WebGLFramebuffer::setInitialized(WebGLObject* attachedObject) -{ - if (attachedObject && attachedObject->object() && attachedObject->isRenderbuffer()) - (reinterpret_cast<WebGLRenderbuffer*>(attachedObject))->setInitialized(); -} - -void WebGLFramebuffer::initializeRenderbuffers() -{ - if (!object()) - return; + ASSERT(object()); + if (!isColorAttached()) + return false; bool initColor = false, initDepth = false, initStencil = false; unsigned long mask = 0; if (isUninitialized(m_colorAttachment.get())) { @@ -167,13 +222,13 @@ void WebGLFramebuffer::initializeRenderbuffers() mask |= (GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT); } if (!initColor && !initDepth && !initStencil) - return; + return true; // We only clear un-initialized renderbuffers when they are ready to be // read, i.e., when the framebuffer is complete. GraphicsContext3D* g3d = context()->graphicsContext3D(); if (g3d->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) - return; + return false; float colorClearValue[] = {0, 0, 0, 0}, depthClearValue = 0; int stencilClearValue = 0; @@ -237,6 +292,7 @@ void WebGLFramebuffer::initializeRenderbuffers() if (initStencil) setInitialized(m_stencilAttachment.get()); } + return true; } } diff --git a/WebCore/html/canvas/WebGLFramebuffer.h b/WebCore/html/canvas/WebGLFramebuffer.h index 1892694..394b770 100644 --- a/WebCore/html/canvas/WebGLFramebuffer.h +++ b/WebCore/html/canvas/WebGLFramebuffer.h @@ -39,27 +39,22 @@ public: static PassRefPtr<WebGLFramebuffer> create(WebGLRenderingContext*); - bool isDepthAttached() const { return (m_depthAttachment && m_depthAttachment->object()); } - bool isStencilAttached() const { return (m_stencilAttachment && m_stencilAttachment->object()); } - bool isDepthStencilAttached() const { return (m_depthStencilAttachment && m_depthStencilAttachment->object()); } - void setAttachment(unsigned long, WebGLObject*); // If an object is attached to the framebuffer, remove it. void removeAttachment(WebGLObject*); + WebGLObject* getAttachment(unsigned long) const; - // This function is called right after a framebuffer is bound. - // Because renderbuffers and textures attached to the framebuffer might - // have changed and the framebuffer might have become complete when it - // isn't bound, so we need to clear un-initialized renderbuffers. - void onBind(); + unsigned long getColorBufferFormat() const; - // When a texture or a renderbuffer changes, we need to check the - // current bound framebuffer; if the newly changed object is attached - // to the framebuffer and the framebuffer becomes complete, we need to - // clear un-initialized renderbuffers. - void onAttachedObjectChange(WebGLObject*); + // This should always be called before drawArray, drawElements, clear, + // readPixels, copyTexImage2D, copyTexSubImage2D if this framebuffer is + // currently bound. + // Return false if the framebuffer is incomplete; otherwise initialize + // the buffers if they haven't been initialized. + bool onAccess(); - unsigned long getColorBufferFormat(); + // Return false does not mean COMPLETE, might still be INCOMPLETE. + bool isIncomplete(bool checkInternalFormat) const; protected: WebGLFramebuffer(WebGLRenderingContext*); @@ -69,9 +64,13 @@ protected: private: virtual bool isFramebuffer() const { return true; } - bool isUninitialized(WebGLObject*); - void setInitialized(WebGLObject*); - void initializeRenderbuffers(); + // Return false if framebuffer is incomplete. + bool initializeRenderbuffers(); + + bool isColorAttached() const { return (m_colorAttachment && m_colorAttachment->object()); } + bool isDepthAttached() const { return (m_depthAttachment && m_depthAttachment->object()); } + bool isStencilAttached() const { return (m_stencilAttachment && m_stencilAttachment->object()); } + bool isDepthStencilAttached() const { return (m_depthStencilAttachment && m_depthStencilAttachment->object()); } RefPtr<WebGLObject> m_colorAttachment; RefPtr<WebGLObject> m_depthAttachment; diff --git a/WebCore/html/canvas/WebGLRenderbuffer.cpp b/WebCore/html/canvas/WebGLRenderbuffer.cpp index 4772873..b9efd47 100644 --- a/WebCore/html/canvas/WebGLRenderbuffer.cpp +++ b/WebCore/html/canvas/WebGLRenderbuffer.cpp @@ -42,6 +42,9 @@ WebGLRenderbuffer::WebGLRenderbuffer(WebGLRenderingContext* ctx) : WebGLObject(ctx) , m_internalFormat(GraphicsContext3D::RGBA4) , m_initialized(false) + , m_width(0) + , m_height(0) + , m_isValid(true) { setObject(context()->graphicsContext3D()->createRenderbuffer()); } diff --git a/WebCore/html/canvas/WebGLRenderbuffer.h b/WebCore/html/canvas/WebGLRenderbuffer.h index 5765061..9a23ca5 100644 --- a/WebCore/html/canvas/WebGLRenderbuffer.h +++ b/WebCore/html/canvas/WebGLRenderbuffer.h @@ -39,9 +39,24 @@ public: static PassRefPtr<WebGLRenderbuffer> create(WebGLRenderingContext*); - void setInternalFormat(unsigned long internalformat) { m_internalFormat = internalformat; } + void setInternalFormat(unsigned long internalformat) + { + m_internalFormat = internalformat; + m_initialized = false; + } unsigned long getInternalFormat() const { return m_internalFormat; } + void setSize(unsigned long width, unsigned long height) + { + m_width = width; + m_height = height; + } + unsigned long getWidth() const { return m_width; } + unsigned long getHeight() const { return m_height; } + + void setIsValid(bool isValid) { m_isValid = isValid; } + bool isValid() const { return m_isValid; } + bool isInitialized() const { return m_initialized; } void setInitialized() { m_initialized = true; } @@ -55,6 +70,8 @@ private: unsigned long m_internalFormat; bool m_initialized; + unsigned long m_width, m_height; + bool m_isValid; // This is only false if internalFormat is DEPTH_STENCIL and packed_depth_stencil is not supported. }; } // namespace WebCore diff --git a/WebCore/html/canvas/WebGLRenderingContext.cpp b/WebCore/html/canvas/WebGLRenderingContext.cpp index 0b89cce..94dac10 100644 --- a/WebCore/html/canvas/WebGLRenderingContext.cpp +++ b/WebCore/html/canvas/WebGLRenderingContext.cpp @@ -34,6 +34,7 @@ #include "CheckedInt.h" #include "Console.h" #include "DOMWindow.h" +#include "Extensions3D.h" #include "FrameView.h" #include "HTMLCanvasElement.h" #include "HTMLImageElement.h" @@ -48,6 +49,7 @@ #include "WebGLActiveInfo.h" #include "WebGLBuffer.h" #include "WebGLContextAttributes.h" +#include "WebGLContextEvent.h" #include "WebGLFramebuffer.h" #include "WebGLProgram.h" #include "WebGLRenderbuffer.h" @@ -90,8 +92,10 @@ PassOwnPtr<WebGLRenderingContext> WebGLRenderingContext::create(HTMLCanvasElemen GraphicsContext3D::Attributes emptyAttributes; RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(attrs ? attrs->attributes() : emptyAttributes, hostWindow)); - if (!context) + if (!context) { + canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Could not create a WebGL context.")); return 0; + } return new WebGLRenderingContext(canvas, context); } @@ -99,32 +103,41 @@ PassOwnPtr<WebGLRenderingContext> WebGLRenderingContext::create(HTMLCanvasElemen WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, PassRefPtr<GraphicsContext3D> context) : CanvasRenderingContext(passedCanvas) , m_context(context) - , m_needsUpdate(true) - , m_markedCanvasDirty(false) - , m_activeTextureUnit(0) , m_videoCache(4) - , m_packAlignment(4) - , m_unpackAlignment(4) - , m_unpackFlipY(false) - , m_unpackPremultiplyAlpha(false) + , m_contextLost(false) + , m_stencilMask(0xFFFFFFFF) + , m_stencilFuncRef(0) + , m_stencilFuncMask(0xFFFFFFFF) { ASSERT(m_context); + initializeNewContext(); +} + +void WebGLRenderingContext::initializeNewContext() +{ + m_needsUpdate = true; + m_markedCanvasDirty = false; + m_activeTextureUnit = 0; + m_packAlignment = 4; + m_unpackAlignment = 4; + m_unpackFlipY = false; + m_unpackPremultiplyAlpha = false; + m_boundArrayBuffer = 0; + m_boundElementArrayBuffer = 0; + m_currentProgram = 0; + m_framebufferBinding = 0; + m_renderbufferBinding = 0; + m_vertexAttribState.clear(); int numCombinedTextureImageUnits = 0; m_context->getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numCombinedTextureImageUnits); + m_textureUnits.clear(); m_textureUnits.resize(numCombinedTextureImageUnits); int numVertexAttribs = 0; m_context->getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &numVertexAttribs); m_maxVertexAttribs = numVertexAttribs; - int implementationColorReadFormat = GraphicsContext3D::RGBA; - m_context->getIntegerv(GraphicsContext3D::IMPLEMENTATION_COLOR_READ_FORMAT, &implementationColorReadFormat); - m_implementationColorReadFormat = implementationColorReadFormat; - int implementationColorReadType = GraphicsContext3D::UNSIGNED_BYTE; - m_context->getIntegerv(GraphicsContext3D::IMPLEMENTATION_COLOR_READ_TYPE, &implementationColorReadType); - m_implementationColorReadType = implementationColorReadType; - m_maxTextureSize = 0; m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize); m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize); @@ -136,6 +149,12 @@ WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, Pa createFallbackBlackTextures1x1(); if (!isGLES2Compliant()) initVertexAttrib0(); + + if (isGLES2Compliant()) + m_isDepthStencilSupported = m_context->getExtensions()->supports("GL_OES_packed_depth_stencil"); + else + m_isDepthStencilSupported = m_context->getExtensions()->supports("GL_EXT_packed_depth_stencil"); + m_context->reshape(canvas()->width(), canvas()->height()); m_context->viewport(0, 0, canvas()->width(), canvas()->height()); } @@ -199,6 +218,8 @@ int WebGLRenderingContext::sizeInBytes(int type) void WebGLRenderingContext::activeTexture(unsigned long texture, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return; if (texture - GraphicsContext3D::TEXTURE0 >= m_textureUnits.size()) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); return; @@ -211,7 +232,7 @@ void WebGLRenderingContext::activeTexture(unsigned long texture, ExceptionCode& void WebGLRenderingContext::attachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateWebGLObject(program) || !validateWebGLObject(shader)) + if (isContextLost() || !validateWebGLObject(program) || !validateWebGLObject(shader)) return; if (!program->attachShader(shader)) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); @@ -225,7 +246,7 @@ void WebGLRenderingContext::attachShader(WebGLProgram* program, WebGLShader* sha void WebGLRenderingContext::bindAttribLocation(WebGLProgram* program, unsigned long index, const String& name, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateWebGLObject(program)) + if (isContextLost() || !validateWebGLObject(program)) return; m_context->bindAttribLocation(objectOrZero(program), index, name); cleanupAfterGraphicsCall(false); @@ -234,6 +255,8 @@ void WebGLRenderingContext::bindAttribLocation(WebGLProgram* program, unsigned l void WebGLRenderingContext::bindBuffer(unsigned long target, WebGLBuffer* buffer, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return; if (buffer && buffer->context() != this) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; @@ -262,6 +285,8 @@ void WebGLRenderingContext::bindBuffer(unsigned long target, WebGLBuffer* buffer void WebGLRenderingContext::bindFramebuffer(unsigned long target, WebGLFramebuffer* buffer, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return; if (buffer && buffer->context() != this) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; @@ -272,14 +297,14 @@ void WebGLRenderingContext::bindFramebuffer(unsigned long target, WebGLFramebuff } m_framebufferBinding = buffer; m_context->bindFramebuffer(target, objectOrZero(buffer)); - if (m_framebufferBinding) - m_framebufferBinding->onBind(); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::bindRenderbuffer(unsigned long target, WebGLRenderbuffer* renderBuffer, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return; if (renderBuffer && renderBuffer->context() != this) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; @@ -297,6 +322,8 @@ void WebGLRenderingContext::bindRenderbuffer(unsigned long target, WebGLRenderbu void WebGLRenderingContext::bindTexture(unsigned long target, WebGLTexture* texture, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return; if (texture && texture->context() != this) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; @@ -330,13 +357,15 @@ void WebGLRenderingContext::bindTexture(unsigned long target, WebGLTexture* text void WebGLRenderingContext::blendColor(double red, double green, double blue, double alpha) { + if (isContextLost()) + return; m_context->blendColor(red, green, blue, alpha); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::blendEquation(unsigned long mode) { - if (!validateBlendEquation(mode)) + if (isContextLost() || !validateBlendEquation(mode)) return; m_context->blendEquation(mode); cleanupAfterGraphicsCall(false); @@ -344,7 +373,7 @@ void WebGLRenderingContext::blendEquation(unsigned long mode) void WebGLRenderingContext::blendEquationSeparate(unsigned long modeRGB, unsigned long modeAlpha) { - if (!validateBlendEquation(modeRGB) || !validateBlendEquation(modeAlpha)) + if (isContextLost() || !validateBlendEquation(modeRGB) || !validateBlendEquation(modeAlpha)) return; m_context->blendEquationSeparate(modeRGB, modeAlpha); cleanupAfterGraphicsCall(false); @@ -353,12 +382,16 @@ void WebGLRenderingContext::blendEquationSeparate(unsigned long modeRGB, unsigne void WebGLRenderingContext::blendFunc(unsigned long sfactor, unsigned long dfactor) { + if (isContextLost() || !validateBlendFuncFactors(sfactor, dfactor)) + return; m_context->blendFunc(sfactor, dfactor); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::blendFuncSeparate(unsigned long srcRGB, unsigned long dstRGB, unsigned long srcAlpha, unsigned long dstAlpha) { + if (isContextLost() || !validateBlendFuncFactors(srcRGB, dstRGB)) + return; m_context->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); cleanupAfterGraphicsCall(false); } @@ -366,6 +399,8 @@ void WebGLRenderingContext::blendFuncSeparate(unsigned long srcRGB, unsigned lon void WebGLRenderingContext::bufferData(unsigned long target, int size, unsigned long usage, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return; WebGLBuffer* buffer = validateBufferDataParameters(target, usage); if (!buffer) return; @@ -383,6 +418,8 @@ void WebGLRenderingContext::bufferData(unsigned long target, int size, unsigned void WebGLRenderingContext::bufferData(unsigned long target, ArrayBuffer* data, unsigned long usage, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return; WebGLBuffer* buffer = validateBufferDataParameters(target, usage); if (!buffer) return; @@ -400,6 +437,8 @@ void WebGLRenderingContext::bufferData(unsigned long target, ArrayBuffer* data, void WebGLRenderingContext::bufferData(unsigned long target, ArrayBufferView* data, unsigned long usage, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return; WebGLBuffer* buffer = validateBufferDataParameters(target, usage); if (!buffer) return; @@ -417,6 +456,8 @@ void WebGLRenderingContext::bufferData(unsigned long target, ArrayBufferView* da void WebGLRenderingContext::bufferSubData(unsigned long target, long offset, ArrayBuffer* data, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return; WebGLBuffer* buffer = validateBufferDataParameters(target, GraphicsContext3D::STATIC_DRAW); if (!buffer) return; @@ -434,6 +475,8 @@ void WebGLRenderingContext::bufferSubData(unsigned long target, long offset, Arr void WebGLRenderingContext::bufferSubData(unsigned long target, long offset, ArrayBufferView* data, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return; WebGLBuffer* buffer = validateBufferDataParameters(target, GraphicsContext3D::STATIC_DRAW); if (!buffer) return; @@ -450,28 +493,40 @@ void WebGLRenderingContext::bufferSubData(unsigned long target, long offset, Arr unsigned long WebGLRenderingContext::checkFramebufferStatus(unsigned long target) { + if (isContextLost()) + return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED; if (target != GraphicsContext3D::FRAMEBUFFER) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); return 0; } if (!m_framebufferBinding || !m_framebufferBinding->object()) return GraphicsContext3D::FRAMEBUFFER_COMPLETE; + if (m_framebufferBinding->isIncomplete(true)) + return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED; return m_context->checkFramebufferStatus(target); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::clear(unsigned long mask) { + if (isContextLost()) + return; if (mask & ~(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); return; } + if (m_framebufferBinding && !m_framebufferBinding->onAccess()) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION); + return; + } m_context->clear(mask); cleanupAfterGraphicsCall(true); } void WebGLRenderingContext::clearColor(double r, double g, double b, double a) { + if (isContextLost()) + return; if (isnan(r)) r = 0; if (isnan(g)) @@ -486,18 +541,24 @@ void WebGLRenderingContext::clearColor(double r, double g, double b, double a) void WebGLRenderingContext::clearDepth(double depth) { + if (isContextLost()) + return; m_context->clearDepth(depth); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::clearStencil(long s) { + if (isContextLost()) + return; m_context->clearStencil(s); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::colorMask(bool red, bool green, bool blue, bool alpha) { + if (isContextLost()) + return; m_context->colorMask(red, green, blue, alpha); cleanupAfterGraphicsCall(false); } @@ -505,7 +566,7 @@ void WebGLRenderingContext::colorMask(bool red, bool green, bool blue, bool alph void WebGLRenderingContext::compileShader(WebGLShader* shader, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateWebGLObject(shader)) + if (isContextLost() || !validateWebGLObject(shader)) return; m_context->compileShader(objectOrZero(shader)); cleanupAfterGraphicsCall(false); @@ -513,6 +574,8 @@ void WebGLRenderingContext::compileShader(WebGLShader* shader, ExceptionCode& ec void WebGLRenderingContext::copyTexImage2D(unsigned long target, long level, unsigned long internalformat, long x, long y, unsigned long width, unsigned long height, long border) { + if (isContextLost()) + return; if (!validateTexFuncParameters(target, level, internalformat, width, height, border, internalformat, GraphicsContext3D::UNSIGNED_BYTE)) return; WebGLTexture* tex = validateTextureBinding(target, true); @@ -530,16 +593,20 @@ void WebGLRenderingContext::copyTexImage2D(unsigned long target, long level, uns m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); return; } + if (m_framebufferBinding && !m_framebufferBinding->onAccess()) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION); + return; + } m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border); // FIXME: if the framebuffer is not complete, none of the below should be executed. tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE); - if (m_framebufferBinding) - m_framebufferBinding->onAttachedObjectChange(tex); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::copyTexSubImage2D(unsigned long target, long level, long xoffset, long yoffset, long x, long y, unsigned long width, unsigned long height) { + if (isContextLost()) + return; WebGLTexture* tex = validateTextureBinding(target, true); if (!tex) return; @@ -551,12 +618,18 @@ void WebGLRenderingContext::copyTexSubImage2D(unsigned long target, long level, return; } } + if (m_framebufferBinding && !m_framebufferBinding->onAccess()) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION); + return; + } m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); cleanupAfterGraphicsCall(false); } PassRefPtr<WebGLBuffer> WebGLRenderingContext::createBuffer() { + if (isContextLost()) + return 0; RefPtr<WebGLBuffer> o = WebGLBuffer::create(this); addObject(o.get()); return o; @@ -564,6 +637,8 @@ PassRefPtr<WebGLBuffer> WebGLRenderingContext::createBuffer() PassRefPtr<WebGLFramebuffer> WebGLRenderingContext::createFramebuffer() { + if (isContextLost()) + return 0; RefPtr<WebGLFramebuffer> o = WebGLFramebuffer::create(this); addObject(o.get()); return o; @@ -571,6 +646,8 @@ PassRefPtr<WebGLFramebuffer> WebGLRenderingContext::createFramebuffer() PassRefPtr<WebGLTexture> WebGLRenderingContext::createTexture() { + if (isContextLost()) + return 0; RefPtr<WebGLTexture> o = WebGLTexture::create(this); addObject(o.get()); return o; @@ -578,6 +655,8 @@ PassRefPtr<WebGLTexture> WebGLRenderingContext::createTexture() PassRefPtr<WebGLProgram> WebGLRenderingContext::createProgram() { + if (isContextLost()) + return 0; RefPtr<WebGLProgram> o = WebGLProgram::create(this); addObject(o.get()); return o; @@ -585,6 +664,8 @@ PassRefPtr<WebGLProgram> WebGLRenderingContext::createProgram() PassRefPtr<WebGLRenderbuffer> WebGLRenderingContext::createRenderbuffer() { + if (isContextLost()) + return 0; RefPtr<WebGLRenderbuffer> o = WebGLRenderbuffer::create(this); addObject(o.get()); return o; @@ -593,6 +674,8 @@ PassRefPtr<WebGLRenderbuffer> WebGLRenderingContext::createRenderbuffer() PassRefPtr<WebGLShader> WebGLRenderingContext::createShader(unsigned long type, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return 0; if (type != GraphicsContext3D::VERTEX_SHADER && type != GraphicsContext3D::FRAGMENT_SHADER) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); return 0; @@ -605,13 +688,15 @@ PassRefPtr<WebGLShader> WebGLRenderingContext::createShader(unsigned long type, void WebGLRenderingContext::cullFace(unsigned long mode) { + if (isContextLost()) + return; m_context->cullFace(mode); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::deleteBuffer(WebGLBuffer* buffer) { - if (!buffer) + if (isContextLost() || !buffer) return; buffer->deleteObject(); @@ -633,7 +718,7 @@ void WebGLRenderingContext::deleteBuffer(WebGLBuffer* buffer) void WebGLRenderingContext::deleteFramebuffer(WebGLFramebuffer* framebuffer) { - if (!framebuffer) + if (isContextLost() || !framebuffer) return; if (framebuffer == m_framebufferBinding) { m_framebufferBinding = 0; @@ -645,7 +730,7 @@ void WebGLRenderingContext::deleteFramebuffer(WebGLFramebuffer* framebuffer) void WebGLRenderingContext::deleteProgram(WebGLProgram* program) { - if (!program) + if (isContextLost() || !program) return; if (program->context() != this) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); @@ -658,7 +743,7 @@ void WebGLRenderingContext::deleteProgram(WebGLProgram* program) void WebGLRenderingContext::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer) { - if (!renderbuffer) + if (isContextLost() || !renderbuffer) return; if (renderbuffer == m_renderbufferBinding) m_renderbufferBinding = 0; @@ -669,7 +754,7 @@ void WebGLRenderingContext::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer) void WebGLRenderingContext::deleteShader(WebGLShader* shader) { - if (!shader) + if (isContextLost() || !shader) return; shader->deleteObject(); @@ -677,7 +762,7 @@ void WebGLRenderingContext::deleteShader(WebGLShader* shader) void WebGLRenderingContext::deleteTexture(WebGLTexture* texture) { - if (!texture) + if (isContextLost() || !texture) return; texture->deleteObject(); @@ -687,18 +772,28 @@ void WebGLRenderingContext::deleteTexture(WebGLTexture* texture) void WebGLRenderingContext::depthFunc(unsigned long func) { + if (isContextLost()) + return; m_context->depthFunc(func); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::depthMask(bool flag) { + if (isContextLost()) + return; m_context->depthMask(flag); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::depthRange(double zNear, double zFar) { + if (isContextLost()) + return; + if (zNear > zFar) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + return; + } m_context->depthRange(zNear, zFar); cleanupAfterGraphicsCall(false); } @@ -706,7 +801,7 @@ void WebGLRenderingContext::depthRange(double zNear, double zFar) void WebGLRenderingContext::detachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateWebGLObject(program) || !validateWebGLObject(shader)) + if (isContextLost() || !validateWebGLObject(program) || !validateWebGLObject(shader)) return; if (!program->detachShader(shader)) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); @@ -720,7 +815,7 @@ void WebGLRenderingContext::detachShader(WebGLProgram* program, WebGLShader* sha void WebGLRenderingContext::disable(unsigned long cap) { - if (!validateCapability(cap)) + if (isContextLost() || !validateCapability(cap)) return; m_context->disable(cap); cleanupAfterGraphicsCall(false); @@ -729,6 +824,8 @@ void WebGLRenderingContext::disable(unsigned long cap) void WebGLRenderingContext::disableVertexAttribArray(unsigned long index, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return; if (index >= m_maxVertexAttribs) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); return; @@ -925,7 +1022,7 @@ void WebGLRenderingContext::drawArrays(unsigned long mode, long first, long coun { UNUSED_PARAM(ec); - if (!validateDrawMode(mode)) + if (isContextLost() || !validateDrawMode(mode)) return; if (first < 0 || count < 0) { @@ -952,6 +1049,11 @@ void WebGLRenderingContext::drawArrays(unsigned long mode, long first, long coun } } + if (m_framebufferBinding && !m_framebufferBinding->onAccess()) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION); + return; + } + bool vertexAttrib0Simulated = false; if (!isGLES2Compliant()) vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1); @@ -969,7 +1071,7 @@ void WebGLRenderingContext::drawElements(unsigned long mode, long count, unsigne { UNUSED_PARAM(ec); - if (!validateDrawMode(mode)) + if (isContextLost() || !validateDrawMode(mode)) return; switch (type) { @@ -1011,6 +1113,11 @@ void WebGLRenderingContext::drawElements(unsigned long mode, long count, unsigne } } + if (m_framebufferBinding && !m_framebufferBinding->onAccess()) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION); + return; + } + bool vertexAttrib0Simulated = false; if (!isGLES2Compliant()) { if (!numElements) @@ -1029,7 +1136,7 @@ void WebGLRenderingContext::drawElements(unsigned long mode, long count, unsigne void WebGLRenderingContext::enable(unsigned long cap) { - if (!validateCapability(cap)) + if (isContextLost() || !validateCapability(cap)) return; m_context->enable(cap); cleanupAfterGraphicsCall(false); @@ -1038,6 +1145,8 @@ void WebGLRenderingContext::enable(unsigned long cap) void WebGLRenderingContext::enableVertexAttribArray(unsigned long index, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return; if (index >= m_maxVertexAttribs) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); return; @@ -1054,6 +1163,8 @@ void WebGLRenderingContext::enableVertexAttribArray(unsigned long index, Excepti void WebGLRenderingContext::finish() { + if (isContextLost()) + return; m_context->finish(); cleanupAfterGraphicsCall(true); } @@ -1061,6 +1172,8 @@ void WebGLRenderingContext::finish() void WebGLRenderingContext::flush() { + if (isContextLost()) + return; m_context->flush(); cleanupAfterGraphicsCall(true); } @@ -1068,7 +1181,7 @@ void WebGLRenderingContext::flush() void WebGLRenderingContext::framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, WebGLRenderbuffer* buffer, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateFramebufferFuncParameters(target, attachment)) + if (isContextLost() || !validateFramebufferFuncParameters(target, attachment)) return; if (renderbuffertarget != GraphicsContext3D::RENDERBUFFER) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); @@ -1085,42 +1198,61 @@ void WebGLRenderingContext::framebufferRenderbuffer(unsigned long target, unsign m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } - if (buffer && buffer->object()) { - bool isConflicted = false; - switch (attachment) { - case GraphicsContext3D::DEPTH_ATTACHMENT: - if (m_framebufferBinding->isDepthStencilAttached() || m_framebufferBinding->isStencilAttached()) - isConflicted = true; - if (buffer->getInternalFormat() != GraphicsContext3D::DEPTH_COMPONENT16) - isConflicted = true; - break; - case GraphicsContext3D::STENCIL_ATTACHMENT: - if (m_framebufferBinding->isDepthStencilAttached() || m_framebufferBinding->isDepthAttached()) - isConflicted = true; - if (buffer->getInternalFormat() != GraphicsContext3D::STENCIL_INDEX8) - isConflicted = true; - break; - case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT: - if (m_framebufferBinding->isDepthAttached() || m_framebufferBinding->isStencilAttached()) - isConflicted = true; - if (buffer->getInternalFormat() != GraphicsContext3D::DEPTH_STENCIL) - isConflicted = true; - break; - } - if (isConflicted) { - m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); - return; + Platform3DObject bufferObject = objectOrZero(buffer); + bool reattachDepth = false; + bool reattachStencil = false; + bool reattachDepthStencilDepth = false; + bool reattachDepthStencilStencil = false; + switch (attachment) { + case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT: + m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, bufferObject); + m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, bufferObject); + if (!bufferObject) { + reattachDepth = true; + reattachStencil = true; } + break; + case GraphicsContext3D::DEPTH_ATTACHMENT: + m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer)); + if (!bufferObject) + reattachDepthStencilDepth = true; + break; + case GraphicsContext3D::STENCIL_ATTACHMENT: + m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer)); + if (!bufferObject) + reattachDepthStencilStencil = true; + break; + default: + m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer)); } - m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer)); m_framebufferBinding->setAttachment(attachment, buffer); + if (reattachDepth) { + Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_ATTACHMENT)); + if (object) + m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object); + } + if (reattachStencil) { + Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::STENCIL_ATTACHMENT)); + if (object) + m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object); + } + if (reattachDepthStencilDepth) { + Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT)); + if (object) + m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object); + } + if (reattachDepthStencilStencil) { + Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT)); + if (object) + m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object); + } cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, WebGLTexture* texture, long level, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateFramebufferFuncParameters(target, attachment)) + if (isContextLost() || !validateFramebufferFuncParameters(target, attachment)) return; if (level) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); @@ -1144,12 +1276,16 @@ void WebGLRenderingContext::framebufferTexture2D(unsigned long target, unsigned void WebGLRenderingContext::frontFace(unsigned long mode) { + if (isContextLost()) + return; m_context->frontFace(mode); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::generateMipmap(unsigned long target) { + if (isContextLost()) + return; WebGLTexture* tex = validateTextureBinding(target, false); if (!tex) return; @@ -1178,9 +1314,9 @@ void WebGLRenderingContext::generateMipmap(unsigned long target) PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveAttrib(WebGLProgram* program, unsigned long index, ExceptionCode& ec) { UNUSED_PARAM(ec); - ActiveInfo info; - if (!validateWebGLObject(program)) + if (isContextLost() || !validateWebGLObject(program)) return 0; + ActiveInfo info; if (!m_context->getActiveAttrib(objectOrZero(program), index, info)) return 0; return WebGLActiveInfo::create(info.name, info.type, info.size); @@ -1189,9 +1325,9 @@ PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveAttrib(WebGLProgram* PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveUniform(WebGLProgram* program, unsigned long index, ExceptionCode& ec) { UNUSED_PARAM(ec); - ActiveInfo info; - if (!validateWebGLObject(program)) + if (isContextLost() || !validateWebGLObject(program)) return 0; + ActiveInfo info; if (!m_context->getActiveUniform(objectOrZero(program), index, info)) return 0; if (!isGLES2Compliant()) @@ -1204,7 +1340,7 @@ bool WebGLRenderingContext::getAttachedShaders(WebGLProgram* program, Vector<Web { UNUSED_PARAM(ec); shaderObjects.clear(); - if (!validateWebGLObject(program)) + if (isContextLost() || !validateWebGLObject(program)) return false; int numShaders = 0; m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::ATTACHED_SHADERS, &numShaders); @@ -1229,12 +1365,16 @@ bool WebGLRenderingContext::getAttachedShaders(WebGLProgram* program, Vector<Web int WebGLRenderingContext::getAttribLocation(WebGLProgram* program, const String& name) { + if (isContextLost()) + return -1; return m_context->getAttribLocation(objectOrZero(program), name); } WebGLGetInfo WebGLRenderingContext::getBufferParameter(unsigned long target, unsigned long pname, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return WebGLGetInfo(); if (target != GraphicsContext3D::ARRAY_BUFFER && target != GraphicsContext3D::ELEMENT_ARRAY_BUFFER) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); return WebGLGetInfo(); @@ -1255,6 +1395,8 @@ WebGLGetInfo WebGLRenderingContext::getBufferParameter(unsigned long target, uns PassRefPtr<WebGLContextAttributes> WebGLRenderingContext::getContextAttributes() { + if (isContextLost()) + return 0; // We always need to return a new WebGLContextAttributes object to // prevent the user from mutating any cached version. return WebGLContextAttributes::create(m_context->getContextAttributes()); @@ -1268,7 +1410,7 @@ unsigned long WebGLRenderingContext::getError() WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(unsigned long target, unsigned long attachment, unsigned long pname, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateFramebufferFuncParameters(target, attachment)) + if (isContextLost() || !validateFramebufferFuncParameters(target, attachment)) return WebGLGetInfo(); switch (pname) { case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: @@ -1281,7 +1423,7 @@ WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(unsigned l return WebGLGetInfo(); } - if (!m_framebufferBinding || !m_framebufferBinding->object()) { + if (!m_framebufferBinding || !m_framebufferBinding->object() || m_framebufferBinding->isIncomplete(false)) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return WebGLGetInfo(); } @@ -1316,6 +1458,8 @@ WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(unsigned l WebGLGetInfo WebGLRenderingContext::getParameter(unsigned long pname, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return WebGLGetInfo(); WebGLStateRestorer(this, false); switch (pname) { case GraphicsContext3D::ACTIVE_TEXTURE: @@ -1383,10 +1527,6 @@ WebGLGetInfo WebGLRenderingContext::getParameter(unsigned long pname, ExceptionC return getUnsignedLongParameter(pname); case GraphicsContext3D::GREEN_BITS: return getLongParameter(pname); - case GraphicsContext3D::IMPLEMENTATION_COLOR_READ_FORMAT: - return getLongParameter(pname); - case GraphicsContext3D::IMPLEMENTATION_COLOR_READ_TYPE: - return getLongParameter(pname); case GraphicsContext3D::LINE_WIDTH: return getFloatParameter(pname); case GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS: @@ -1507,7 +1647,7 @@ WebGLGetInfo WebGLRenderingContext::getParameter(unsigned long pname, ExceptionC WebGLGetInfo WebGLRenderingContext::getProgramParameter(WebGLProgram* program, unsigned long pname, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateWebGLObject(program)) + if (isContextLost() || !validateWebGLObject(program)) return WebGLGetInfo(); WebGLStateRestorer(this, false); @@ -1536,6 +1676,8 @@ WebGLGetInfo WebGLRenderingContext::getProgramParameter(WebGLProgram* program, u String WebGLRenderingContext::getProgramInfoLog(WebGLProgram* program, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return String(); if (!validateWebGLObject(program)) return ""; WebGLStateRestorer(this, false); @@ -1545,10 +1687,48 @@ String WebGLRenderingContext::getProgramInfoLog(WebGLProgram* program, Exception WebGLGetInfo WebGLRenderingContext::getRenderbufferParameter(unsigned long target, unsigned long pname, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return WebGLGetInfo(); if (target != GraphicsContext3D::RENDERBUFFER) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); return WebGLGetInfo(); } + if (!m_renderbufferBinding || !m_renderbufferBinding->object()) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + return WebGLGetInfo(); + } + + if (m_renderbufferBinding->getInternalFormat() == GraphicsContext3D::DEPTH_STENCIL + && !m_renderbufferBinding->isValid()) { + ASSERT(!m_isDepthStencilSupported); + long value = 0; + switch (pname) { + case GraphicsContext3D::RENDERBUFFER_WIDTH: + value = static_cast<long>(m_renderbufferBinding->getWidth()); + break; + case GraphicsContext3D::RENDERBUFFER_HEIGHT: + value = static_cast<long>(m_renderbufferBinding->getHeight()); + break; + case GraphicsContext3D::RENDERBUFFER_RED_SIZE: + case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE: + case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE: + case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE: + value = 0; + break; + case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE: + value = 24; + break; + case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE: + value = 8; + break; + case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT: + return WebGLGetInfo(m_renderbufferBinding->getInternalFormat()); + default: + m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); + return WebGLGetInfo(); + } + return WebGLGetInfo(value); + } WebGLStateRestorer(this, false); int value = 0; @@ -1564,10 +1744,6 @@ WebGLGetInfo WebGLRenderingContext::getRenderbufferParameter(unsigned long targe m_context->getRenderbufferParameteriv(target, pname, &value); return WebGLGetInfo(static_cast<long>(value)); case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT: - if (!m_renderbufferBinding) { - m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); - return WebGLGetInfo(); - } return WebGLGetInfo(m_renderbufferBinding->getInternalFormat()); default: m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); @@ -1578,7 +1754,7 @@ WebGLGetInfo WebGLRenderingContext::getRenderbufferParameter(unsigned long targe WebGLGetInfo WebGLRenderingContext::getShaderParameter(WebGLShader* shader, unsigned long pname, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateWebGLObject(shader)) + if (isContextLost() || !validateWebGLObject(shader)) return WebGLGetInfo(); WebGLStateRestorer(this, false); int value = 0; @@ -1603,6 +1779,8 @@ WebGLGetInfo WebGLRenderingContext::getShaderParameter(WebGLShader* shader, unsi String WebGLRenderingContext::getShaderInfoLog(WebGLShader* shader, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return String(); if (!validateWebGLObject(shader)) return ""; WebGLStateRestorer(this, false); @@ -1612,6 +1790,8 @@ String WebGLRenderingContext::getShaderInfoLog(WebGLShader* shader, ExceptionCod String WebGLRenderingContext::getShaderSource(WebGLShader* shader, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return String(); if (!validateWebGLObject(shader)) return ""; WebGLStateRestorer(this, false); @@ -1621,6 +1801,8 @@ String WebGLRenderingContext::getShaderSource(WebGLShader* shader, ExceptionCode WebGLGetInfo WebGLRenderingContext::getTexParameter(unsigned long target, unsigned long pname, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return WebGLGetInfo(); WebGLTexture* tex = validateTextureBinding(target, false); if (!tex) return WebGLGetInfo(); @@ -1642,7 +1824,7 @@ WebGLGetInfo WebGLRenderingContext::getTexParameter(unsigned long target, unsign WebGLGetInfo WebGLRenderingContext::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateWebGLObject(program)) + if (isContextLost() || !validateWebGLObject(program)) return WebGLGetInfo(); if (!uniformLocation) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); @@ -1755,20 +1937,20 @@ WebGLGetInfo WebGLRenderingContext::getUniform(WebGLProgram* program, const WebG return WebGLGetInfo(Float32Array::create(value, length)); } case GraphicsContext3D::INT: { - int value[16] = {0}; + int value[4] = {0}; m_context->getUniformiv(objectOrZero(program), location, value); if (length == 1) return WebGLGetInfo(static_cast<long>(value[0])); return WebGLGetInfo(Int32Array::create(value, length)); } case GraphicsContext3D::BOOL: { - int value[16] = {0}; + int value[4] = {0}; m_context->getUniformiv(objectOrZero(program), location, value); if (length > 1) { - unsigned char boolValue[16] = {0}; + bool boolValue[16] = {0}; for (unsigned j = 0; j < length; j++) boolValue[j] = static_cast<bool>(value[j]); - return WebGLGetInfo(Uint8Array::create(boolValue, length)); + return WebGLGetInfo(boolValue, length); } return WebGLGetInfo(static_cast<bool>(value[0])); } @@ -1786,7 +1968,7 @@ WebGLGetInfo WebGLRenderingContext::getUniform(WebGLProgram* program, const WebG PassRefPtr<WebGLUniformLocation> WebGLRenderingContext::getUniformLocation(WebGLProgram* program, const String& name, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateWebGLObject(program)) + if (isContextLost() || !validateWebGLObject(program)) return 0; WebGLStateRestorer(this, false); long uniformLocation = m_context->getUniformLocation(objectOrZero(program), name); @@ -1798,6 +1980,8 @@ PassRefPtr<WebGLUniformLocation> WebGLRenderingContext::getUniformLocation(WebGL WebGLGetInfo WebGLRenderingContext::getVertexAttrib(unsigned long index, unsigned long pname, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return WebGLGetInfo(); WebGLStateRestorer(this, false); if (index >= m_maxVertexAttribs) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); @@ -1845,6 +2029,8 @@ WebGLGetInfo WebGLRenderingContext::getVertexAttrib(unsigned long index, unsigne long WebGLRenderingContext::getVertexAttribOffset(unsigned long index, unsigned long pname) { + if (isContextLost()) + return 0; long result = m_context->getVertexAttribOffset(index, pname); cleanupAfterGraphicsCall(false); return result; @@ -1852,6 +2038,8 @@ long WebGLRenderingContext::getVertexAttribOffset(unsigned long index, unsigned void WebGLRenderingContext::hint(unsigned long target, unsigned long mode) { + if (isContextLost()) + return; if (target != GraphicsContext3D::GENERATE_MIPMAP_HINT) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); return; @@ -1862,22 +2050,27 @@ void WebGLRenderingContext::hint(unsigned long target, unsigned long mode) bool WebGLRenderingContext::isBuffer(WebGLBuffer* buffer) { - if (!buffer) + if (!buffer || isContextLost()) return false; return m_context->isBuffer(buffer->object()); } +bool WebGLRenderingContext::isContextLost() const +{ + return m_contextLost; +} + bool WebGLRenderingContext::isEnabled(unsigned long cap) { - if (!validateCapability(cap)) + if (!validateCapability(cap) || isContextLost()) return false; return m_context->isEnabled(cap); } bool WebGLRenderingContext::isFramebuffer(WebGLFramebuffer* framebuffer) { - if (!framebuffer) + if (!framebuffer || isContextLost()) return false; return m_context->isFramebuffer(framebuffer->object()); @@ -1885,7 +2078,7 @@ bool WebGLRenderingContext::isFramebuffer(WebGLFramebuffer* framebuffer) bool WebGLRenderingContext::isProgram(WebGLProgram* program) { - if (!program) + if (!program || isContextLost()) return false; return m_context->isProgram(program->object()); @@ -1893,7 +2086,7 @@ bool WebGLRenderingContext::isProgram(WebGLProgram* program) bool WebGLRenderingContext::isRenderbuffer(WebGLRenderbuffer* renderbuffer) { - if (!renderbuffer) + if (!renderbuffer || isContextLost()) return false; return m_context->isRenderbuffer(renderbuffer->object()); @@ -1901,7 +2094,7 @@ bool WebGLRenderingContext::isRenderbuffer(WebGLRenderbuffer* renderbuffer) bool WebGLRenderingContext::isShader(WebGLShader* shader) { - if (!shader) + if (!shader || isContextLost()) return false; return m_context->isShader(shader->object()); @@ -1909,7 +2102,7 @@ bool WebGLRenderingContext::isShader(WebGLShader* shader) bool WebGLRenderingContext::isTexture(WebGLTexture* texture) { - if (!texture) + if (!texture || isContextLost()) return false; return m_context->isTexture(texture->object()); @@ -1917,6 +2110,8 @@ bool WebGLRenderingContext::isTexture(WebGLTexture* texture) void WebGLRenderingContext::lineWidth(double width) { + if (isContextLost()) + return; m_context->lineWidth((float) width); cleanupAfterGraphicsCall(false); } @@ -1924,7 +2119,7 @@ void WebGLRenderingContext::lineWidth(double width) void WebGLRenderingContext::linkProgram(WebGLProgram* program, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateWebGLObject(program)) + if (isContextLost() || !validateWebGLObject(program)) return; if (!isGLES2Compliant()) { if (!program->getAttachedShader(GraphicsContext3D::VERTEX_SHADER) || !program->getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER)) { @@ -1944,6 +2139,8 @@ void WebGLRenderingContext::linkProgram(WebGLProgram* program, ExceptionCode& ec void WebGLRenderingContext::pixelStorei(unsigned long pname, long param) { + if (isContextLost()) + return; switch (pname) { case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL: m_unpackFlipY = param; @@ -1970,12 +2167,16 @@ void WebGLRenderingContext::pixelStorei(unsigned long pname, long param) void WebGLRenderingContext::polygonOffset(double factor, double units) { + if (isContextLost()) + return; m_context->polygonOffset((float) factor, (float) units); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::readPixels(long x, long y, long width, long height, unsigned long format, unsigned long type, ArrayBufferView* pixels, ExceptionCode& ec) { + if (isContextLost()) + return; if (!canvas()->originClean()) { ec = SECURITY_ERR; return; @@ -1994,7 +2195,7 @@ void WebGLRenderingContext::readPixels(long x, long y, long width, long height, m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); return; } - if (!((format == GraphicsContext3D::RGBA && type == GraphicsContext3D::UNSIGNED_BYTE) || (format == m_implementationColorReadFormat && type == m_implementationColorReadType))) { + if (format != GraphicsContext3D::RGBA || type != GraphicsContext3D::UNSIGNED_BYTE) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -2004,6 +2205,10 @@ void WebGLRenderingContext::readPixels(long x, long y, long width, long height, m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } + if (m_framebufferBinding && !m_framebufferBinding->onAccess()) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION); + return; + } // Calculate array size, taking into consideration of PACK_ALIGNMENT. unsigned long bytesPerRow = componentsPerPixel * bytesPerComponent * width; unsigned long padding = 0; @@ -2043,27 +2248,44 @@ void WebGLRenderingContext::readPixels(long x, long y, long width, long height, void WebGLRenderingContext::releaseShaderCompiler() { + if (isContextLost()) + return; m_context->releaseShaderCompiler(); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::renderbufferStorage(unsigned long target, unsigned long internalformat, unsigned long width, unsigned long height) { + if (isContextLost()) + return; + if (target != GraphicsContext3D::RENDERBUFFER) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); + return; + } + if (!m_renderbufferBinding || !m_renderbufferBinding->object()) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + return; + } switch (internalformat) { case GraphicsContext3D::DEPTH_COMPONENT16: case GraphicsContext3D::RGBA4: case GraphicsContext3D::RGB5_A1: case GraphicsContext3D::RGB565: case GraphicsContext3D::STENCIL_INDEX8: - case GraphicsContext3D::DEPTH_STENCIL: m_context->renderbufferStorage(target, internalformat, width, height); - if (m_renderbufferBinding) { - m_renderbufferBinding->setInternalFormat(internalformat); - if (m_framebufferBinding) - m_framebufferBinding->onAttachedObjectChange(m_renderbufferBinding.get()); - } + m_renderbufferBinding->setInternalFormat(internalformat); + m_renderbufferBinding->setIsValid(true); cleanupAfterGraphicsCall(false); break; + case GraphicsContext3D::DEPTH_STENCIL: + if (m_isDepthStencilSupported) { + m_context->renderbufferStorage(target, Extensions3D::DEPTH24_STENCIL8, width, height); + cleanupAfterGraphicsCall(false); + } else + m_renderbufferBinding->setSize(width, height); + m_renderbufferBinding->setIsValid(m_isDepthStencilSupported); + m_renderbufferBinding->setInternalFormat(internalformat); + break; default: m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); } @@ -2071,12 +2293,16 @@ void WebGLRenderingContext::renderbufferStorage(unsigned long target, unsigned l void WebGLRenderingContext::sampleCoverage(double value, bool invert) { + if (isContextLost()) + return; m_context->sampleCoverage((float) value, invert); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::scissor(long x, long y, unsigned long width, unsigned long height) { + if (isContextLost()) + return; m_context->scissor(x, y, width, height); cleanupAfterGraphicsCall(false); } @@ -2084,7 +2310,7 @@ void WebGLRenderingContext::scissor(long x, long y, unsigned long width, unsigne void WebGLRenderingContext::shaderSource(WebGLShader* shader, const String& string, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateWebGLObject(shader)) + if (isContextLost() || !validateWebGLObject(shader)) return; m_context->shaderSource(objectOrZero(shader), string); cleanupAfterGraphicsCall(false); @@ -2092,36 +2318,72 @@ void WebGLRenderingContext::shaderSource(WebGLShader* shader, const String& stri void WebGLRenderingContext::stencilFunc(unsigned long func, long ref, unsigned long mask) { + if (isContextLost()) + return; + if (!validateStencilFunc(func)) + return; + m_stencilFuncRef = ref; + m_stencilFuncMask = mask; m_context->stencilFunc(func, ref, mask); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::stencilFuncSeparate(unsigned long face, unsigned long func, long ref, unsigned long mask) { + if (isContextLost()) + return; + if (!validateFace(face) || !validateStencilFunc(func)) + return; + if (face == GraphicsContext3D::FRONT_AND_BACK) { + m_stencilFuncRef = ref; + m_stencilFuncMask = mask; + } else if (m_stencilFuncRef != ref || m_stencilFuncMask != mask) { + // for ref value, we generate an error if user specify a different value + // for front/back faces even if they clamp to the same value internally. + m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + return; + } m_context->stencilFuncSeparate(face, func, ref, mask); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::stencilMask(unsigned long mask) { + if (isContextLost()) + return; + m_stencilMask = mask; m_context->stencilMask(mask); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::stencilMaskSeparate(unsigned long face, unsigned long mask) { + if (isContextLost()) + return; + if (!validateFace(face)) + return; + if (face == GraphicsContext3D::FRONT_AND_BACK) + m_stencilMask = mask; + else if (m_stencilMask != mask) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + return; + } m_context->stencilMaskSeparate(face, mask); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::stencilOp(unsigned long fail, unsigned long zfail, unsigned long zpass) { + if (isContextLost()) + return; m_context->stencilOp(fail, zfail, zpass); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::stencilOpSeparate(unsigned long face, unsigned long fail, unsigned long zfail, unsigned long zpass) { + if (isContextLost()) + return; m_context->stencilOpSeparate(face, fail, zfail, zpass); cleanupAfterGraphicsCall(false); } @@ -2146,8 +2408,6 @@ void WebGLRenderingContext::texImage2DBase(unsigned target, unsigned level, unsi m_context->texImage2D(target, level, internalformat, width, height, border, format, type, pixels); tex->setLevelInfo(target, level, internalformat, width, height, type); - if (m_framebufferBinding) - m_framebufferBinding->onAttachedObjectChange(tex); cleanupAfterGraphicsCall(false); } @@ -2173,7 +2433,7 @@ void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, unsigned unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, ArrayBufferView* pixels, ExceptionCode& ec) { - if (!validateTexFuncData(width, height, format, type, pixels)) + if (isContextLost() || !validateTexFuncData(width, height, format, type, pixels)) return; void* data = pixels ? pixels->baseAddress() : 0; Vector<uint8_t> tempData; @@ -2200,6 +2460,8 @@ void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, unsigned unsigned format, unsigned type, ImageData* pixels, ExceptionCode& ec) { ec = 0; + if (isContextLost()) + return; Vector<uint8_t> data; if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); @@ -2217,6 +2479,8 @@ void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, unsigned unsigned format, unsigned type, HTMLImageElement* image, ExceptionCode& ec) { ec = 0; + if (isContextLost()) + return; if (!image || !image->cachedImage()) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); return; @@ -2230,6 +2494,8 @@ void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, unsigned unsigned format, unsigned type, HTMLCanvasElement* canvas, ExceptionCode& ec) { ec = 0; + if (isContextLost()) + return; if (!canvas || !canvas->buffer()) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); return; @@ -2262,6 +2528,8 @@ void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, unsigned unsigned format, unsigned type, HTMLVideoElement* video, ExceptionCode& ec) { ec = 0; + if (isContextLost()) + return; RefPtr<Image> image = videoFrameToImage(video); if (!video) return; @@ -2270,6 +2538,8 @@ void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, unsigned void WebGLRenderingContext::texParameter(unsigned long target, unsigned long pname, float paramf, int parami, bool isFloat) { + if (isContextLost()) + return; WebGLTexture* tex = validateTextureBinding(target, false); if (!tex) return; @@ -2315,6 +2585,8 @@ void WebGLRenderingContext::texSubImage2DBase(unsigned target, unsigned level, u { // FIXME: For now we ignore any errors returned ec = 0; + if (isContextLost()) + return; if (!validateTexFuncFormatAndType(format, type)) return; if (!validateTextureBinding(target, true)) @@ -2328,6 +2600,8 @@ void WebGLRenderingContext::texSubImage2DImpl(unsigned target, unsigned level, u Image* image, bool flipY, bool premultiplyAlpha, ExceptionCode& ec) { ec = 0; + if (isContextLost()) + return; Vector<uint8_t> data; if (!m_context->extractImageData(image, format, type, flipY, premultiplyAlpha, data)) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); @@ -2341,7 +2615,7 @@ void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsig unsigned width, unsigned height, unsigned format, unsigned type, ArrayBufferView* pixels, ExceptionCode& ec) { - if (!validateTexFuncData(width, height, format, type, pixels)) + if (isContextLost() || !validateTexFuncData(width, height, format, type, pixels)) return; void* data = pixels ? pixels->baseAddress() : 0; Vector<uint8_t> tempData; @@ -2367,6 +2641,8 @@ void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsig unsigned format, unsigned type, ImageData* pixels, ExceptionCode& ec) { ec = 0; + if (isContextLost()) + return; Vector<uint8_t> data; if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); @@ -2380,6 +2656,8 @@ void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsig unsigned format, unsigned type, HTMLImageElement* image, ExceptionCode& ec) { ec = 0; + if (isContextLost()) + return; if (!image || !image->cachedImage()) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); return; @@ -2393,6 +2671,8 @@ void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsig unsigned format, unsigned type, HTMLCanvasElement* canvas, ExceptionCode& ec) { ec = 0; + if (isContextLost()) + return; if (!canvas || !canvas->buffer()) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); return; @@ -2406,6 +2686,8 @@ void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsig unsigned format, unsigned type, HTMLVideoElement* video, ExceptionCode& ec) { ec = 0; + if (isContextLost()) + return; RefPtr<Image> image = videoFrameToImage(video); if (!video) return; @@ -2415,7 +2697,7 @@ void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsig void WebGLRenderingContext::uniform1f(const WebGLUniformLocation* location, float x, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location) + if (isContextLost() || !location) return; if (location->program() != m_currentProgram) { @@ -2430,7 +2712,7 @@ void WebGLRenderingContext::uniform1f(const WebGLUniformLocation* location, floa void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformParameters(location, v, 1)) + if (isContextLost() || !validateUniformParameters(location, v, 1)) return; m_context->uniform1fv(location->location(), v->data(), v->length()); @@ -2440,7 +2722,7 @@ void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, Flo void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, float* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformParameters(location, v, size, 1)) + if (isContextLost() || !validateUniformParameters(location, v, size, 1)) return; m_context->uniform1fv(location->location(), v, size); @@ -2450,7 +2732,7 @@ void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, flo void WebGLRenderingContext::uniform1i(const WebGLUniformLocation* location, int x, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location) + if (isContextLost() || !location) return; if (location->program() != m_currentProgram) { @@ -2465,7 +2747,7 @@ void WebGLRenderingContext::uniform1i(const WebGLUniformLocation* location, int void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformParameters(location, v, 1)) + if (isContextLost() || !validateUniformParameters(location, v, 1)) return; m_context->uniform1iv(location->location(), v->data(), v->length()); @@ -2475,7 +2757,7 @@ void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, Int void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, int* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformParameters(location, v, size, 1)) + if (isContextLost() || !validateUniformParameters(location, v, size, 1)) return; m_context->uniform1iv(location->location(), v, size); @@ -2485,7 +2767,7 @@ void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, int void WebGLRenderingContext::uniform2f(const WebGLUniformLocation* location, float x, float y, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location) + if (isContextLost() || !location) return; if (location->program() != m_currentProgram) { @@ -2500,7 +2782,7 @@ void WebGLRenderingContext::uniform2f(const WebGLUniformLocation* location, floa void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformParameters(location, v, 2)) + if (isContextLost() || !validateUniformParameters(location, v, 2)) return; m_context->uniform2fv(location->location(), v->data(), v->length() / 2); @@ -2510,7 +2792,7 @@ void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, Flo void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, float* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformParameters(location, v, size, 2)) + if (isContextLost() || !validateUniformParameters(location, v, size, 2)) return; m_context->uniform2fv(location->location(), v, size / 2); @@ -2520,7 +2802,7 @@ void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, flo void WebGLRenderingContext::uniform2i(const WebGLUniformLocation* location, int x, int y, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location) + if (isContextLost() || !location) return; if (location->program() != m_currentProgram) { @@ -2535,7 +2817,7 @@ void WebGLRenderingContext::uniform2i(const WebGLUniformLocation* location, int void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformParameters(location, v, 2)) + if (isContextLost() || !validateUniformParameters(location, v, 2)) return; m_context->uniform2iv(location->location(), v->data(), v->length() / 2); @@ -2545,7 +2827,7 @@ void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, Int void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, int* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformParameters(location, v, size, 2)) + if (isContextLost() || !validateUniformParameters(location, v, size, 2)) return; m_context->uniform2iv(location->location(), v, size / 2); @@ -2555,7 +2837,7 @@ void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, int void WebGLRenderingContext::uniform3f(const WebGLUniformLocation* location, float x, float y, float z, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location) + if (isContextLost() || !location) return; if (location->program() != m_currentProgram) { @@ -2570,7 +2852,7 @@ void WebGLRenderingContext::uniform3f(const WebGLUniformLocation* location, floa void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformParameters(location, v, 3)) + if (isContextLost() || !validateUniformParameters(location, v, 3)) return; m_context->uniform3fv(location->location(), v->data(), v->length() / 3); @@ -2580,7 +2862,7 @@ void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, Flo void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, float* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformParameters(location, v, size, 3)) + if (isContextLost() || !validateUniformParameters(location, v, size, 3)) return; m_context->uniform3fv(location->location(), v, size / 3); @@ -2590,7 +2872,7 @@ void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, flo void WebGLRenderingContext::uniform3i(const WebGLUniformLocation* location, int x, int y, int z, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location) + if (isContextLost() || !location) return; if (location->program() != m_currentProgram) { @@ -2605,7 +2887,7 @@ void WebGLRenderingContext::uniform3i(const WebGLUniformLocation* location, int void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformParameters(location, v, 3)) + if (isContextLost() || !validateUniformParameters(location, v, 3)) return; m_context->uniform3iv(location->location(), v->data(), v->length() / 3); @@ -2615,7 +2897,7 @@ void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, Int void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, int* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformParameters(location, v, size, 3)) + if (isContextLost() || !validateUniformParameters(location, v, size, 3)) return; m_context->uniform3iv(location->location(), v, size / 3); @@ -2625,7 +2907,7 @@ void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, int void WebGLRenderingContext::uniform4f(const WebGLUniformLocation* location, float x, float y, float z, float w, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location) + if (isContextLost() || !location) return; if (location->program() != m_currentProgram) { @@ -2640,7 +2922,7 @@ void WebGLRenderingContext::uniform4f(const WebGLUniformLocation* location, floa void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformParameters(location, v, 4)) + if (isContextLost() || !validateUniformParameters(location, v, 4)) return; m_context->uniform4fv(location->location(), v->data(), v->length() / 4); @@ -2650,7 +2932,7 @@ void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, Flo void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, float* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformParameters(location, v, size, 4)) + if (isContextLost() || !validateUniformParameters(location, v, size, 4)) return; m_context->uniform4fv(location->location(), v, size / 4); @@ -2660,7 +2942,7 @@ void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, flo void WebGLRenderingContext::uniform4i(const WebGLUniformLocation* location, int x, int y, int z, int w, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location) + if (isContextLost() || !location) return; if (location->program() != m_currentProgram) { @@ -2675,7 +2957,7 @@ void WebGLRenderingContext::uniform4i(const WebGLUniformLocation* location, int void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformParameters(location, v, 4)) + if (isContextLost() || !validateUniformParameters(location, v, 4)) return; m_context->uniform4iv(location->location(), v->data(), v->length() / 4); @@ -2685,7 +2967,7 @@ void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, Int void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, int* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformParameters(location, v, size, 4)) + if (isContextLost() || !validateUniformParameters(location, v, size, 4)) return; m_context->uniform4iv(location->location(), v, size / 4); @@ -2695,7 +2977,7 @@ void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, int void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, bool transpose, Float32Array* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformMatrixParameters(location, transpose, v, 4)) + if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 4)) return; m_context->uniformMatrix2fv(location->location(), transpose, v->data(), v->length() / 4); cleanupAfterGraphicsCall(false); @@ -2704,7 +2986,7 @@ void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* locatio void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, bool transpose, float* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformMatrixParameters(location, transpose, v, size, 4)) + if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 4)) return; m_context->uniformMatrix2fv(location->location(), transpose, v, size / 4); cleanupAfterGraphicsCall(false); @@ -2713,7 +2995,7 @@ void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* locatio void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, bool transpose, Float32Array* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformMatrixParameters(location, transpose, v, 9)) + if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 9)) return; m_context->uniformMatrix3fv(location->location(), transpose, v->data(), v->length() / 9); cleanupAfterGraphicsCall(false); @@ -2722,7 +3004,7 @@ void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* locatio void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, bool transpose, float* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformMatrixParameters(location, transpose, v, size, 9)) + if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 9)) return; m_context->uniformMatrix3fv(location->location(), transpose, v, size / 9); cleanupAfterGraphicsCall(false); @@ -2731,7 +3013,7 @@ void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* locatio void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, bool transpose, Float32Array* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformMatrixParameters(location, transpose, v, 16)) + if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 16)) return; m_context->uniformMatrix4fv(location->location(), transpose, v->data(), v->length() / 16); cleanupAfterGraphicsCall(false); @@ -2740,7 +3022,7 @@ void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* locatio void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, bool transpose, float* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateUniformMatrixParameters(location, transpose, v, size, 16)) + if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 16)) return; m_context->uniformMatrix4fv(location->location(), transpose, v, size / 16); cleanupAfterGraphicsCall(false); @@ -2749,6 +3031,8 @@ void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* locatio void WebGLRenderingContext::useProgram(WebGLProgram* program, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return; if (program && program->context() != this) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; @@ -2772,7 +3056,7 @@ void WebGLRenderingContext::useProgram(WebGLProgram* program, ExceptionCode& ec) void WebGLRenderingContext::validateProgram(WebGLProgram* program, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!validateWebGLObject(program)) + if (isContextLost() || !validateWebGLObject(program)) return; m_context->validateProgram(objectOrZero(program)); cleanupAfterGraphicsCall(false); @@ -2841,11 +3125,13 @@ void WebGLRenderingContext::vertexAttrib4fv(unsigned long index, float* v, int s void WebGLRenderingContext::vertexAttribPointer(unsigned long index, long size, unsigned long type, bool normalized, long stride, long offset, ExceptionCode& ec) { UNUSED_PARAM(ec); + if (isContextLost()) + return; if (index >= m_maxVertexAttribs) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); return; } - if (size < 1 || size > 4 || stride < 0 || offset < 0) { + if (size < 1 || size > 4 || stride < 0 || stride > 255 || offset < 0) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); return; } @@ -2885,6 +3171,8 @@ void WebGLRenderingContext::vertexAttribPointer(unsigned long index, long size, void WebGLRenderingContext::viewport(long x, long y, unsigned long width, unsigned long height) { + if (isContextLost()) + return; if (isnan(x)) x = 0; if (isnan(y)) @@ -2897,6 +3185,44 @@ void WebGLRenderingContext::viewport(long x, long y, unsigned long width, unsign cleanupAfterGraphicsCall(false); } +void WebGLRenderingContext::loseContext() +{ + if (isContextLost()) + return; + + m_contextLost = true; + + detachAndRemoveAllObjects(); + + // There is no direct way to clear errors from a GL implementation and + // looping until getError() becomes NO_ERROR might cause an infinite loop if + // the driver or context implementation had a bug. So, loop a reasonably + // large number of times to clear any existing errors. + for (int i = 0; i < 100; ++i) { + if (m_context->getError() == GraphicsContext3D::NO_ERROR) + break; + } + m_context->synthesizeGLError(GraphicsContext3D::CONTEXT_LOST_WEBGL); + + canvas()->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextlostEvent, false, true, "")); +} + +void WebGLRenderingContext::restoreContext() +{ + if (!isContextLost()) + return; + + // The rendering context is not restored if there is no handler for + // the context restored event. + if (!canvas()->hasEventListeners(eventNames().webglcontextrestoredEvent)) + return; + + m_contextLost = false; + initializeNewContext(); + + canvas()->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextrestoredEvent, false, true, "")); +} + void WebGLRenderingContext::removeObject(WebGLObject* object) { m_canvasObjects.remove(object); @@ -2904,6 +3230,7 @@ void WebGLRenderingContext::removeObject(WebGLObject* object) void WebGLRenderingContext::addObject(WebGLObject* object) { + ASSERT(!isContextLost()); removeObject(object); m_canvasObjects.add(object); } @@ -3355,6 +3682,37 @@ bool WebGLRenderingContext::validateDrawMode(unsigned long mode) } } +bool WebGLRenderingContext::validateFace(unsigned long face) +{ + switch (face) { + case GraphicsContext3D::FRONT: + case GraphicsContext3D::BACK: + case GraphicsContext3D::FRONT_AND_BACK: + return true; + default: + m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); + return false; + } +} + +bool WebGLRenderingContext::validateStencilFunc(unsigned long func) +{ + switch (func) { + case GraphicsContext3D::NEVER: + case GraphicsContext3D::LESS: + case GraphicsContext3D::LEQUAL: + case GraphicsContext3D::GREATER: + case GraphicsContext3D::GEQUAL: + case GraphicsContext3D::EQUAL: + case GraphicsContext3D::NOTEQUAL: + case GraphicsContext3D::ALWAYS: + return true; + default: + m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); + return false; + } +} + void WebGLRenderingContext::printWarningToConsole(const String& message) { canvas()->document()->frame()->domWindow()->console()->addMessage(HTMLMessageSource, LogMessageType, WarningMessageLevel, @@ -3393,6 +3751,18 @@ bool WebGLRenderingContext::validateBlendEquation(unsigned long mode) } } +bool WebGLRenderingContext::validateBlendFuncFactors(unsigned long src, unsigned long dst) +{ + if (((src == GraphicsContext3D::CONSTANT_COLOR || src == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR) + && (dst == GraphicsContext3D::CONSTANT_ALPHA || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA)) + || ((dst == GraphicsContext3D::CONSTANT_COLOR || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR) + && (src == GraphicsContext3D::CONSTANT_ALPHA || src == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA))) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + return false; + } + return true; +} + bool WebGLRenderingContext::validateCapability(unsigned long cap) { switch (cap) { @@ -3497,6 +3867,8 @@ WebGLBuffer* WebGLRenderingContext::validateBufferDataParameters(unsigned long t void WebGLRenderingContext::vertexAttribfImpl(unsigned long index, int expectedSize, float v0, float v1, float v2, float v3) { + if (isContextLost()) + return; if (index >= m_maxVertexAttribs) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); return; @@ -3529,6 +3901,8 @@ void WebGLRenderingContext::vertexAttribfImpl(unsigned long index, int expectedS void WebGLRenderingContext::vertexAttribfvImpl(unsigned long index, Float32Array* v, int expectedSize) { + if (isContextLost()) + return; if (!v) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); return; @@ -3538,6 +3912,8 @@ void WebGLRenderingContext::vertexAttribfvImpl(unsigned long index, Float32Array void WebGLRenderingContext::vertexAttribfvImpl(unsigned long index, float* v, int size, int expectedSize) { + if (isContextLost()) + return; if (!v) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); return; diff --git a/WebCore/html/canvas/WebGLRenderingContext.h b/WebCore/html/canvas/WebGLRenderingContext.h index ce66f6a..5f66248 100644 --- a/WebCore/html/canvas/WebGLRenderingContext.h +++ b/WebCore/html/canvas/WebGLRenderingContext.h @@ -176,6 +176,7 @@ public: void hint(unsigned long target, unsigned long mode); bool isBuffer(WebGLBuffer*); + bool isContextLost() const; bool isEnabled(unsigned long cap); bool isFramebuffer(WebGLFramebuffer*); bool isProgram(WebGLProgram*); @@ -277,6 +278,9 @@ public: void viewport(long x, long y, unsigned long width, unsigned long height); + void loseContext(); + void restoreContext(); + GraphicsContext3D* graphicsContext3D() const { return m_context.get(); } #if USE(ACCELERATED_COMPOSITING) virtual PlatformLayer* platformLayer() const { return m_context->platformLayer(); } @@ -292,6 +296,7 @@ public: friend class WebGLObject; WebGLRenderingContext(HTMLCanvasElement*, PassRefPtr<GraphicsContext3D>); + void initializeNewContext(); void addObject(WebGLObject*); void detachAndRemoveAllObjects(); @@ -333,8 +338,6 @@ public: RefPtr<GraphicsContext3D> m_context; bool m_needsUpdate; bool m_markedCanvasDirty; - // FIXME: I think this is broken -- it does not increment any - // reference counts, so may refer to destroyed objects. HashSet<RefPtr<WebGLObject> > m_canvasObjects; // List of bound VBO's. Used to maintain info about sizes for ARRAY_BUFFER and stored values for ELEMENT_ARRAY_BUFFER @@ -417,10 +420,16 @@ public: int m_packAlignment; int m_unpackAlignment; - unsigned long m_implementationColorReadFormat; - unsigned long m_implementationColorReadType; bool m_unpackFlipY; bool m_unpackPremultiplyAlpha; + bool m_contextLost; + + long m_stencilBits; + unsigned long m_stencilMask; + long m_stencilFuncRef; // Note that this is the user specified value, not the internal clamped value. + unsigned long m_stencilFuncMask; + + bool m_isDepthStencilSupported; // Helpers for getParameter and others WebGLGetInfo getBooleanParameter(unsigned long pname); @@ -481,6 +490,12 @@ public: // Helper function to validate mode for draw{Arrays/Elements}. bool validateDrawMode(unsigned long); + // Helper function to validate face. + bool validateFace(unsigned long); + + // Helper function to validate stencil func. + bool validateStencilFunc(unsigned long); + // Helper function for texParameterf and texParameteri. void texParameter(unsigned long target, unsigned long pname, float parami, int paramf, bool isFloat); @@ -495,6 +510,9 @@ public: // Helper function to validate blend equation mode. bool validateBlendEquation(unsigned long); + // Helper function to validate blend func factors. + bool validateBlendFuncFactors(unsigned long src, unsigned long dst); + // Helper function to validate a GL capability. bool validateCapability(unsigned long); diff --git a/WebCore/html/canvas/WebGLRenderingContext.idl b/WebCore/html/canvas/WebGLRenderingContext.idl index f76646d..4d41b78 100644 --- a/WebCore/html/canvas/WebGLRenderingContext.idl +++ b/WebCore/html/canvas/WebGLRenderingContext.idl @@ -392,10 +392,6 @@ module html { const unsigned int VERTEX_ATTRIB_ARRAY_POINTER = 0x8645; const unsigned int VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F; - /* Read Format */ - const unsigned int IMPLEMENTATION_COLOR_READ_TYPE = 0x8B9A; - const unsigned int IMPLEMENTATION_COLOR_READ_FORMAT = 0x8B9B; - /* Shader Source */ const unsigned int COMPILE_STATUS = 0x8B81; const unsigned int INFO_LOG_LENGTH = 0x8B84; @@ -463,6 +459,7 @@ module html { /* WebGL-specific enums */ const unsigned int UNPACK_FLIP_Y_WEBGL = 0x9240; const unsigned int UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241; + const unsigned int CONTEXT_LOST_WEBGL = 0x9242; [StrictTypeChecking] void activeTexture(in unsigned long texture) raises(DOMException); [StrictTypeChecking] void attachShader(in WebGLProgram program, in WebGLShader shader) raises(DOMException); @@ -551,18 +548,18 @@ module html { [StrictTypeChecking, Custom] void getParameter(); // any getProgramParameter(in WebGLProgram program, in unsigned long pname) raises(DOMException); [StrictTypeChecking, Custom] void getProgramParameter(); - [StrictTypeChecking] DOMString getProgramInfoLog(in WebGLProgram program) raises(DOMException); + [StrictTypeChecking, ConvertNullStringTo=Null] DOMString getProgramInfoLog(in WebGLProgram program) raises(DOMException); // any getRenderbufferParameter(in unsigned long target, in unsigned long pname) raises(DOMException); [StrictTypeChecking, Custom] void getRenderbufferParameter(); // any getShaderParameter(in WebGLShader shader, in unsigned long pname) raises(DOMException); [StrictTypeChecking, Custom] void getShaderParameter() raises(DOMException); - [StrictTypeChecking] DOMString getShaderInfoLog(in WebGLShader shader) raises(DOMException); + [StrictTypeChecking, ConvertNullStringTo=Null] DOMString getShaderInfoLog(in WebGLShader shader) raises(DOMException); // TBD // void glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); - [StrictTypeChecking] DOMString getShaderSource(in WebGLShader shader) raises(DOMException); + [StrictTypeChecking, ConvertNullStringTo=Null] DOMString getShaderSource(in WebGLShader shader) raises(DOMException); // any getTexParameter(in unsigned long target, in unsigned long pname) raises(DOMException); [StrictTypeChecking, Custom] void getTexParameter(); @@ -579,6 +576,7 @@ module html { [StrictTypeChecking] void hint(in unsigned long target, in unsigned long mode); [StrictTypeChecking] boolean isBuffer(in WebGLBuffer buffer); + [StrictTypeChecking] boolean isContextLost(); [StrictTypeChecking] boolean isEnabled(in unsigned long cap); [StrictTypeChecking] boolean isFramebuffer(in WebGLFramebuffer framebuffer); [StrictTypeChecking] boolean isProgram(in WebGLProgram program); diff --git a/WebCore/html/parser/HTMLTreeBuilder.cpp b/WebCore/html/parser/HTMLTreeBuilder.cpp index 310ff60..6134607 100644 --- a/WebCore/html/parser/HTMLTreeBuilder.cpp +++ b/WebCore/html/parser/HTMLTreeBuilder.cpp @@ -2295,7 +2295,8 @@ void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token) while (1) { if (nodeRecord->element()->hasLocalName(token.name())) { m_tree.openElements()->popUntilPopped(nodeRecord->element()); - break; + resetForeignInsertionMode(); + return; } nodeRecord = nodeRecord->next(); if (nodeRecord->element()->namespaceURI() == xhtmlNamespaceURI) @@ -2580,7 +2581,7 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken& token) case AfterBodyMode: case AfterAfterBodyMode: ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode); - return; + break; case InHeadNoscriptMode: ASSERT(insertionMode() == InHeadNoscriptMode); defaultForInHeadNoscript(); @@ -2602,11 +2603,11 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken& token) case InColumnGroupMode: if (m_tree.currentElement() == m_tree.openElements()->htmlElement()) { ASSERT(isParsingFragment()); - return; + return; // FIXME: Should we break here instead of returning? } if (!processColgroupEndTagForInColumnGroup()) { ASSERT(isParsingFragment()); - return; + return; // FIXME: Should we break here instead of returning? } prepareToReprocessToken(); processEndOfFile(token); |