diff options
Diffstat (limited to 'WebCore/html')
139 files changed, 2145 insertions, 1171 deletions
diff --git a/WebCore/html/BaseDateAndTimeInputType.cpp b/WebCore/html/BaseDateAndTimeInputType.cpp new file mode 100644 index 0000000..e1126d4 --- /dev/null +++ b/WebCore/html/BaseDateAndTimeInputType.cpp @@ -0,0 +1,148 @@ +/* + * 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 "BaseDateAndTimeInputType.h" + +#include "DateComponents.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" +#include <limits> +#include <wtf/MathExtras.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +using namespace HTMLNames; +using namespace std; + +static const double msecPerMinute = 60 * 1000; +static const double msecPerSecond = 1000; + +double BaseDateAndTimeInputType::valueAsDate() const +{ + return parseToDouble(element()->value(), DateComponents::invalidMilliseconds()); +} + +void BaseDateAndTimeInputType::setValueAsDate(double value, ExceptionCode&) const +{ + element()->setValue(serialize(value)); +} + +double BaseDateAndTimeInputType::valueAsNumber() const +{ + return parseToDouble(element()->value(), numeric_limits<double>::quiet_NaN()); +} + +void BaseDateAndTimeInputType::setValueAsNumber(double newValue, ExceptionCode&) const +{ + element()->setValue(serialize(newValue)); +} + +bool BaseDateAndTimeInputType::typeMismatchFor(const String& value) const +{ + return !value.isEmpty() && !parseToDateComponents(value, 0); +} + +bool BaseDateAndTimeInputType::typeMismatch() const +{ + return typeMismatchFor(element()->value()); +} + +bool BaseDateAndTimeInputType::rangeUnderflow(const String& value) const +{ + const double nan = numeric_limits<double>::quiet_NaN(); + double doubleValue = parseToDouble(value, nan); + return isfinite(doubleValue) && doubleValue < minimum(); +} + +bool BaseDateAndTimeInputType::rangeOverflow(const String& value) const +{ + const double nan = numeric_limits<double>::quiet_NaN(); + double doubleValue = parseToDouble(value, nan); + return isfinite(doubleValue) && doubleValue > maximum(); +} + +bool BaseDateAndTimeInputType::stepMismatch(const String& value, double step) const +{ + const double nan = numeric_limits<double>::quiet_NaN(); + double doubleValue = parseToDouble(value, nan); + doubleValue = fabs(doubleValue - stepBase()); + if (!isfinite(doubleValue)) + return false; + ASSERT(round(doubleValue) == doubleValue); + ASSERT(round(step) == step); + return fmod(doubleValue, step); +} + +double BaseDateAndTimeInputType::stepBase() const +{ + return parseToDouble(element()->fastGetAttribute(minAttr), defaultStepBase()); +} + +double BaseDateAndTimeInputType::parseToDouble(const String& src, double defaultValue) const +{ + DateComponents date; + if (!parseToDateComponents(src, &date)) + return defaultValue; + double msec = date.millisecondsSinceEpoch(); + ASSERT(isfinite(msec)); + return msec; +} + +bool BaseDateAndTimeInputType::parseToDateComponents(const String& source, DateComponents* out) const +{ + if (source.isEmpty()) + return false; + DateComponents ignoredResult; + if (!out) + out = &ignoredResult; + return parseToDateComponentsInternal(source.characters(), source.length(), out); +} + +String BaseDateAndTimeInputType::serialize(double value) const +{ + if (!isfinite(value)) + return String(); + DateComponents date; + if (!setMillisecondToDateComponents(value, &date)) + return String(); + double step; + if (!element()->getAllowedValueStep(&step)) + return date.toString(); + if (!fmod(step, msecPerMinute)) + return date.toString(DateComponents::None); + if (!fmod(step, msecPerSecond)) + return date.toString(DateComponents::Second); + return date.toString(DateComponents::Millisecond); +} + +} // namespace WebCore diff --git a/WebCore/html/BaseDateAndTimeInputType.h b/WebCore/html/BaseDateAndTimeInputType.h new file mode 100644 index 0000000..83c1e93 --- /dev/null +++ b/WebCore/html/BaseDateAndTimeInputType.h @@ -0,0 +1,65 @@ +/* + * 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 BaseDateAndTimeInputType_h +#define BaseDateAndTimeInputType_h + +#include "TextFieldInputType.h" +#include <wtf/unicode/Unicode.h> + +namespace WebCore { + +// A super class of date, datetime, datetime-local, month, time, and week types. +class BaseDateAndTimeInputType : public TextFieldInputType { +protected: + BaseDateAndTimeInputType(HTMLInputElement* element) : TextFieldInputType(element) { } + virtual double parseToDouble(const String&, double) const; + virtual bool parseToDateComponents(const String&, DateComponents*) const; + // A helper for parseToDateComponents(). + virtual bool parseToDateComponentsInternal(const UChar*, unsigned length, DateComponents*) const = 0; + virtual bool setMillisecondToDateComponents(double, DateComponents*) const = 0; + +private: + virtual double valueAsDate() const; + virtual void setValueAsDate(double, ExceptionCode&) const; + virtual double valueAsNumber() const; + virtual void setValueAsNumber(double, ExceptionCode&) const; + virtual bool typeMismatchFor(const String&) const; + virtual bool typeMismatch() const; + virtual bool rangeUnderflow(const String&) const; + virtual bool rangeOverflow(const String&) const; + virtual bool stepMismatch(const String&, double) const; + virtual double stepBase() const; + virtual String serialize(double) const; +}; + +} // namespace WebCore + +#endif // BaseDateAndTimeInputType_h diff --git a/WebCore/html/ButtonInputType.cpp b/WebCore/html/ButtonInputType.cpp index 7f56970..deaf30f 100644 --- a/WebCore/html/ButtonInputType.cpp +++ b/WebCore/html/ButtonInputType.cpp @@ -45,4 +45,9 @@ const AtomicString& ButtonInputType::formControlType() const return InputTypeNames::button(); } +bool ButtonInputType::supportsValidation() const +{ + return false; +} + } // namespace WebCore diff --git a/WebCore/html/ButtonInputType.h b/WebCore/html/ButtonInputType.h index 99b3574..7efbad2 100644 --- a/WebCore/html/ButtonInputType.h +++ b/WebCore/html/ButtonInputType.h @@ -42,6 +42,7 @@ public: private: ButtonInputType(HTMLInputElement* element) : InputType(element) { } virtual const AtomicString& formControlType() const; + virtual bool supportsValidation() const; }; } // namespace WebCore diff --git a/WebCore/html/CheckboxInputType.cpp b/WebCore/html/CheckboxInputType.cpp index 1c7ea4b..572dde0 100644 --- a/WebCore/html/CheckboxInputType.cpp +++ b/WebCore/html/CheckboxInputType.cpp @@ -31,6 +31,7 @@ #include "config.h" #include "CheckboxInputType.h" +#include "HTMLInputElement.h" #include <wtf/PassOwnPtr.h> namespace WebCore { @@ -45,4 +46,9 @@ const AtomicString& CheckboxInputType::formControlType() const return InputTypeNames::checkbox(); } +bool CheckboxInputType::valueMissing(const String&) const +{ + return !element()->checked(); +} + } // namespace WebCore diff --git a/WebCore/html/CheckboxInputType.h b/WebCore/html/CheckboxInputType.h index 6a152e9..e041a07 100644 --- a/WebCore/html/CheckboxInputType.h +++ b/WebCore/html/CheckboxInputType.h @@ -42,6 +42,7 @@ public: private: CheckboxInputType(HTMLInputElement* element) : InputType(element) { } virtual const AtomicString& formControlType() const; + virtual bool valueMissing(const String&) const; }; } // namespace WebCore diff --git a/WebCore/html/ColorInputType.cpp b/WebCore/html/ColorInputType.cpp index c68acea..56bfd08 100644 --- a/WebCore/html/ColorInputType.cpp +++ b/WebCore/html/ColorInputType.cpp @@ -31,10 +31,28 @@ #include "config.h" #include "ColorInputType.h" +#include "Color.h" +#include "HTMLInputElement.h" #include <wtf/PassOwnPtr.h> +#include <wtf/text/WTFString.h> namespace WebCore { +static bool isValidColorString(const String& value) +{ + if (value.isEmpty()) + return false; + if (value[0] == '#') { + // We don't accept #rgb and #aarrggbb formats. + if (value.length() != 7) + return false; + } + // This accepts named colors such as "white". + // FIXME: Reject named colors, accept only #rrggbb. + Color color(value); + return color.isValid() && !color.hasAlpha(); +} + PassOwnPtr<InputType> ColorInputType::create(HTMLInputElement* element) { return adoptPtr(new ColorInputType(element)); @@ -45,4 +63,26 @@ const AtomicString& ColorInputType::formControlType() const return InputTypeNames::color(); } +bool ColorInputType::typeMismatchFor(const String& value) const +{ + // FIXME: Should not accept an empty value. Remove it when we implement value + // sanitization for type=color. + if (value.isEmpty()) + return false; + return !isValidColorString(value); +} + +bool ColorInputType::typeMismatch() const +{ + // FIXME: Should return false. We don't implement value sanitization for + // type=color yet. + String value = element()->value(); + return !value.isEmpty() && !isValidColorString(value); +} + +bool ColorInputType::supportsRequired() const +{ + return false; +} + } // namespace WebCore diff --git a/WebCore/html/ColorInputType.h b/WebCore/html/ColorInputType.h index 7259346..ea3798b 100644 --- a/WebCore/html/ColorInputType.h +++ b/WebCore/html/ColorInputType.h @@ -42,6 +42,9 @@ public: private: ColorInputType(HTMLInputElement* element) : TextFieldInputType(element) { } virtual const AtomicString& formControlType() const; + virtual bool typeMismatchFor(const String&) const; + virtual bool typeMismatch() const; + virtual bool supportsRequired() const; }; } // namespace WebCore diff --git a/WebCore/html/DOMFormData.cpp b/WebCore/html/DOMFormData.cpp index f848898..0ece637 100644 --- a/WebCore/html/DOMFormData.cpp +++ b/WebCore/html/DOMFormData.cpp @@ -32,6 +32,8 @@ #include "DOMFormData.h" #include "Blob.h" +#include "HTMLFormControlElement.h" +#include "HTMLFormElement.h" #include "PlatformString.h" #include "TextEncoding.h" @@ -42,6 +44,19 @@ DOMFormData::DOMFormData(const TextEncoding& encoding) { } +DOMFormData::DOMFormData(HTMLFormElement* form) + : FormDataList(UTF8Encoding()) +{ + if (!form) + return; + + for (unsigned i = 0; i < form->associatedElements().size(); ++i) { + HTMLFormControlElement* control = form->associatedElements()[i]; + if (!control->disabled()) + control->appendFormData(*this, true); + } +} + void DOMFormData::append(const String& name, const String& value) { if (!name.isEmpty()) diff --git a/WebCore/html/DOMFormData.h b/WebCore/html/DOMFormData.h index 6c24858..967d64d 100644 --- a/WebCore/html/DOMFormData.h +++ b/WebCore/html/DOMFormData.h @@ -39,18 +39,20 @@ namespace WebCore { class Blob; +class HTMLFormElement; class TextEncoding; class DOMFormData : public FormDataList, public RefCounted<DOMFormData> { public: - static PassRefPtr<DOMFormData> create() { return adoptRef(new DOMFormData(UTF8Encoding())); } + static PassRefPtr<DOMFormData> create(HTMLFormElement* form) { return adoptRef(new DOMFormData(form)); } static PassRefPtr<DOMFormData> create(const TextEncoding& encoding) { return adoptRef(new DOMFormData(encoding)); } void append(const String& name, const String& value); void append(const String& name, Blob*); private: - DOMFormData(const TextEncoding&); + explicit DOMFormData(const TextEncoding&); + explicit DOMFormData(HTMLFormElement*); }; } // namespace WebCore diff --git a/WebCore/html/DOMFormData.idl b/WebCore/html/DOMFormData.idl index c339381..4418428 100644 --- a/WebCore/html/DOMFormData.idl +++ b/WebCore/html/DOMFormData.idl @@ -32,6 +32,8 @@ module html { interface [ CanBeConstructed, + CustomConstructFunction, + V8CustomConstructor, GenerateNativeConverter, GenerateToJS ] DOMFormData { diff --git a/WebCore/html/DOMTokenList.cpp b/WebCore/html/DOMTokenList.cpp index 8ee45a2..aa0a74b 100644 --- a/WebCore/html/DOMTokenList.cpp +++ b/WebCore/html/DOMTokenList.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, Google Inc. All rights reserved. + * Copyright (C) 2010 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,8 +27,9 @@ #include "Element.h" #include "HTMLNames.h" +#include "HTMLParserIdioms.h" #include "SpaceSplitString.h" -#include "StringBuilder.h" +#include <wtf/text/StringBuilder.h> namespace WebCore { @@ -43,7 +44,7 @@ static bool validateToken(const AtomicString& token, ExceptionCode& ec) unsigned length = token.length(); for (unsigned i = 0; i < length; ++i) { - if (isClassWhitespace(token[i])) { + if (isHTMLSpace(token[i])) { ec = INVALID_CHARACTER_ERR; return false; } @@ -71,7 +72,7 @@ void DOMTokenList::deref() unsigned DOMTokenList::length() const { - return classNames().size(); + return m_element->hasClass() ? classNames().size() : 0; } const AtomicString DOMTokenList::item(unsigned index) const @@ -90,7 +91,7 @@ bool DOMTokenList::contains(const AtomicString& token, ExceptionCode& ec) const bool DOMTokenList::containsInternal(const AtomicString& token) const { - return classNames().contains(token); + return m_element->hasClass() && classNames().contains(token); } void DOMTokenList::add(const AtomicString& token, ExceptionCode& ec) @@ -139,25 +140,25 @@ void DOMTokenList::removeInternal(const AtomicString& token) const // Step 5 while (position < inputLength) { - if (isClassWhitespace(input[position])) { // 6 + if (isHTMLSpace(input[position])) { // 6 output.append(input[position++]); // 6.1, 6.2 continue; // 6.3 } // Step 7 Vector<UChar> s; - while (position < inputLength && !isClassWhitespace(input[position])) + while (position < inputLength && isNotHTMLSpace(input[position])) s.append(input[position++]); // Step 8 if (s == token) { // Step 8.1 - while (position < inputLength && isClassWhitespace(input[position])) + while (position < inputLength && isHTMLSpace(input[position])) ++position; // Step 8.2 size_t j = output.size(); - while (j > 0 && isClassWhitespace(output[j - 1])) + while (j > 0 && isHTMLSpace(output[j - 1])) --j; output.resize(j); @@ -198,6 +199,7 @@ void DOMTokenList::reset(const String& newClassName) const SpaceSplitString& DOMTokenList::classNames() const { + ASSERT(m_element->hasClass()); if (!m_classNamesForQuirksMode.isNull()) return m_classNamesForQuirksMode; return m_element->attributeMap()->classNames(); diff --git a/WebCore/html/DateInputType.cpp b/WebCore/html/DateInputType.cpp index 0605846..3409d3b 100644 --- a/WebCore/html/DateInputType.cpp +++ b/WebCore/html/DateInputType.cpp @@ -31,10 +31,18 @@ #include "config.h" #include "DateInputType.h" +#include "DateComponents.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" #include <wtf/PassOwnPtr.h> namespace WebCore { +using namespace HTMLNames; + +static const double dateDefaultStep = 1.0; +static const double dateStepScaleFactor = 86400000.0; + PassOwnPtr<InputType> DateInputType::create(HTMLInputElement* element) { return adoptPtr(new DateInputType(element)); @@ -45,4 +53,42 @@ const AtomicString& DateInputType::formControlType() const return InputTypeNames::date(); } +double DateInputType::minimum() const +{ + return parseToDouble(element()->fastGetAttribute(minAttr), DateComponents::minimumDate()); +} + +double DateInputType::maximum() const +{ + return parseToDouble(element()->fastGetAttribute(maxAttr), DateComponents::maximumDate()); +} + +double DateInputType::defaultStep() const +{ + return dateDefaultStep; +} + +double DateInputType::stepScaleFactor() const +{ + return dateStepScaleFactor; +} + +bool DateInputType::parsedStepValueShouldBeInteger() const +{ + return true; +} + +bool DateInputType::parseToDateComponentsInternal(const UChar* characters, unsigned length, DateComponents* out) const +{ + ASSERT(out); + unsigned end; + return out->parseDate(characters, length, 0, end) && end == length; +} + +bool DateInputType::setMillisecondToDateComponents(double value, DateComponents* date) const +{ + ASSERT(date); + return date->setMillisecondsSinceEpochForDate(value); +} + } // namespace WebCore diff --git a/WebCore/html/DateInputType.h b/WebCore/html/DateInputType.h index e6f60d7..965d9ea 100644 --- a/WebCore/html/DateInputType.h +++ b/WebCore/html/DateInputType.h @@ -31,17 +31,24 @@ #ifndef DateInputType_h #define DateInputType_h -#include "TextFieldInputType.h" +#include "BaseDateAndTimeInputType.h" namespace WebCore { -class DateInputType : public TextFieldInputType { +class DateInputType : public BaseDateAndTimeInputType { public: static PassOwnPtr<InputType> create(HTMLInputElement*); private: - DateInputType(HTMLInputElement* element) : TextFieldInputType(element) { } + DateInputType(HTMLInputElement* element) : BaseDateAndTimeInputType(element) { } virtual const AtomicString& formControlType() const; + virtual double minimum() const; + virtual double maximum() const; + virtual double defaultStep() const; + virtual double stepScaleFactor() const; + virtual bool parsedStepValueShouldBeInteger() const; + virtual bool parseToDateComponentsInternal(const UChar*, unsigned length, DateComponents*) const; + virtual bool setMillisecondToDateComponents(double, DateComponents*) const; }; } // namespace WebCore diff --git a/WebCore/html/DateTimeInputType.cpp b/WebCore/html/DateTimeInputType.cpp index 0bf5e04..c78a540 100644 --- a/WebCore/html/DateTimeInputType.cpp +++ b/WebCore/html/DateTimeInputType.cpp @@ -31,10 +31,18 @@ #include "config.h" #include "DateTimeInputType.h" +#include "DateComponents.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" #include <wtf/PassOwnPtr.h> namespace WebCore { +using namespace HTMLNames; + +static const double dateTimeDefaultStep = 60.0; +static const double dateTimeStepScaleFactor = 1000.0; + PassOwnPtr<InputType> DateTimeInputType::create(HTMLInputElement* element) { return adoptPtr(new DateTimeInputType(element)); @@ -45,4 +53,42 @@ const AtomicString& DateTimeInputType::formControlType() const return InputTypeNames::datetime(); } +double DateTimeInputType::minimum() const +{ + return parseToDouble(element()->fastGetAttribute(minAttr), DateComponents::minimumDateTime()); +} + +double DateTimeInputType::maximum() const +{ + return parseToDouble(element()->fastGetAttribute(maxAttr), DateComponents::maximumDateTime()); +} + +double DateTimeInputType::defaultStep() const +{ + return dateTimeDefaultStep; +} + +double DateTimeInputType::stepScaleFactor() const +{ + return dateTimeStepScaleFactor; +} + +bool DateTimeInputType::scaledStepValeuShouldBeInteger() const +{ + return true; +} + +bool DateTimeInputType::parseToDateComponentsInternal(const UChar* characters, unsigned length, DateComponents* out) const +{ + ASSERT(out); + unsigned end; + return out->parseDateTime(characters, length, 0, end) && end == length; +} + +bool DateTimeInputType::setMillisecondToDateComponents(double value, DateComponents* date) const +{ + ASSERT(date); + return date->setMillisecondsSinceEpochForDateTime(value); +} + } // namespace WebCore diff --git a/WebCore/html/DateTimeInputType.h b/WebCore/html/DateTimeInputType.h index f24ebfb..140975b 100644 --- a/WebCore/html/DateTimeInputType.h +++ b/WebCore/html/DateTimeInputType.h @@ -31,17 +31,24 @@ #ifndef DateTimeInputType_h #define DateTimeInputType_h -#include "TextFieldInputType.h" +#include "BaseDateAndTimeInputType.h" namespace WebCore { -class DateTimeInputType : public TextFieldInputType { +class DateTimeInputType : public BaseDateAndTimeInputType { public: static PassOwnPtr<InputType> create(HTMLInputElement*); private: - DateTimeInputType(HTMLInputElement* element) : TextFieldInputType(element) { } + DateTimeInputType(HTMLInputElement* element) : BaseDateAndTimeInputType(element) { } virtual const AtomicString& formControlType() const; + virtual double minimum() const; + virtual double maximum() const; + virtual double defaultStep() const; + virtual double stepScaleFactor() const; + virtual bool scaledStepValeuShouldBeInteger() const; + virtual bool parseToDateComponentsInternal(const UChar*, unsigned length, DateComponents*) const; + virtual bool setMillisecondToDateComponents(double, DateComponents*) const; }; } // namespace WebCore diff --git a/WebCore/html/DateTimeLocalInputType.cpp b/WebCore/html/DateTimeLocalInputType.cpp index 33c6cfa..1ec2a47 100644 --- a/WebCore/html/DateTimeLocalInputType.cpp +++ b/WebCore/html/DateTimeLocalInputType.cpp @@ -31,10 +31,18 @@ #include "config.h" #include "DateTimeLocalInputType.h" +#include "DateComponents.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" #include <wtf/PassOwnPtr.h> namespace WebCore { +using namespace HTMLNames; + +static const double dateTimeLocalDefaultStep = 60.0; +static const double dateTimeLocalStepScaleFactor = 1000.0; + PassOwnPtr<InputType> DateTimeLocalInputType::create(HTMLInputElement* element) { return adoptPtr(new DateTimeLocalInputType(element)); @@ -45,4 +53,54 @@ const AtomicString& DateTimeLocalInputType::formControlType() const return InputTypeNames::datetimelocal(); } +double DateTimeLocalInputType::valueAsDate() const +{ + // valueAsDate doesn't work for the datetime-local type according to the standard. + return DateComponents::invalidMilliseconds(); +} + +void DateTimeLocalInputType::setValueAsDate(double value, ExceptionCode& ec) const +{ + // valueAsDate doesn't work for the datetime-local type according to the standard. + InputType::setValueAsDate(value, ec); +} + +double DateTimeLocalInputType::minimum() const +{ + return parseToDouble(element()->fastGetAttribute(minAttr), DateComponents::minimumDateTime()); +} + +double DateTimeLocalInputType::maximum() const +{ + return parseToDouble(element()->fastGetAttribute(maxAttr), DateComponents::maximumDateTime()); +} + +double DateTimeLocalInputType::defaultStep() const +{ + return dateTimeLocalDefaultStep; +} + +double DateTimeLocalInputType::stepScaleFactor() const +{ + return dateTimeLocalStepScaleFactor; +} + +bool DateTimeLocalInputType::scaledStepValeuShouldBeInteger() const +{ + return true; +} + +bool DateTimeLocalInputType::parseToDateComponentsInternal(const UChar* characters, unsigned length, DateComponents* out) const +{ + ASSERT(out); + unsigned end; + return out->parseDateTimeLocal(characters, length, 0, end) && end == length; +} + +bool DateTimeLocalInputType::setMillisecondToDateComponents(double value, DateComponents* date) const +{ + ASSERT(date); + return date->setMillisecondsSinceEpochForDateTimeLocal(value); +} + } // namespace WebCore diff --git a/WebCore/html/DateTimeLocalInputType.h b/WebCore/html/DateTimeLocalInputType.h index 1a3d866..966e294 100644 --- a/WebCore/html/DateTimeLocalInputType.h +++ b/WebCore/html/DateTimeLocalInputType.h @@ -31,17 +31,26 @@ #ifndef DateTimeLocalInputType_h #define DateTimeLocalInputType_h -#include "TextFieldInputType.h" +#include "BaseDateAndTimeInputType.h" namespace WebCore { -class DateTimeLocalInputType : public TextFieldInputType { +class DateTimeLocalInputType : public BaseDateAndTimeInputType { public: static PassOwnPtr<InputType> create(HTMLInputElement*); private: - DateTimeLocalInputType(HTMLInputElement* element) : TextFieldInputType(element) { } + DateTimeLocalInputType(HTMLInputElement* element) : BaseDateAndTimeInputType(element) { } virtual const AtomicString& formControlType() const; + virtual double valueAsDate() const; + virtual void setValueAsDate(double, ExceptionCode&) const; + virtual double minimum() const; + virtual double maximum() const; + virtual double defaultStep() const; + virtual double stepScaleFactor() const; + virtual bool scaledStepValeuShouldBeInteger() const; + virtual bool parseToDateComponentsInternal(const UChar*, unsigned length, DateComponents*) const; + virtual bool setMillisecondToDateComponents(double, DateComponents*) const; }; } // namespace WebCore diff --git a/WebCore/html/EmailInputType.cpp b/WebCore/html/EmailInputType.cpp index 4472310..78bda9c 100644 --- a/WebCore/html/EmailInputType.cpp +++ b/WebCore/html/EmailInputType.cpp @@ -1,40 +1,54 @@ /* + * This file is part of the WebKit project. + * + * Copyright (C) 2009 Michelangelo De Simone <micdesim@gmail.com> * 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: + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. * - * * 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. + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. * - * THIS 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 "EmailInputType.h" +#include "HTMLInputElement.h" +#include "RegularExpression.h" #include <wtf/PassOwnPtr.h> namespace WebCore { +static const char emailPattern[] = + "[a-z0-9!#$%&'*+/=?^_`{|}~.-]+" // local part + "@" + "[a-z0-9-]+(\\.[a-z0-9-]+)+"; // domain part + +static bool isValidEmailAddress(const String& address) +{ + int addressLength = address.length(); + if (!addressLength) + return false; + + DEFINE_STATIC_LOCAL(const RegularExpression, regExp, (emailPattern, TextCaseInsensitive)); + + int matchLength; + int matchOffset = regExp.match(address, 0, &matchLength); + + return !matchOffset && matchLength == addressLength; +} + PassOwnPtr<InputType> EmailInputType::create(HTMLInputElement* element) { return adoptPtr(new EmailInputType(element)); @@ -45,4 +59,24 @@ const AtomicString& EmailInputType::formControlType() const return InputTypeNames::email(); } +bool EmailInputType::typeMismatchFor(const String& value) const +{ + if (value.isEmpty()) + return false; + if (!element()->multiple()) + return !isValidEmailAddress(value); + Vector<String> addresses; + value.split(',', addresses); + for (unsigned i = 0; i < addresses.size(); ++i) { + if (!isValidEmailAddress(addresses[i])) + return true; + } + return false; +} + +bool EmailInputType::typeMismatch() const +{ + return typeMismatchFor(element()->value()); +} + } // namespace WebCore diff --git a/WebCore/html/EmailInputType.h b/WebCore/html/EmailInputType.h index bbf6f73..b77a9ad 100644 --- a/WebCore/html/EmailInputType.h +++ b/WebCore/html/EmailInputType.h @@ -42,6 +42,8 @@ public: private: EmailInputType(HTMLInputElement* element) : BaseTextInputType(element) { } virtual const AtomicString& formControlType() const; + virtual bool typeMismatchFor(const String&) const; + virtual bool typeMismatch() const; }; } // namespace WebCore diff --git a/WebCore/html/FTPDirectoryDocument.cpp b/WebCore/html/FTPDirectoryDocument.cpp index 6475ea9..2a08696 100644 --- a/WebCore/html/FTPDirectoryDocument.cpp +++ b/WebCore/html/FTPDirectoryDocument.cpp @@ -39,6 +39,7 @@ #include "Text.h" #include <wtf/text/CString.h> +#include <wtf/text/StringConcatenate.h> #include <wtf/CurrentTime.h> #include <wtf/StdLibExtras.h> @@ -253,9 +254,9 @@ static String processFileDateString(const FTPTime& fileTime) String dateString; if (fileTime.tm_year > -1) - dateString = String::format("%s %i, %i", months[month], fileTime.tm_mday, fileTime.tm_year); + dateString = makeString(months[month], ' ', String::number(fileTime.tm_mday), ", ", String::number(fileTime.tm_year)); else - dateString = String::format("%s %i, %i", months[month], fileTime.tm_mday, now.tm_year); + dateString = makeString(months[month], ' ', String::number(fileTime.tm_mday), ", ", String::number(now.tm_year)); return dateString + timeOfDay; } diff --git a/WebCore/html/FileInputType.cpp b/WebCore/html/FileInputType.cpp index 0e08362..6cb17f2 100644 --- a/WebCore/html/FileInputType.cpp +++ b/WebCore/html/FileInputType.cpp @@ -32,6 +32,7 @@ #include "FileInputType.h" #include <wtf/PassOwnPtr.h> +#include <wtf/text/WTFString.h> namespace WebCore { @@ -45,4 +46,9 @@ const AtomicString& FileInputType::formControlType() const return InputTypeNames::file(); } +bool FileInputType::valueMissing(const String& value) const +{ + return value.isEmpty(); +} + } // namespace WebCore diff --git a/WebCore/html/FileInputType.h b/WebCore/html/FileInputType.h index cebfab7..2cbfe67 100644 --- a/WebCore/html/FileInputType.h +++ b/WebCore/html/FileInputType.h @@ -42,6 +42,7 @@ public: private: FileInputType(HTMLInputElement* element) : InputType(element) { } virtual const AtomicString& formControlType() const; + virtual bool valueMissing(const String&) const; }; } // namespace WebCore diff --git a/WebCore/html/HTMLAnchorElement.cpp b/WebCore/html/HTMLAnchorElement.cpp index 8beccc2..dcdde28 100644 --- a/WebCore/html/HTMLAnchorElement.cpp +++ b/WebCore/html/HTMLAnchorElement.cpp @@ -30,6 +30,7 @@ #include "FrameLoaderTypes.h" #include "HTMLImageElement.h" #include "HTMLNames.h" +#include "HTMLParserIdioms.h" #include "KeyboardEvent.h" #include "MouseEvent.h" #include "Page.h" @@ -37,6 +38,7 @@ #include "RenderImage.h" #include "ResourceHandle.h" #include "Settings.h" +#include "UserGestureIndicator.h" namespace WebCore { @@ -145,7 +147,7 @@ void HTMLAnchorElement::defaultEventHandler(Event* event) } if (isLinkClick(event) && treatLinkAsLiveForEventType(eventType(event))) { - String url = deprecatedParseURL(getAttribute(hrefAttr)); + String url = stripLeadingAndTrailingHTMLSpaces(getAttribute(hrefAttr)); appendServerMapMousePosition(url, event); handleLinkClick(event, document(), url, getAttribute(targetAttr), hasRel(RelationNoReferrer)); sendPings(document()->completeURL(url)); @@ -210,7 +212,7 @@ void HTMLAnchorElement::parseMappedAttribute(Attribute* attr) if (wasLink != isLink()) setNeedsStyleRecalc(); if (isLink()) { - String parsedURL = deprecatedParseURL(attr->value()); + String parsedURL = stripLeadingAndTrailingHTMLSpaces(attr->value()); if (document()->isDNSPrefetchEnabled()) { if (protocolIs(parsedURL, "http") || protocolIs(parsedURL, "https") || parsedURL.startsWith("//")) ResourceHandle::prepareForURL(document()->completeURL(parsedURL)); @@ -261,7 +263,7 @@ bool HTMLAnchorElement::draggable() const KURL HTMLAnchorElement::href() const { - return document()->completeURL(deprecatedParseURL(getAttribute(hrefAttr))); + return document()->completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(hrefAttr))); } void HTMLAnchorElement::setHref(const AtomicString& value) @@ -448,6 +450,13 @@ String HTMLAnchorElement::origin() const return origin->toString(); } +String HTMLAnchorElement::getParameter(const String& name) const +{ + ParsedURLParameters parameters; + href().copyParsedQueryTo(parameters); + return parameters.get(name); +} + void HTMLAnchorElement::setSearch(const String& value) { KURL url = href(); @@ -542,7 +551,9 @@ void handleLinkClick(Event* event, Document* document, const String& url, const Frame* frame = document->frame(); if (!frame) return; - frame->loader()->urlSelected(document->completeURL(url), target, event, false, false, true, hideReferrer ? NoReferrer : SendReferrer); + // FIXME: This seems wrong. Why are we manufactuing a user gesture? + UserGestureIndicator indicator(DefinitelyProcessingUserGesture); + frame->loader()->urlSelected(document->completeURL(url), target, event, false, false, hideReferrer ? NoReferrer : SendReferrer); } } diff --git a/WebCore/html/HTMLAnchorElement.h b/WebCore/html/HTMLAnchorElement.h index a7e7eec..71837ca 100644 --- a/WebCore/html/HTMLAnchorElement.h +++ b/WebCore/html/HTMLAnchorElement.h @@ -84,6 +84,8 @@ public: String origin() const; + String getParameter(const String&) const; + String text() const; String toString() const; diff --git a/WebCore/html/HTMLAnchorElement.idl b/WebCore/html/HTMLAnchorElement.idl index c918fde..432df69 100644 --- a/WebCore/html/HTMLAnchorElement.idl +++ b/WebCore/html/HTMLAnchorElement.idl @@ -53,6 +53,8 @@ module html { readonly attribute [ConvertNullToNullString] DOMString origin; #endif + DOMString getParameter(in DOMString name); + readonly attribute DOMString text; #if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT diff --git a/WebCore/html/HTMLAreaElement.cpp b/WebCore/html/HTMLAreaElement.cpp index 3547cd9..0155bce 100644 --- a/WebCore/html/HTMLAreaElement.cpp +++ b/WebCore/html/HTMLAreaElement.cpp @@ -174,12 +174,17 @@ HTMLImageElement* HTMLAreaElement::imageElement() const bool HTMLAreaElement::isKeyboardFocusable(KeyboardEvent*) const { - return supportsFocus(); + return isFocusable(); +} + +bool HTMLAreaElement::isMouseFocusable() const +{ + return isFocusable(); } bool HTMLAreaElement::isFocusable() const { - return supportsFocus(); + return supportsFocus() && Element::tabIndex() >= 0; } void HTMLAreaElement::dispatchBlurEvent() @@ -192,7 +197,10 @@ void HTMLAreaElement::dispatchBlurEvent() void HTMLAreaElement::updateFocusAppearance(bool restorePreviousSelection) { - Node* parent = parentNode(); + if (!isFocusable()) + return; + + ContainerNode* parent = parentNode(); if (!parent || !parent->hasTagName(mapTag)) return; diff --git a/WebCore/html/HTMLAreaElement.h b/WebCore/html/HTMLAreaElement.h index 10784c3..42d4198 100644 --- a/WebCore/html/HTMLAreaElement.h +++ b/WebCore/html/HTMLAreaElement.h @@ -54,6 +54,7 @@ private: virtual bool supportsFocus() const; virtual String target() const; virtual bool isKeyboardFocusable(KeyboardEvent*) const; + virtual bool isMouseFocusable() const; virtual bool isFocusable() const; virtual void updateFocusAppearance(bool /*restorePreviousSelection*/); virtual void dispatchBlurEvent(); diff --git a/WebCore/html/HTMLAttributeNames.in b/WebCore/html/HTMLAttributeNames.in index 7a80c13..d5c48c4 100644 --- a/WebCore/html/HTMLAttributeNames.in +++ b/WebCore/html/HTMLAttributeNames.in @@ -206,6 +206,7 @@ onseeked onseeking onselect onselectstart +onwebkitspeechchange onstalled onstorage onsuspend @@ -258,7 +259,7 @@ size sortable sortdirection span -webkitspeech +x-webkit-speech spellcheck src standby diff --git a/WebCore/html/HTMLBodyElement.cpp b/WebCore/html/HTMLBodyElement.cpp index 60126f7..c394f3d 100644 --- a/WebCore/html/HTMLBodyElement.cpp +++ b/WebCore/html/HTMLBodyElement.cpp @@ -33,6 +33,7 @@ #include "FrameView.h" #include "HTMLFrameElementBase.h" #include "HTMLNames.h" +#include "HTMLParserIdioms.h" #include "ScriptEventListener.h" #ifdef ANDROID_META_SUPPORT @@ -100,7 +101,7 @@ bool HTMLBodyElement::mapToEntry(const QualifiedName& attrName, MappedAttributeE void HTMLBodyElement::parseMappedAttribute(Attribute* attr) { if (attr->name() == backgroundAttr) { - String url = deprecatedParseURL(attr->value()); + String url = stripLeadingAndTrailingHTMLSpaces(attr->value()); if (!url.isEmpty()) addCSSImageProperty(attr, CSSPropertyBackgroundImage, document()->completeURL(url).string()); } else if (attr->name() == marginwidthAttr || attr->name() == leftmarginAttr) { @@ -218,6 +219,9 @@ void HTMLBodyElement::insertedIntoDocument() // But without it we hang during WebKit tests; need to fix that and remove this. if (FrameView* view = document()->view()) view->scheduleRelayout(); + + if (document() && document()->page()) + document()->page()->updateViewportArguments(); } bool HTMLBodyElement::isURLAttribute(Attribute *attr) const @@ -225,6 +229,11 @@ bool HTMLBodyElement::isURLAttribute(Attribute *attr) const return attr->name() == backgroundAttr; } +bool HTMLBodyElement::supportsFocus() const +{ + return isContentEditable() || HTMLElement::supportsFocus(); +} + String HTMLBodyElement::aLink() const { return getAttribute(alinkAttr); diff --git a/WebCore/html/HTMLBodyElement.h b/WebCore/html/HTMLBodyElement.h index d6ef185..df7bfec 100644 --- a/WebCore/html/HTMLBodyElement.h +++ b/WebCore/html/HTMLBodyElement.h @@ -77,6 +77,8 @@ private: void createLinkDecl(); virtual bool isURLAttribute(Attribute*) const; + + virtual bool supportsFocus() const; virtual int scrollLeft() const; virtual void setScrollLeft(int scrollLeft); diff --git a/WebCore/html/HTMLCanvasElement.cpp b/WebCore/html/HTMLCanvasElement.cpp index 634fe13..fea70d1 100644 --- a/WebCore/html/HTMLCanvasElement.cpp +++ b/WebCore/html/HTMLCanvasElement.cpp @@ -260,9 +260,9 @@ void HTMLCanvasElement::paint(GraphicsContext* context, const IntRect& r) ImageBuffer* imageBuffer = buffer(); if (imageBuffer) { if (imageBuffer->drawsUsingCopy()) - context->drawImage(copiedImage(), DeviceColorSpace, r); + context->drawImage(copiedImage(), ColorSpaceDeviceRGB, r); else - context->drawImageBuffer(imageBuffer, DeviceColorSpace, r); + context->drawImageBuffer(imageBuffer, ColorSpaceDeviceRGB, r); } } } diff --git a/WebCore/html/HTMLElement.cpp b/WebCore/html/HTMLElement.cpp index a56efdc..1483fbc 100644 --- a/WebCore/html/HTMLElement.cpp +++ b/WebCore/html/HTMLElement.cpp @@ -456,7 +456,7 @@ void HTMLElement::setOuterText(const String &text, ExceptionCode& ec) return; } - Node* parent = parentNode(); + ContainerNode* parent = parentNode(); if (!parent) { ec = NO_MODIFICATION_ALLOWED_ERR; return; @@ -507,9 +507,8 @@ Node* HTMLElement::insertAdjacent(const String& where, Node* newChild, Exception // Opera also appears to disallow such usage. if (equalIgnoringCase(where, "beforeBegin")) { - if (Node* p = parent()) - return p->insertBefore(newChild, this, ec) ? newChild : 0; - return 0; + ContainerNode* parent = this->parent(); + return (parent && parent->insertBefore(newChild, this, ec)) ? newChild : 0; } if (equalIgnoringCase(where, "afterBegin")) @@ -519,9 +518,8 @@ Node* HTMLElement::insertAdjacent(const String& where, Node* newChild, Exception return appendChild(newChild, ec) ? newChild : 0; if (equalIgnoringCase(where, "afterEnd")) { - if (Node* p = parent()) - return p->insertBefore(newChild, nextSibling(), ec) ? newChild : 0; - return 0; + ContainerNode* parent = this->parent(); + return (parent && parent->insertBefore(newChild, nextSibling(), ec)) ? newChild : 0; } // IE throws COM Exception E_INVALIDARG; this is the best DOM exception alternative. @@ -546,7 +544,7 @@ Element* HTMLElement::insertAdjacentElement(const String& where, Element* newChi static Element* contextElementForInsertion(const String& where, Element* element, ExceptionCode& ec) { if (equalIgnoringCase(where, "beforeBegin") || equalIgnoringCase(where, "afterEnd")) { - Node* parent = element->parentNode(); + ContainerNode* parent = element->parentNode(); if (parent && parent->isDocumentNode()) { ec = NO_MODIFICATION_ALLOWED_ERR; return 0; @@ -793,9 +791,10 @@ RenderObject* HTMLElement::createRenderer(RenderArena* arena, RenderStyle* style HTMLFormElement* HTMLElement::findFormAncestor() const { - for (Node* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) + for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) { if (ancestor->hasTagName(formTag)) return static_cast<HTMLFormElement*>(ancestor); + } return 0; } diff --git a/WebCore/html/HTMLEmbedElement.cpp b/WebCore/html/HTMLEmbedElement.cpp index e88ee81..c4f007c 100644 --- a/WebCore/html/HTMLEmbedElement.cpp +++ b/WebCore/html/HTMLEmbedElement.cpp @@ -25,13 +25,16 @@ #include "HTMLEmbedElement.h" #include "Attribute.h" -#include "CSSHelper.h" #include "CSSPropertyNames.h" +#include "DocumentLoader.h" #include "Frame.h" #include "HTMLDocument.h" #include "HTMLImageLoader.h" #include "HTMLNames.h" #include "HTMLObjectElement.h" +#include "HTMLParserIdioms.h" +#include "MainResourceLoader.h" +#include "PluginDocument.h" #include "RenderEmbeddedObject.h" #include "RenderImage.h" #include "RenderWidget.h" @@ -94,9 +97,9 @@ void HTMLEmbedElement::parseMappedAttribute(Attribute* attr) if (!isImageType() && m_imageLoader) m_imageLoader.clear(); } else if (attr->name() == codeAttr) - m_url = deprecatedParseURL(value.string()); + m_url = stripLeadingAndTrailingHTMLSpaces(value.string()); else if (attr->name() == srcAttr) { - m_url = deprecatedParseURL(value.string()); + m_url = stripLeadingAndTrailingHTMLSpaces(value.string()); if (renderer() && isImageType()) { if (!m_imageLoader) m_imageLoader = adoptPtr(new HTMLImageLoader(this)); @@ -158,8 +161,20 @@ void HTMLEmbedElement::updateWidget(bool onlyCreateNonNetscapePlugins) Vector<String> paramValues; parametersForPlugin(paramNames, paramValues); - if (!dispatchBeforeLoadEvent(m_url)) + ASSERT(!m_inBeforeLoadEventHandler); + m_inBeforeLoadEventHandler = true; + bool beforeLoadAllowedLoad = dispatchBeforeLoadEvent(m_url); + m_inBeforeLoadEventHandler = false; + + if (!beforeLoadAllowedLoad) { + if (document()->isPluginDocument()) { + // Plugins inside plugin documents load differently than other plugins. By the time + // we are here in a plugin document, the load of the plugin (which is the plugin document's + // main resource) has already started. We need to explicitly cancel the main resource load here. + toPluginDocument(document())->cancelManualPluginLoad(); + } return; + } SubframeLoader* loader = document()->frame()->loader()->subframeLoader(); // FIXME: beforeLoad could have detached the renderer! Just like in the <object> case above. @@ -177,7 +192,7 @@ bool HTMLEmbedElement::rendererIsNeeded(RenderStyle* style) // If my parent is an <object> and is not set to use fallback content, I // should be ignored and not get a renderer. - Node* p = parentNode(); + ContainerNode* p = parentNode(); if (p && p->hasTagName(objectTag)) { ASSERT(p->renderer()); if (!static_cast<HTMLObjectElement*>(p)->useFallbackContent()) { diff --git a/WebCore/html/HTMLFormControlElement.cpp b/WebCore/html/HTMLFormControlElement.cpp index 2080d91..51b9e20 100644 --- a/WebCore/html/HTMLFormControlElement.cpp +++ b/WebCore/html/HTMLFormControlElement.cpp @@ -255,7 +255,7 @@ bool HTMLFormControlElement::isKeyboardFocusable(KeyboardEvent* event) const bool HTMLFormControlElement::isMouseFocusable() const { -#if PLATFORM(GTK) +#if PLATFORM(GTK) || PLATFORM(QT) return HTMLElement::isMouseFocusable(); #else return false; @@ -440,7 +440,7 @@ bool HTMLFormControlElementWithState::autoComplete() const bool HTMLFormControlElementWithState::shouldSaveAndRestoreFormControlState() const { // We don't save/restore control state in a form with autocomplete=off. - return autoComplete(); + return attached() && autoComplete(); } void HTMLFormControlElementWithState::finishParsingChildren() @@ -592,10 +592,10 @@ int HTMLTextFormControlElement::selectionEnd() return toRenderTextControl(renderer())->selectionEnd(); } -VisibleSelection HTMLTextFormControlElement::selection() const +PassRefPtr<Range> HTMLTextFormControlElement::selection() const { if (!renderer() || !isTextFormControl() || cachedSelectionStart() < 0 || cachedSelectionEnd() < 0) - return VisibleSelection(); + return 0; return toRenderTextControl(renderer())->selection(cachedSelectionStart(), cachedSelectionEnd()); } diff --git a/WebCore/html/HTMLFormControlElement.h b/WebCore/html/HTMLFormControlElement.h index eae7f0a..4792dba 100644 --- a/WebCore/html/HTMLFormControlElement.h +++ b/WebCore/html/HTMLFormControlElement.h @@ -177,6 +177,8 @@ public: virtual ~HTMLTextFormControlElement(); + // The derived class should return true if placeholder processing is needed. + virtual bool supportsPlaceholder() const = 0; String strippedPlaceholder() const; int selectionStart(); @@ -185,7 +187,7 @@ public: void setSelectionEnd(int); void select(); void setSelectionRange(int start, int end); - VisibleSelection selection() const; + PassRefPtr<Range> selection() const; protected: HTMLTextFormControlElement(const QualifiedName&, Document*, HTMLFormElement*); @@ -204,8 +206,6 @@ private: virtual int cachedSelectionStart() const = 0; virtual int cachedSelectionEnd() const = 0; - // The derived class should return true if placeholder processing is needed. - virtual bool supportsPlaceholder() const = 0; // Returns true if user-editable value is empty. Used to check placeholder visibility. virtual bool isEmptyValue() const = 0; // Called in dispatchFocusEvent(), after placeholder process, before calling parent's dispatchFocusEvent(). diff --git a/WebCore/html/HTMLFormElement.cpp b/WebCore/html/HTMLFormElement.cpp index db5da66..31a72bd 100644 --- a/WebCore/html/HTMLFormElement.cpp +++ b/WebCore/html/HTMLFormElement.cpp @@ -107,7 +107,7 @@ bool HTMLFormElement::rendererIsNeeded(RenderStyle* style) if (!isDemoted()) return HTMLElement::rendererIsNeeded(style); - Node* node = parentNode(); + ContainerNode* node = parentNode(); RenderObject* parentRenderer = node->renderer(); bool parentIsTableElementPart = (parentRenderer->isTable() && node->hasTagName(tableTag)) || (parentRenderer->isTableRow() && node->hasTagName(trTag)) diff --git a/WebCore/html/HTMLFrameElementBase.cpp b/WebCore/html/HTMLFrameElementBase.cpp index 8cca465..f8d682c 100644 --- a/WebCore/html/HTMLFrameElementBase.cpp +++ b/WebCore/html/HTMLFrameElementBase.cpp @@ -25,7 +25,6 @@ #include "HTMLFrameElementBase.h" #include "Attribute.h" -#include "CSSHelper.h" #include "Document.h" #include "EventNames.h" #include "FocusController.h" @@ -35,6 +34,7 @@ #include "FrameView.h" #include "HTMLFrameSetElement.h" #include "HTMLNames.h" +#include "HTMLParserIdioms.h" #include "KURL.h" #include "Page.h" #include "RenderEmbeddedObject.h" @@ -112,7 +112,7 @@ void HTMLFrameElementBase::openURL(bool lockHistory, bool lockBackForwardList) void HTMLFrameElementBase::parseMappedAttribute(Attribute* attr) { if (attr->name() == srcAttr) - setLocation(deprecatedParseURL(attr->value())); + setLocation(stripLeadingAndTrailingHTMLSpaces(attr->value())); else if (isIdAttributeName(attr->name())) { // Important to call through to base for the id attribute so the hasID bit gets set. HTMLFrameOwnerElement::parseMappedAttribute(attr); diff --git a/WebCore/html/HTMLFrameSetElement.cpp b/WebCore/html/HTMLFrameSetElement.cpp index 48c19a1..d7a47d7 100644 --- a/WebCore/html/HTMLFrameSetElement.cpp +++ b/WebCore/html/HTMLFrameSetElement.cpp @@ -164,7 +164,7 @@ void HTMLFrameSetElement::attach() { // Inherit default settings from parent frameset // FIXME: This is not dynamic. - for (Node* node = parentNode(); node; node = node->parentNode()) { + for (ContainerNode* node = parentNode(); node; node = node->parentNode()) { if (node->hasTagName(framesetTag)) { HTMLFrameSetElement* frameset = static_cast<HTMLFrameSetElement*>(node); if (!frameBorderSet) @@ -186,7 +186,7 @@ void HTMLFrameSetElement::attach() void HTMLFrameSetElement::defaultEventHandler(Event* evt) { - if (evt->isMouseEvent() && !noresize && renderer()) { + if (evt->isMouseEvent() && !noresize && renderer() && renderer()->isFrameSet()) { if (toRenderFrameSet(renderer())->userResize(static_cast<MouseEvent*>(evt))) { evt->setDefaultHandled(); return; diff --git a/WebCore/html/HTMLHtmlElement.cpp b/WebCore/html/HTMLHtmlElement.cpp index 6007805..59c0d3e 100644 --- a/WebCore/html/HTMLHtmlElement.cpp +++ b/WebCore/html/HTMLHtmlElement.cpp @@ -27,6 +27,7 @@ #include "ApplicationCacheHost.h" #include "Document.h" #include "DocumentLoader.h" +#include "DocumentParser.h" #include "Frame.h" #include "HTMLNames.h" @@ -56,11 +57,10 @@ bool HTMLHtmlElement::isURLAttribute(Attribute* attribute) const } #if ENABLE(OFFLINE_WEB_APPLICATIONS) -void HTMLHtmlElement::insertedIntoDocument() +void HTMLHtmlElement::insertedByParser() { - HTMLElement::insertedIntoDocument(); - - if (!document()->parsing()) + // When parsing a fragment, its dummy document has a null parser. + if (!document()->parser() || !document()->parser()->documentWasLoadedAsPartOfNavigation()) return; if (!document()->frame()) @@ -70,12 +70,8 @@ void HTMLHtmlElement::insertedIntoDocument() if (!documentLoader) return; - // Check the manifest attribute - // FIXME: Revisit this when we get a clarification from whatwg on how to handle empty - // manifest attributes. As spec'd, and coded here, the system will initiate an update - // passing in the document URL as the manifest URL. That's not a good thing. const AtomicString& manifest = getAttribute(manifestAttr); - if (manifest.isNull()) + if (manifest.isEmpty()) documentLoader->applicationCacheHost()->selectCacheWithoutManifest(); else documentLoader->applicationCacheHost()->selectCacheWithManifest(document()->completeURL(manifest)); diff --git a/WebCore/html/HTMLHtmlElement.h b/WebCore/html/HTMLHtmlElement.h index 47503f7..9cad44e 100644 --- a/WebCore/html/HTMLHtmlElement.h +++ b/WebCore/html/HTMLHtmlElement.h @@ -33,14 +33,14 @@ public: static PassRefPtr<HTMLHtmlElement> create(Document*); static PassRefPtr<HTMLHtmlElement> create(const QualifiedName&, Document*); +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + void insertedByParser(); +#endif + private: HTMLHtmlElement(const QualifiedName&, Document*); virtual bool isURLAttribute(Attribute*) const; - -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - virtual void insertedIntoDocument(); -#endif }; } // namespace diff --git a/WebCore/html/HTMLIFrameElement.cpp b/WebCore/html/HTMLIFrameElement.cpp index b3fffe3..06af093 100644 --- a/WebCore/html/HTMLIFrameElement.cpp +++ b/WebCore/html/HTMLIFrameElement.cpp @@ -67,7 +67,6 @@ bool HTMLIFrameElement::mapToEntry(const QualifiedName& attrName, MappedAttribut return HTMLFrameElementBase::mapToEntry(attrName, result); } -#if ENABLE(SANDBOX) static SandboxFlags parseSandboxAttribute(Attribute* attribute) { if (attribute->isNull()) @@ -103,7 +102,6 @@ static SandboxFlags parseSandboxAttribute(Attribute* attribute) return flags; } -#endif void HTMLIFrameElement::parseMappedAttribute(Attribute* attr) { @@ -127,11 +125,8 @@ void HTMLIFrameElement::parseMappedAttribute(Attribute* attr) if (!attr->isNull() && !attr->value().toInt()) // Add a rule that nulls out our border width. addCSSLength(attr, CSSPropertyBorderWidth, "0"); - } -#if ENABLE(SANDBOX) - else if (attr->name() == sandboxAttr) + } else if (attr->name() == sandboxAttr) setSandboxFlags(parseSandboxAttribute(attr)); -#endif else HTMLFrameElementBase::parseMappedAttribute(attr); } diff --git a/WebCore/html/HTMLImageElement.cpp b/WebCore/html/HTMLImageElement.cpp index 29ea592..d66075e 100644 --- a/WebCore/html/HTMLImageElement.cpp +++ b/WebCore/html/HTMLImageElement.cpp @@ -24,7 +24,6 @@ #include "HTMLImageElement.h" #include "Attribute.h" -#include "CSSHelper.h" #include "CSSPropertyNames.h" #include "CSSValueKeywords.h" #include "EventNames.h" @@ -32,6 +31,7 @@ #include "HTMLDocument.h" #include "HTMLFormElement.h" #include "HTMLNames.h" +#include "HTMLParserIdioms.h" #include "RenderImage.h" #include "ScriptEventListener.h" @@ -131,7 +131,7 @@ void HTMLImageElement::parseMappedAttribute(Attribute* attr) if (attr->value().string()[0] == '#') usemap = attr->value(); else - usemap = document()->completeURL(deprecatedParseURL(attr->value())).string(); + usemap = document()->completeURL(stripLeadingAndTrailingHTMLSpaces(attr->value())).string(); setIsLink(!attr->isNull()); } else if (attrName == ismapAttr) ismap = true; @@ -237,7 +237,7 @@ void HTMLImageElement::insertedIntoTree(bool deep) { if (!m_form) { // m_form can be non-null if it was set in constructor. - for (Node* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) { + for (ContainerNode* ancestor = parentNode(); ancestor; ancestor = ancestor->parentNode()) { if (ancestor->hasTagName(formTag)) { m_form = static_cast<HTMLFormElement*>(ancestor); m_form->registerImgElement(this); diff --git a/WebCore/html/HTMLImageLoader.cpp b/WebCore/html/HTMLImageLoader.cpp index 6e31d9b..f620542 100644 --- a/WebCore/html/HTMLImageLoader.cpp +++ b/WebCore/html/HTMLImageLoader.cpp @@ -22,13 +22,13 @@ #include "config.h" #include "HTMLImageLoader.h" -#include "CSSHelper.h" #include "CachedImage.h" #include "Element.h" #include "Event.h" #include "EventNames.h" #include "HTMLNames.h" #include "HTMLObjectElement.h" +#include "HTMLParserIdioms.h" #if USE(JSC) #include "JSDOMWindowBase.h" @@ -55,7 +55,7 @@ void HTMLImageLoader::dispatchLoadEvent() String HTMLImageLoader::sourceURI(const AtomicString& attr) const { - return deprecatedParseURL(attr); + return stripLeadingAndTrailingHTMLSpaces(attr); } void HTMLImageLoader::notifyFinished(CachedResource*) diff --git a/WebCore/html/HTMLInputElement.cpp b/WebCore/html/HTMLInputElement.cpp index ef7c42f..9807a55 100644 --- a/WebCore/html/HTMLInputElement.cpp +++ b/WebCore/html/HTMLInputElement.cpp @@ -56,7 +56,6 @@ #include "LocalizedStrings.h" #include "MouseEvent.h" #include "Page.h" -#include "RegularExpression.h" #include "RenderButton.h" #include "RenderFileUploadControl.h" #include "RenderImage.h" @@ -65,6 +64,7 @@ #include "RenderTextControlSingleLine.h" #include "RenderTheme.h" #include "ScriptEventListener.h" +#include "Settings.h" #include "StepRange.h" #include "TextEvent.h" #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS @@ -84,72 +84,12 @@ using namespace HTMLNames; const int maxSavedResults = 256; -// Constant values for getAllowedValueStep(). -static const double dateDefaultStep = 1.0; -static const double dateStepScaleFactor = 86400000.0; -static const double dateTimeDefaultStep = 60.0; -static const double dateTimeStepScaleFactor = 1000.0; -static const double monthDefaultStep = 1.0; -static const double monthStepScaleFactor = 1.0; -static const double numberDefaultStep = 1.0; -static const double numberStepScaleFactor = 1.0; -static const double timeDefaultStep = 60.0; -static const double timeStepScaleFactor = 1000.0; -static const double weekDefaultStep = 1.0; -static const double weekStepScaleFactor = 604800000.0; - -// Constant values for minimum(). -static const double numberDefaultMinimum = -DBL_MAX; -static const double rangeDefaultMinimum = 0.0; - -// Constant values for maximum(). -static const double numberDefaultMaximum = DBL_MAX; -static const double rangeDefaultMaximum = 100.0; - -static const double defaultStepBase = 0.0; -static const double weekDefaultStepBase = -259200000.0; // The first day of 1970-W01. - -static const double msecPerMinute = 60 * 1000; -static const double msecPerSecond = 1000; - -static const char emailPattern[] = - "[a-z0-9!#$%&'*+/=?^_`{|}~.-]+" // local part - "@" - "[a-z0-9-]+(\\.[a-z0-9-]+)+"; // domain part - static bool isNumberCharacter(UChar ch) { return ch == '+' || ch == '-' || ch == '.' || ch == 'e' || ch == 'E' || (ch >= '0' && ch <= '9'); } -static bool isValidColorString(const String& value) -{ - if (value.isEmpty()) - return false; - if (value[0] == '#') { - // We don't accept #rgb and #aarrggbb formats. - if (value.length() != 7) - return false; - } - Color color(value); // This accepts named colors such as "white". - return color.isValid() && !color.hasAlpha(); -} - -static bool isValidEmailAddress(const String& address) -{ - int addressLength = address.length(); - if (!addressLength) - return false; - - DEFINE_STATIC_LOCAL(const RegularExpression, regExp, (emailPattern, TextCaseInsensitive)); - - int matchLength; - int matchOffset = regExp.match(address, 0, &matchLength); - - return !matchOffset && matchLength == addressLength; -} - HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form) : HTMLTextFormControlElement(tagName, document, form) , m_xPos(0) @@ -199,17 +139,10 @@ bool HTMLInputElement::autoComplete() const return HTMLTextFormControlElement::autoComplete(); } -static inline CheckedRadioButtons& checkedRadioButtons(const HTMLInputElement* element) -{ - if (HTMLFormElement* form = element->form()) - return form->checkedRadioButtons(); - return element->document()->checkedRadioButtons(); -} - void HTMLInputElement::updateCheckedRadioButtons() { if (attached() && checked()) - checkedRadioButtons(this).addButton(this); + checkedRadioButtons().addButton(this); if (form()) { const Vector<HTMLFormControlElement*>& controls = form()->associatedElements(); @@ -250,7 +183,7 @@ bool HTMLInputElement::isValidValue(const String& value) const ASSERT_NOT_REACHED(); return false; } - return !typeMismatch(value) + return !m_inputType->typeMismatchFor(value) && !stepMismatch(value) && !rangeUnderflow(value) && !rangeOverflow(value) @@ -259,93 +192,16 @@ bool HTMLInputElement::isValidValue(const String& value) const && !valueMissing(value); } -bool HTMLInputElement::typeMismatch(const String& value) const +bool HTMLInputElement::typeMismatch() const { - switch (deprecatedInputType()) { - case COLOR: - return !isValidColorString(value); - case NUMBER: - ASSERT(parseToDoubleForNumberType(value, 0)); - return false; - case URL: - return !KURL(KURL(), value).isValid(); - case EMAIL: { - if (!multiple()) - return !isValidEmailAddress(value); - Vector<String> addresses; - value.split(',', addresses); - for (unsigned i = 0; i < addresses.size(); ++i) { - if (!isValidEmailAddress(addresses[i])) - return true; - } - return false; - } - case DATE: - case DATETIME: - case DATETIMELOCAL: - case MONTH: - case TIME: - case WEEK: - return !parseToDateComponents(deprecatedInputType(), value, 0); - case BUTTON: - case CHECKBOX: - case FILE: - case HIDDEN: - case IMAGE: - case ISINDEX: - case PASSWORD: - case RADIO: - case RANGE: - case RESET: - case SEARCH: - case SUBMIT: - case TELEPHONE: - case TEXT: - return false; - } - ASSERT_NOT_REACHED(); - return false; + return m_inputType->typeMismatch(); } bool HTMLInputElement::valueMissing(const String& value) const { if (!isRequiredFormControl() || readOnly() || disabled()) return false; - - switch (deprecatedInputType()) { - case DATE: - case DATETIME: - case DATETIMELOCAL: - case EMAIL: - case FILE: - case MONTH: - case NUMBER: - case PASSWORD: - case SEARCH: - case TELEPHONE: - case TEXT: - case TIME: - case URL: - case WEEK: - return value.isEmpty(); - case CHECKBOX: - return !checked(); - case RADIO: - return !checkedRadioButtons(this).checkedButtonForGroup(name()); - case COLOR: - return false; - case BUTTON: - case HIDDEN: - case IMAGE: - case ISINDEX: - case RANGE: - case RESET: - case SUBMIT: - break; - } - - ASSERT_NOT_REACHED(); - return false; + return m_inputType->valueMissing(value); } bool HTMLInputElement::patternMismatch(const String& value) const @@ -373,199 +229,22 @@ bool HTMLInputElement::tooLong(const String& value, NeedsToCheckDirtyFlag check) bool HTMLInputElement::rangeUnderflow(const String& value) const { - const double nan = numeric_limits<double>::quiet_NaN(); - switch (deprecatedInputType()) { - case DATE: - case DATETIME: - case DATETIMELOCAL: - case MONTH: - case NUMBER: - case TIME: - case WEEK: { - double doubleValue = parseToDouble(value, nan); - return isfinite(doubleValue) && doubleValue < minimum(); - } - case RANGE: // Guaranteed by sanitization. - ASSERT(parseToDouble(value, nan) >= minimum()); - case BUTTON: - case CHECKBOX: - case COLOR: - case EMAIL: - case FILE: - case HIDDEN: - case IMAGE: - case ISINDEX: - case PASSWORD: - case RADIO: - case RESET: - case SEARCH: - case SUBMIT: - case TELEPHONE: - case TEXT: - case URL: - break; - } - return false; + return m_inputType->rangeUnderflow(value); } bool HTMLInputElement::rangeOverflow(const String& value) const { - const double nan = numeric_limits<double>::quiet_NaN(); - switch (deprecatedInputType()) { - case DATE: - case DATETIME: - case DATETIMELOCAL: - case MONTH: - case NUMBER: - case TIME: - case WEEK: { - double doubleValue = parseToDouble(value, nan); - return isfinite(doubleValue) && doubleValue > maximum(); - } - case RANGE: // Guaranteed by sanitization. - ASSERT(parseToDouble(value, nan) <= maximum()); - case BUTTON: - case CHECKBOX: - case COLOR: - case EMAIL: - case FILE: - case HIDDEN: - case IMAGE: - case ISINDEX: - case PASSWORD: - case RADIO: - case RESET: - case SEARCH: - case SUBMIT: - case TELEPHONE: - case TEXT: - case URL: - break; - } - return false; + return m_inputType->rangeOverflow(value); } double HTMLInputElement::minimum() const { - switch (deprecatedInputType()) { - case DATE: - return parseToDouble(getAttribute(minAttr), DateComponents::minimumDate()); - case DATETIME: - case DATETIMELOCAL: - return parseToDouble(getAttribute(minAttr), DateComponents::minimumDateTime()); - case MONTH: - return parseToDouble(getAttribute(minAttr), DateComponents::minimumMonth()); - case NUMBER: - return parseToDouble(getAttribute(minAttr), numberDefaultMinimum); - case RANGE: - return parseToDouble(getAttribute(minAttr), rangeDefaultMinimum); - case TIME: - return parseToDouble(getAttribute(minAttr), DateComponents::minimumTime()); - case WEEK: - return parseToDouble(getAttribute(minAttr), DateComponents::minimumWeek()); - case BUTTON: - case CHECKBOX: - case COLOR: - case EMAIL: - case FILE: - case HIDDEN: - case IMAGE: - case ISINDEX: - case PASSWORD: - case RADIO: - case RESET: - case SEARCH: - case SUBMIT: - case TELEPHONE: - case TEXT: - case URL: - break; - } - ASSERT_NOT_REACHED(); - return 0; + return m_inputType->minimum(); } double HTMLInputElement::maximum() const { - switch (deprecatedInputType()) { - case DATE: - return parseToDouble(getAttribute(maxAttr), DateComponents::maximumDate()); - case DATETIME: - case DATETIMELOCAL: - return parseToDouble(getAttribute(maxAttr), DateComponents::maximumDateTime()); - case MONTH: - return parseToDouble(getAttribute(maxAttr), DateComponents::maximumMonth()); - case NUMBER: - return parseToDouble(getAttribute(maxAttr), numberDefaultMaximum); - case RANGE: { - double max = parseToDouble(getAttribute(maxAttr), rangeDefaultMaximum); - // A remedy for the inconsistent min/max values for RANGE. - // Sets the maximum to the default or the minimum value. - double min = minimum(); - if (max < min) - max = std::max(min, rangeDefaultMaximum); - return max; - } - case TIME: - return parseToDouble(getAttribute(maxAttr), DateComponents::maximumTime()); - case WEEK: - return parseToDouble(getAttribute(maxAttr), DateComponents::maximumWeek()); - case BUTTON: - case CHECKBOX: - case COLOR: - case EMAIL: - case FILE: - case HIDDEN: - case IMAGE: - case ISINDEX: - case PASSWORD: - case RADIO: - case RESET: - case SEARCH: - case SUBMIT: - case TELEPHONE: - case TEXT: - case URL: - break; - } - ASSERT_NOT_REACHED(); - return 0; -} - -double HTMLInputElement::stepBase() const -{ - switch (deprecatedInputType()) { - case RANGE: - return minimum(); - case DATE: - case DATETIME: - case DATETIMELOCAL: - case MONTH: - case NUMBER: - case TIME: - return parseToDouble(getAttribute(minAttr), defaultStepBase); - case WEEK: - return parseToDouble(getAttribute(minAttr), weekDefaultStepBase); - case BUTTON: - case CHECKBOX: - case COLOR: - case EMAIL: - case FILE: - case HIDDEN: - case IMAGE: - case ISINDEX: - case PASSWORD: - case RADIO: - case RESET: - case SEARCH: - case SUBMIT: - case TELEPHONE: - case TEXT: - case URL: - break; - } - ASSERT_NOT_REACHED(); - return 0.0; + return m_inputType->maximum(); } bool HTMLInputElement::stepMismatch(const String& value) const @@ -573,126 +252,15 @@ bool HTMLInputElement::stepMismatch(const String& value) const double step; if (!getAllowedValueStep(&step)) return false; - switch (deprecatedInputType()) { - case RANGE: - // stepMismatch doesn't occur for RANGE. RenderSlider guarantees the - // value matches to step on user input, and sanitation takes care - // of the general case. - return false; - case NUMBER: { - double doubleValue; - if (!parseToDoubleForNumberType(value, &doubleValue)) - return false; - doubleValue = fabs(doubleValue - stepBase()); - if (isinf(doubleValue)) - return false; - // double's fractional part size is DBL_MAN_DIG-bit. If the current - // value is greater than step*2^DBL_MANT_DIG, the following fmod() makes - // no sense. - if (doubleValue / pow(2.0, DBL_MANT_DIG) > step) - return false; - double remainder = fmod(doubleValue, step); - // Accepts errors in lower 7-bit. - double acceptableError = step / pow(2.0, DBL_MANT_DIG - 7); - return acceptableError < remainder && remainder < (step - acceptableError); - } - case DATE: - case DATETIME: - case DATETIMELOCAL: - case MONTH: - case TIME: - case WEEK: { - const double nan = numeric_limits<double>::quiet_NaN(); - double doubleValue = parseToDouble(value, nan); - doubleValue = fabs(doubleValue - stepBase()); - if (!isfinite(doubleValue)) - return false; - ASSERT(round(doubleValue) == doubleValue); - ASSERT(round(step) == step); - return fmod(doubleValue, step); - } - case BUTTON: - case CHECKBOX: - case COLOR: - case EMAIL: - case FILE: - case HIDDEN: - case IMAGE: - case ISINDEX: - case PASSWORD: - case RADIO: - case RESET: - case SEARCH: - case SUBMIT: - case TELEPHONE: - case TEXT: - case URL: - break; - } - // Non-supported types should be rejected by getAllowedValueStep(). - ASSERT_NOT_REACHED(); - return false; -} - -bool HTMLInputElement::getStepParameters(double* defaultStep, double* stepScaleFactor) const -{ - ASSERT(defaultStep); - ASSERT(stepScaleFactor); - switch (deprecatedInputType()) { - case NUMBER: - case RANGE: - *defaultStep = numberDefaultStep; - *stepScaleFactor = numberStepScaleFactor; - return true; - case DATE: - *defaultStep = dateDefaultStep; - *stepScaleFactor = dateStepScaleFactor; - return true; - case DATETIME: - case DATETIMELOCAL: - *defaultStep = dateTimeDefaultStep; - *stepScaleFactor = dateTimeStepScaleFactor; - return true; - case MONTH: - *defaultStep = monthDefaultStep; - *stepScaleFactor = monthStepScaleFactor; - return true; - case TIME: - *defaultStep = timeDefaultStep; - *stepScaleFactor = timeStepScaleFactor; - return true; - case WEEK: - *defaultStep = weekDefaultStep; - *stepScaleFactor = weekStepScaleFactor; - return true; - case BUTTON: - case CHECKBOX: - case COLOR: - case EMAIL: - case FILE: - case HIDDEN: - case IMAGE: - case ISINDEX: - case PASSWORD: - case RADIO: - case RESET: - case SEARCH: - case SUBMIT: - case TELEPHONE: - case TEXT: - case URL: - return false; - } - ASSERT_NOT_REACHED(); - return false; + return m_inputType->stepMismatch(value, step); } bool HTMLInputElement::getAllowedValueStep(double* step) const { ASSERT(step); - double defaultStep; - double stepScaleFactor; - if (!getStepParameters(&defaultStep, &stepScaleFactor)) + double defaultStep = m_inputType->defaultStep(); + double stepScaleFactor = m_inputType->stepScaleFactor(); + if (!isfinite(defaultStep) || !isfinite(stepScaleFactor)) return false; const AtomicString& stepString = getAttribute(stepAttr); if (stepString.isEmpty()) { @@ -706,12 +274,12 @@ bool HTMLInputElement::getAllowedValueStep(double* step) const *step = defaultStep * stepScaleFactor; return true; } - // For DATE, MONTH, WEEK, the parsed value should be an integer. - if (deprecatedInputType() == DATE || deprecatedInputType() == MONTH || deprecatedInputType() == WEEK) + // For date, month, week, the parsed value should be an integer for some types. + if (m_inputType->parsedStepValueShouldBeInteger()) parsed = max(round(parsed), 1.0); double result = parsed * stepScaleFactor; - // For DATETIME, DATETIMELOCAL, TIME, the result should be an integer. - if (deprecatedInputType() == DATETIME || deprecatedInputType() == DATETIMELOCAL || deprecatedInputType() == TIME) + // For datetime, datetime-local, time, the result should be an integer. + if (m_inputType->scaledStepValeuShouldBeInteger()) result = max(round(result), 1.0); ASSERT(result > 0); *step = result; @@ -726,7 +294,7 @@ void HTMLInputElement::applyStep(double count, ExceptionCode& ec) return; } const double nan = numeric_limits<double>::quiet_NaN(); - double current = parseToDouble(value(), nan); + double current = m_inputType->parseToDouble(value(), nan); if (!isfinite(current)) { ec = INVALID_STATE_ERR; return; @@ -736,13 +304,13 @@ void HTMLInputElement::applyStep(double count, ExceptionCode& ec) ec = INVALID_STATE_ERR; return; } - if (newValue < minimum()) { + if (newValue < m_inputType->minimum()) { ec = INVALID_STATE_ERR; return; } - double base = stepBase(); + double base = m_inputType->stepBase(); newValue = base + round((newValue - base) / step) * step; - if (newValue > maximum()) { + if (newValue > m_inputType->maximum()) { ec = INVALID_STATE_ERR; return; } @@ -770,6 +338,9 @@ bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const return false; if (deprecatedInputType() == RADIO) { + // When using Spatial Navigation, every radio button should be focusable. + if (document()->frame() && document()->frame()->settings() && document()->frame()->settings()->isSpatialNavigationEnabled()) + return true; // Never allow keyboard tabbing to leave you in the same radio group. Always // skip any other elements in the group. @@ -781,7 +352,7 @@ bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const } // Allow keyboard focus if we're checked or if nothing in the group is checked. - return checked() || !checkedRadioButtons(this).checkedButtonForGroup(name()); + return checked() || !checkedRadioButtons().checkedButtonForGroup(name()); } return true; @@ -847,33 +418,32 @@ void HTMLInputElement::setType(const String& t) setAttribute(typeAttr, t); } -typedef HashMap<String, HTMLInputElement::DeprecatedInputType, CaseFoldingHash> InputTypeMap; -static PassOwnPtr<InputTypeMap> createTypeMap() +PassOwnPtr<HTMLInputElement::InputTypeMap> HTMLInputElement::createTypeMap() { OwnPtr<InputTypeMap> map = adoptPtr(new InputTypeMap); - map->add("button", HTMLInputElement::BUTTON); - map->add("checkbox", HTMLInputElement::CHECKBOX); - map->add("color", HTMLInputElement::COLOR); - map->add("date", HTMLInputElement::DATE); - map->add("datetime", HTMLInputElement::DATETIME); - map->add("datetime-local", HTMLInputElement::DATETIMELOCAL); - map->add("email", HTMLInputElement::EMAIL); - map->add("file", HTMLInputElement::FILE); - map->add("hidden", HTMLInputElement::HIDDEN); - map->add("image", HTMLInputElement::IMAGE); - map->add("khtml_isindex", HTMLInputElement::ISINDEX); - map->add("month", HTMLInputElement::MONTH); - map->add("number", HTMLInputElement::NUMBER); - map->add("password", HTMLInputElement::PASSWORD); - map->add("radio", HTMLInputElement::RADIO); - map->add("range", HTMLInputElement::RANGE); - map->add("reset", HTMLInputElement::RESET); - map->add("search", HTMLInputElement::SEARCH); - map->add("submit", HTMLInputElement::SUBMIT); - map->add("tel", HTMLInputElement::TELEPHONE); - map->add("time", HTMLInputElement::TIME); - map->add("url", HTMLInputElement::URL); - map->add("week", HTMLInputElement::WEEK); + map->add("button", BUTTON); + map->add("checkbox", CHECKBOX); + map->add("color", COLOR); + map->add("date", DATE); + map->add("datetime", DATETIME); + map->add("datetime-local", DATETIMELOCAL); + map->add("email", EMAIL); + map->add("file", FILE); + map->add("hidden", HIDDEN); + map->add("image", IMAGE); + map->add("khtml_isindex", ISINDEX); + map->add("month", MONTH); + map->add("number", NUMBER); + map->add("password", PASSWORD); + map->add("radio", RADIO); + map->add("range", RANGE); + map->add("reset", RESET); + map->add("search", SEARCH); + map->add("submit", SUBMIT); + map->add("tel", TELEPHONE); + map->add("time", TIME); + map->add("url", URL); + map->add("week", WEEK); // No need to register "text" because it is the default type. return map.release(); } @@ -897,7 +467,7 @@ void HTMLInputElement::updateType() // Useful in case we were called from inside parseMappedAttribute. setAttribute(typeAttr, type()); else { - checkedRadioButtons(this).removeButton(this); + checkedRadioButtons().removeButton(this); if (newType == FILE && !m_fileList) m_fileList = FileList::create(); @@ -947,7 +517,7 @@ void HTMLInputElement::updateType() updateFocusAppearance(true); } - checkedRadioButtons(this).addButton(this); + checkedRadioButtons().addButton(this); } setNeedsValidityCheck(); @@ -1115,9 +685,9 @@ bool HTMLInputElement::mapToEntry(const QualifiedName& attrName, MappedAttribute void HTMLInputElement::parseMappedAttribute(Attribute* attr) { if (attr->name() == nameAttr) { - checkedRadioButtons(this).removeButton(this); + checkedRadioButtons().removeButton(this); m_data.setName(attr->value()); - checkedRadioButtons(this).addButton(this); + checkedRadioButtons().addButton(this); HTMLFormControlElementWithState::parseMappedAttribute(attr); } else if (attr->name() == autocompleteAttr) { if (equalIgnoringCase(attr->value(), "off")) { @@ -1219,7 +789,8 @@ void HTMLInputElement::parseMappedAttribute(Attribute* attr) if (renderer()) renderer()->updateFromElement(); setNeedsStyleRecalc(); - } + } else if (attr->name() == onwebkitspeechchangeAttr) + setAttributeEventListener(eventNames().webkitspeechchangeEvent, createAttributeEventListener(this, attr)); #endif else HTMLTextFormControlElement::parseMappedAttribute(attr); @@ -1461,7 +1032,7 @@ void HTMLInputElement::setChecked(bool nowChecked, bool sendChangeEvent) if (checked() == nowChecked) return; - checkedRadioButtons(this).removeButton(this); + checkedRadioButtons().removeButton(this); m_useDefaultChecked = false; m_checked = nowChecked; @@ -1584,6 +1155,7 @@ String HTMLInputElement::valueWithDefault() const v = submitButtonDefaultLabel(); break; } +<<<<<<< HEAD } return v; } @@ -1825,144 +1397,97 @@ double HTMLInputElement::valueAsNumber() const case TEXT: case URL: return nan; +======= +>>>>>>> webkit.org at r70209 } - ASSERT_NOT_REACHED(); - return nan; + return v; } -void HTMLInputElement::setValueAsNumber(double newValue, ExceptionCode& ec) +void HTMLInputElement::setValueForUser(const String& value) { - if (!isfinite(newValue)) { - ec = NOT_SUPPORTED_ERR; - return; - } - switch (deprecatedInputType()) { - case DATE: - case DATETIME: - case DATETIMELOCAL: - case MONTH: - case NUMBER: - case RANGE: - case TIME: - case WEEK: - setValue(serialize(newValue)); + // Call setValue and make it send a change event. + setValue(value, true); +} + +const String& HTMLInputElement::suggestedValue() const +{ + return m_data.suggestedValue(); +} + +void HTMLInputElement::setSuggestedValue(const String& value) +{ + if (deprecatedInputType() != TEXT) return; + setFormControlValueMatchesRenderer(false); + m_data.setSuggestedValue(sanitizeValue(value)); + updatePlaceholderVisibility(false); + if (renderer()) + renderer()->updateFromElement(); + setNeedsStyleRecalc(); +} - case BUTTON: - case CHECKBOX: - case COLOR: - case EMAIL: - case FILE: - case HIDDEN: - case IMAGE: - case ISINDEX: - case PASSWORD: - case RADIO: - case RESET: - case SEARCH: - case SUBMIT: - case TELEPHONE: - case TEXT: - case URL: - ec = INVALID_STATE_ERR; +void HTMLInputElement::setValue(const String& value, bool sendChangeEvent) +{ + // For security reasons, we don't allow setting the filename, but we do allow clearing it. + // The HTML5 spec (as of the 10/24/08 working draft) says that the value attribute isn't applicable to the file upload control + // but we don't want to break existing websites, who may be relying on this method to clear things. + if (deprecatedInputType() == FILE && !value.isEmpty()) return; + + setFormControlValueMatchesRenderer(false); + if (storesValueSeparateFromAttribute()) { + if (deprecatedInputType() == FILE) + m_fileList->clear(); + else { + m_data.setValue(sanitizeValue(value)); + if (isTextField()) + updatePlaceholderVisibility(false); + } + setNeedsStyleRecalc(); + } else + setAttribute(valueAttr, sanitizeValue(value)); + + setNeedsValidityCheck(); + + if (isTextField()) { + unsigned max = m_data.value().length(); + if (document()->focusedNode() == this) + InputElement::updateSelectionRange(this, this, max, max); + else + cacheSelection(max, max); + m_data.setSuggestedValue(String()); } - ASSERT_NOT_REACHED(); + + // Don't dispatch the change event when focused, it will be dispatched + // when the control loses focus. + if (sendChangeEvent && document()->focusedNode() != this) + dispatchFormControlChangeEvent(); + + InputElement::notifyFormStateChanged(this); } -String HTMLInputElement::serializeForDateTimeTypes(double value) const +double HTMLInputElement::valueAsDate() const { - bool success = false; - DateComponents date; - switch (deprecatedInputType()) { - case DATE: - success = date.setMillisecondsSinceEpochForDate(value); - break; - case DATETIME: - success = date.setMillisecondsSinceEpochForDateTime(value); - break; - case DATETIMELOCAL: - success = date.setMillisecondsSinceEpochForDateTimeLocal(value); - break; - case MONTH: - success = date.setMonthsSinceEpoch(value); - break; - case TIME: - success = date.setMillisecondsSinceMidnight(value); - break; - case WEEK: - success = date.setMillisecondsSinceEpochForWeek(value); - break; - case NUMBER: - case RANGE: - case BUTTON: - case CHECKBOX: - case COLOR: - case EMAIL: - case FILE: - case HIDDEN: - case IMAGE: - case ISINDEX: - case PASSWORD: - case RADIO: - case RESET: - case SEARCH: - case SUBMIT: - case TELEPHONE: - case TEXT: - case URL: - ASSERT_NOT_REACHED(); - return String(); - } - if (!success) - return String(); + return m_inputType->valueAsDate(); +} - double step; - if (!getAllowedValueStep(&step)) - return date.toString(); - if (!fmod(step, msecPerMinute)) - return date.toString(DateComponents::None); - if (!fmod(step, msecPerSecond)) - return date.toString(DateComponents::Second); - return date.toString(DateComponents::Millisecond); +void HTMLInputElement::setValueAsDate(double value, ExceptionCode& ec) +{ + m_inputType->setValueAsDate(value, ec); } -String HTMLInputElement::serialize(double value) const +double HTMLInputElement::valueAsNumber() const { - if (!isfinite(value)) - return String(); - switch (deprecatedInputType()) { - case DATE: - case DATETIME: - case DATETIMELOCAL: - case MONTH: - case TIME: - case WEEK: - return serializeForDateTimeTypes(value); - case NUMBER: - case RANGE: - return serializeForNumberType(value); + return m_inputType->valueAsNumber(); +} - case BUTTON: - case CHECKBOX: - case COLOR: - case EMAIL: - case FILE: - case HIDDEN: - case IMAGE: - case ISINDEX: - case PASSWORD: - case RADIO: - case RESET: - case SEARCH: - case SUBMIT: - case TELEPHONE: - case TEXT: - case URL: - break; +void HTMLInputElement::setValueAsNumber(double newValue, ExceptionCode& ec) +{ + if (!isfinite(newValue)) { + ec = NOT_SUPPORTED_ERR; + return; } - ASSERT_NOT_REACHED(); - return String(); + m_inputType->setValueAsNumber(newValue, ec); } String HTMLInputElement::placeholder() const @@ -2090,7 +1615,7 @@ void* HTMLInputElement::preDispatchEventHandler(Event* evt) // We really want radio groups to end up in sane states, i.e., to have something checked. // Therefore if nothing is currently selected, we won't allow this action to be "undone", since // we want some object in the radio group to actually get selected. - HTMLInputElement* currRadio = checkedRadioButtons(this).checkedButtonForGroup(name()); + HTMLInputElement* currRadio = checkedRadioButtons().checkedButtonForGroup(name()); if (currRadio) { // We have a radio button selected that is not us. Cache it in our result field and ref it so // that it can't be destroyed. @@ -2326,29 +1851,32 @@ void HTMLInputElement::defaultEventHandler(Event* evt) // Right and down mean "next radio button". // Tested in WinIE, and even for RTL, left still means previous radio button (and so moves // to the right). Seems strange, but we'll match it. - bool forward = (key == "Down" || key == "Right"); - - // We can only stay within the form's children if the form hasn't been demoted to a leaf because - // of malformed HTML. - Node* n = this; - while ((n = (forward ? n->traverseNextNode() : n->traversePreviousNode()))) { - // Once we encounter a form element, we know we're through. - if (n->hasTagName(formTag)) - break; - - // Look for more radio buttons. - if (n->hasTagName(inputTag)) { - HTMLInputElement* elt = static_cast<HTMLInputElement*>(n); - if (elt->form() != form()) + // However, when using Spatial Navigation, we need to be able to navigate without changing the selection. + if (!document()->frame() || !document()->frame()->settings() || !document()->frame()->settings()->isSpatialNavigationEnabled()) { + bool forward = (key == "Down" || key == "Right"); + + // We can only stay within the form's children if the form hasn't been demoted to a leaf because + // of malformed HTML. + Node* n = this; + while ((n = (forward ? n->traverseNextNode() : n->traversePreviousNode()))) { + // Once we encounter a form element, we know we're through. + if (n->hasTagName(formTag)) break; + + // Look for more radio buttons. if (n->hasTagName(inputTag)) { - HTMLInputElement* inputElt = static_cast<HTMLInputElement*>(n); - if (inputElt->deprecatedInputType() == RADIO && inputElt->name() == name() && inputElt->isFocusable()) { - inputElt->setChecked(true); - document()->setFocusedNode(inputElt); - inputElt->dispatchSimulatedClick(evt, false, false); - evt->setDefaultHandled(); + HTMLInputElement* elt = static_cast<HTMLInputElement*>(n); + if (elt->form() != form()) break; + if (n->hasTagName(inputTag)) { + HTMLInputElement* inputElt = static_cast<HTMLInputElement*>(n); + if (inputElt->deprecatedInputType() == RADIO && inputElt->name() == name() && inputElt->isFocusable()) { + inputElt->setChecked(true); + document()->setFocusedNode(inputElt); + inputElt->dispatchSimulatedClick(evt, false, false); + evt->setDefaultHandled(); + break; + } } } } @@ -2500,11 +2028,11 @@ void HTMLInputElement::handleKeyEventForRange(KeyboardEvent* event) ExceptionCode ec; if (equalIgnoringCase(getAttribute(stepAttr), "any")) { - double min = minimum(); - double max = maximum(); + double min = m_inputType->minimum(); + double max = m_inputType->maximum(); // FIXME: Is 1/100 reasonable? double step = (max - min) / 100; - double current = parseToDouble(value(), numeric_limits<double>::quiet_NaN()); + double current = m_inputType->parseToDouble(value(), numeric_limits<double>::quiet_NaN()); ASSERT(isfinite(current)); double newValue; if (key == "Up" || key == "Right") { @@ -2678,40 +2206,7 @@ void HTMLInputElement::unregisterForActivationCallbackIfNeeded() bool HTMLInputElement::isRequiredFormControl() const { - if (!required()) - return false; - - switch (deprecatedInputType()) { - case CHECKBOX: - case DATE: - case DATETIME: - case DATETIMELOCAL: - case EMAIL: - case FILE: - case MONTH: - case NUMBER: - case PASSWORD: - case RADIO: - case SEARCH: - case TELEPHONE: - case TEXT: - case TIME: - case URL: - case WEEK: - return true; - case BUTTON: - case COLOR: - case HIDDEN: - case IMAGE: - case ISINDEX: - case RANGE: - case RESET: - case SUBMIT: - return false; - } - - ASSERT_NOT_REACHED(); - return false; + return m_inputType->supportsRequired() && required(); } void HTMLInputElement::cacheSelection(int start, int end) @@ -2771,66 +2266,7 @@ void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) cons bool HTMLInputElement::recalcWillValidate() const { - switch (deprecatedInputType()) { - case CHECKBOX: - case COLOR: - case DATE: - case DATETIME: - case DATETIMELOCAL: - case EMAIL: - case FILE: - case ISINDEX: - case MONTH: - case NUMBER: - case PASSWORD: - case RADIO: - case RANGE: - case SEARCH: - case TELEPHONE: - case TEXT: - case TIME: - case URL: - case WEEK: - return HTMLFormControlElementWithState::recalcWillValidate(); - case BUTTON: - case HIDDEN: - case IMAGE: - case RESET: - case SUBMIT: - return false; - } - ASSERT_NOT_REACHED(); - return false; -} - -bool HTMLInputElement::parseToDateComponents(DeprecatedInputType type, const String& formString, DateComponents* out) -{ - if (formString.isEmpty()) - return false; - DateComponents ignoredResult; - if (!out) - out = &ignoredResult; - const UChar* characters = formString.characters(); - unsigned length = formString.length(); - unsigned end; - - switch (type) { - case DATE: - return out->parseDate(characters, length, 0, end) && end == length; - case DATETIME: - return out->parseDateTime(characters, length, 0, end) && end == length; - case DATETIMELOCAL: - return out->parseDateTimeLocal(characters, length, 0, end) && end == length; - case MONTH: - return out->parseMonth(characters, length, 0, end) && end == length; - case WEEK: - return out->parseWeek(characters, length, 0, end) && end == length; - case TIME: - return out->parseTime(characters, length, 0, end) && end == length; - default: - ASSERT_NOT_REACHED(); - return false; - } + return m_inputType->supportsValidation() && HTMLFormControlElementWithState::recalcWillValidate(); } #if ENABLE(DATALIST) @@ -2924,9 +2360,9 @@ void HTMLInputElement::stepUpFromRenderer(int n) const double nan = numeric_limits<double>::quiet_NaN(); String currentStringValue = value(); - double current = parseToDouble(currentStringValue, nan); - if (!isfinite(current) || (n > 0 && current < minimum()) || (n < 0 && current > maximum())) - setValue(serialize(n > 0 ? minimum() : maximum())); + double current = m_inputType->parseToDouble(currentStringValue, nan); + if (!isfinite(current) || (n > 0 && current < m_inputType->minimum()) || (n < 0 && current > m_inputType->maximum())) + setValue(m_inputType->serialize(n > 0 ? m_inputType->minimum() : m_inputType->maximum())); else { ExceptionCode ec; stepUp(n, ec); @@ -2982,6 +2418,12 @@ bool HTMLInputElement::isSpeechEnabled() const } return false; } + +void HTMLInputElement::dispatchWebkitSpeechChangeEvent() +{ + ASSERT(isSpeechEnabled()); + dispatchEvent(Event::create(eventNames().webkitspeechchangeEvent, true, false)); +} #endif } // namespace diff --git a/WebCore/html/HTMLInputElement.h b/WebCore/html/HTMLInputElement.h index 88e2bf7..e584a78 100644 --- a/WebCore/html/HTMLInputElement.h +++ b/WebCore/html/HTMLInputElement.h @@ -25,6 +25,7 @@ #define HTMLInputElement_h #include "HTMLFormControlElement.h" +#include "HTMLFormElement.h" #include "InputElement.h" #include <wtf/OwnPtr.h> @@ -41,40 +42,15 @@ class VisibleSelection; class HTMLInputElement : public HTMLTextFormControlElement, public InputElement { public: - enum DeprecatedInputType { - TEXT = 0, // TEXT must be 0. - PASSWORD, - ISINDEX, - CHECKBOX, - RADIO, - SUBMIT, - RESET, - FILE, - HIDDEN, - IMAGE, - BUTTON, - SEARCH, - RANGE, - EMAIL, - NUMBER, - TELEPHONE, - URL, - COLOR, - DATE, - DATETIME, - DATETIMELOCAL, - MONTH, - TIME, - WEEK, - }; - static PassRefPtr<HTMLInputElement> create(const QualifiedName&, Document*, HTMLFormElement*); virtual ~HTMLInputElement(); + DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitspeechchange); + bool autoComplete() const; // For ValidityState - bool typeMismatch(const String&) const; + bool typeMismatch() const; // valueMissing() ignores the specified string value for CHECKBOX and RADIO. bool valueMissing(const String&) const; bool patternMismatch(const String&) const; @@ -125,7 +101,8 @@ public: #if ENABLE(INPUT_SPEECH) virtual bool isSpeechEnabled() const; -#endif + void dispatchWebkitSpeechChangeEvent(); +#endif bool checked() const { return m_checked; } void setChecked(bool, bool sendChangeEvent = false); @@ -175,8 +152,6 @@ public: virtual bool isActivatedSubmit() const; virtual void setActivatedSubmit(bool flag); - DeprecatedInputType deprecatedInputType() const { return static_cast<DeprecatedInputType>(m_deprecatedTypeNumber); } - String altText() const; int maxResults() const { return m_maxResults; } @@ -212,11 +187,6 @@ public: void addSearchResult(); void onSearch(); - // Parses the specified string as the DeprecatedInputType, and returns true if it is successfully parsed. - // An instance pointed by the DateComponents* parameter will have parsed values and be - // modified even if the parsing fails. The DateComponents* parameter may be 0. - static bool parseToDateComponents(DeprecatedInputType, const String&, DateComponents*); - #if ENABLE(DATALIST) HTMLElement* list() const; HTMLOptionElement* selectedOption() const; @@ -226,14 +196,52 @@ public: void setWapInputFormat(String& mask); #endif + inline CheckedRadioButtons& checkedRadioButtons() const + { + if (HTMLFormElement* formElement = form()) + return formElement->checkedRadioButtons(); + return document()->checkedRadioButtons(); + } + protected: HTMLInputElement(const QualifiedName&, Document*, HTMLFormElement* = 0); virtual void defaultEventHandler(Event*); private: + enum DeprecatedInputType { + TEXT = 0, // TEXT must be 0. + PASSWORD, + ISINDEX, + CHECKBOX, + RADIO, + SUBMIT, + RESET, + FILE, + HIDDEN, + IMAGE, + BUTTON, + SEARCH, + RANGE, + EMAIL, + NUMBER, + TELEPHONE, + URL, + COLOR, + DATE, + DATETIME, + DATETIMELOCAL, + MONTH, + TIME, + WEEK, + }; + enum AutoCompleteSetting { Uninitialized, On, Off }; + typedef HashMap<String, HTMLInputElement::DeprecatedInputType, CaseFoldingHash> InputTypeMap; + static PassOwnPtr<InputTypeMap> createTypeMap(); + DeprecatedInputType deprecatedInputType() const { return static_cast<DeprecatedInputType>(m_deprecatedTypeNumber); } + virtual void willMoveToNewOwnerDocument(); virtual void didMoveToNewOwnerDocument(); @@ -326,26 +334,8 @@ private: void handleBeforeTextInsertedEvent(Event*); void handleKeyEventForRange(KeyboardEvent*); PassRefPtr<HTMLFormElement> createTemporaryFormForIsIndex(); - // Helper for getAllowedValueStep(); - bool getStepParameters(double* defaultStep, double* stepScaleFactor) const; // Helper for stepUp()/stepDown(). Adds step value * count to the current value. void applyStep(double count, ExceptionCode&); - // Helper for applyStepForNumberOrRange(). - double stepBase() const; - - // Parses the specified string for the current type, and return - // the double value for the parsing result if the parsing - // succeeds; Returns defaultValue otherwise. This function can - // return NaN or Infinity only if defaultValue is NaN or Infinity. - double parseToDouble(const String&, double defaultValue) const; - // Create a string representation of the specified double value for the - // current input type. If NaN or Infinity is specified, this returns an - // emtpy string. This should not be called for types without valueAsNumber. - String serialize(double) const; - // Create a string representation of the specified double value for the - // current input type. The type must be one of DATE, DATETIME, - // DATETIMELOCAL, MONTH, TIME, and WEEK. - String serializeForDateTimeTypes(double) const; #if ENABLE(DATALIST) HTMLDataListElement* dataList() const; diff --git a/WebCore/html/HTMLInputElement.idl b/WebCore/html/HTMLInputElement.idl index 19dfa5a..1ca7d6c 100644 --- a/WebCore/html/HTMLInputElement.idl +++ b/WebCore/html/HTMLInputElement.idl @@ -56,7 +56,7 @@ module html { #endif attribute [Reflect, URL] DOMString src; attribute [Reflect] DOMString step; - attribute [ConvertNullToNullString, JSCCustomGetter] DOMString type; // readonly dropped as part of DOM level 2 + attribute [ConvertNullToNullString] DOMString type; // readonly dropped as part of DOM level 2 attribute [Reflect] DOMString useMap; attribute [ConvertNullToNullString] DOMString value; #if !defined(LANGUAGE_CPP) || !LANGUAGE_CPP @@ -100,7 +100,8 @@ module html { readonly attribute NodeList labels; #if defined(ENABLE_INPUT_SPEECH) && ENABLE_INPUT_SPEECH - attribute [Reflect, EnabledAtRuntime] boolean webkitspeech; + attribute [Reflect, EnabledAtRuntime] boolean webkitSpeech; + attribute [DontEnum] EventListener onwebkitspeechchange; #endif }; diff --git a/WebCore/html/HTMLLegendElement.cpp b/WebCore/html/HTMLLegendElement.cpp index acc4a59..f998118 100644 --- a/WebCore/html/HTMLLegendElement.cpp +++ b/WebCore/html/HTMLLegendElement.cpp @@ -57,7 +57,7 @@ const AtomicString& HTMLLegendElement::formControlType() const HTMLFormControlElement* HTMLLegendElement::associatedControl() { // Check if there's a fieldset belonging to this legend. - Node* fieldset = parentNode(); + ContainerNode* fieldset = parentNode(); while (fieldset && !fieldset->hasTagName(fieldsetTag)) fieldset = fieldset->parentNode(); if (!fieldset) diff --git a/WebCore/html/HTMLLinkElement.cpp b/WebCore/html/HTMLLinkElement.cpp index 939b375..6a5c2f6 100644 --- a/WebCore/html/HTMLLinkElement.cpp +++ b/WebCore/html/HTMLLinkElement.cpp @@ -25,7 +25,6 @@ #include "HTMLLinkElement.h" #include "Attribute.h" -#include "CSSHelper.h" #include "CachedCSSStyleSheet.h" #include "CachedResourceLoader.h" #include "Document.h" @@ -34,6 +33,7 @@ #include "FrameLoaderClient.h" #include "FrameTree.h" #include "HTMLNames.h" +#include "HTMLParserIdioms.h" #include "MediaList.h" #include "MediaQueryEvaluator.h" #include "Page.h" @@ -118,7 +118,7 @@ void HTMLLinkElement::parseMappedAttribute(Attribute* attr) tokenizeRelAttribute(attr->value(), m_relAttribute); process(); } else if (attr->name() == hrefAttr) { - m_url = document()->completeURL(deprecatedParseURL(attr->value())); + m_url = document()->completeURL(stripLeadingAndTrailingHTMLSpaces(attr->value())); process(); } else if (attr->name() == typeAttr) { m_type = attr->value(); diff --git a/WebCore/html/HTMLMediaElement.cpp b/WebCore/html/HTMLMediaElement.cpp index 6399f60..3f6c286 100644 --- a/WebCore/html/HTMLMediaElement.cpp +++ b/WebCore/html/HTMLMediaElement.cpp @@ -34,7 +34,6 @@ #include "ClientRect.h" #include "ClientRectList.h" #include "ContentType.h" -#include "CSSHelper.h" #include "CSSPropertyNames.h" #include "CSSValueKeywords.h" #include "Event.h" @@ -126,6 +125,7 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* docum , m_lastTimeUpdateEventMovieTime(numeric_limits<float>::max()) , m_loadState(WaitingForSource) , m_currentSourceNode(0) + , m_nextChildNodeToConsider(0) , m_player(0) #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) , m_proxyWidget(0) @@ -137,7 +137,6 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* docum , m_playing(false) , m_isWaitingUntilMediaCanStart(false) , m_shouldDelayLoadEvent(false) - , m_isWaitingToDecrementLoadEventDelayCount(false) , m_haveFiredLoadedData(false) , m_inActiveDocument(true) , m_autoplaying(true) @@ -157,12 +156,14 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* docum , m_loadInitiatedByUserGesture(false) , m_completelyLoaded(false) { + LOG(Media, "HTMLMediaElement::HTMLMediaElement"); document->registerForDocumentActivationCallbacks(this); document->registerForMediaVolumeCallbacks(this); } HTMLMediaElement::~HTMLMediaElement() { + LOG(Media, "HTMLMediaElement::~HTMLMediaElement"); if (m_isWaitingUntilMediaCanStart) document()->removeMediaCanStartListener(this); setShouldDelayLoadEvent(false); @@ -326,6 +327,7 @@ RenderObject* HTMLMediaElement::createRenderer(RenderArena* arena, RenderStyle*) void HTMLMediaElement::insertedIntoDocument() { + LOG(Media, "HTMLMediaElement::removedFromDocument"); HTMLElement::insertedIntoDocument(); if (!getAttribute(srcAttr).isEmpty() && m_networkState == NETWORK_EMPTY) scheduleLoad(); @@ -333,6 +335,7 @@ void HTMLMediaElement::insertedIntoDocument() void HTMLMediaElement::removedFromDocument() { + LOG(Media, "HTMLMediaElement::removedFromDocument"); if (m_networkState > NETWORK_EMPTY) pause(processingUserGesture()); if (m_isFullscreen) @@ -372,6 +375,7 @@ void HTMLMediaElement::recalcStyle(StyleChange change) void HTMLMediaElement::scheduleLoad() { + LOG(Media, "HTMLMediaElement::scheduleLoad"); #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) createMediaPlayerProxy(); #endif @@ -400,15 +404,6 @@ void HTMLMediaElement::scheduleEvent(const AtomicString& eventName) void HTMLMediaElement::asyncEventTimerFired(Timer<HTMLMediaElement>*) { - // If we are waiting to release our delay on the load event, do that first and post - // the pending events on the next go around. - if (m_isWaitingToDecrementLoadEventDelayCount) { - setShouldDelayLoadEvent(false); - if (!m_asyncEventTimer.isActive()) - m_asyncEventTimer.startOneShot(0); - return; - } - Vector<RefPtr<Event> > pendingEvents; ExceptionCode ec = 0; @@ -541,6 +536,7 @@ void HTMLMediaElement::prepareForLoad() m_displayMode = Unknown; // 1 - Abort any already-running instance of the resource selection algorithm for this element. + m_loadState = WaitingForSource; m_currentSourceNode = 0; // 2 - If there are any tasks from the media element's media element event task source in @@ -879,7 +875,7 @@ void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state) LOG(Media, "HTMLMediaElement::setNetworkState(%d) - current state is %d", static_cast<int>(state), static_cast<int>(m_networkState)); if (state == MediaPlayer::Empty) { - // just update the cached state and leave, we can't do anything + // Just update the cached state and leave, we can't do anything. m_networkState = NETWORK_EMPTY; return; } @@ -890,12 +886,17 @@ void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state) // If we failed while trying to load a <source> element, the movie was never parsed, and there are more // <source> children, schedule the next one if (m_readyState < HAVE_METADATA && m_loadState == LoadingFromSourceElement) { - m_currentSourceNode->scheduleErrorEvent(); + + if (m_currentSourceNode) + m_currentSourceNode->scheduleErrorEvent(); + else + LOG(Media, "HTMLMediaElement::setNetworkState - error event not sent, <source> was removed"); + if (havePotentialSourceChild()) { - LOG(Media, "HTMLMediaElement::setNetworkState scheduling next <source>"); + LOG(Media, "HTMLMediaElement::setNetworkState - scheduling next <source>"); scheduleNextSourceChild(); } else { - LOG(Media, "HTMLMediaElement::setNetworkState no more <source> elements, waiting"); + LOG(Media, "HTMLMediaElement::setNetworkState - no more <source> elements, waiting"); waitForSourceChange(); } @@ -1431,7 +1432,7 @@ float HTMLMediaElement::volume() const void HTMLMediaElement::setVolume(float vol, ExceptionCode& ec) { - LOG(Media, "HTMLMediaElement::setControls(%f)", vol); + LOG(Media, "HTMLMediaElement::setVolume(%f)", vol); if (vol < 0.0f || vol > 1.0f) { ec = INDEX_SIZE_ERR; @@ -1579,11 +1580,15 @@ float HTMLMediaElement::percentLoaded() const bool HTMLMediaElement::havePotentialSourceChild() { - // Stash the current <source> node so we can restore it after checking - // to see there is another potential + // Stash the current <source> node and next nodes so we can restore them after checking + // to see there is another potential. HTMLSourceElement* currentSourceNode = m_currentSourceNode; + Node* nextNode = m_nextChildNodeToConsider; + KURL nextURL = selectNextSourceChild(0, DoNothing); + m_currentSourceNode = currentSourceNode; + m_nextChildNodeToConsider = nextNode; return nextURL.isValid(); } @@ -1597,22 +1602,29 @@ KURL HTMLMediaElement::selectNextSourceChild(ContentType *contentType, InvalidSo LOG(Media, "HTMLMediaElement::selectNextSourceChild(contentType : \"%s\")", contentType ? contentType->raw().utf8().data() : ""); #endif + if (m_nextChildNodeToConsider == sourceChildEndOfListValue()) { +#if !LOG_DISABLED + if (shouldLog) + LOG(Media, "HTMLMediaElement::selectNextSourceChild -> 0x0000, \"\""); +#endif + return KURL(); + } + KURL mediaURL; Node* node; - bool lookingForPreviousNode = m_currentSourceNode; + HTMLSourceElement* source = 0; + bool lookingForStartNode = m_nextChildNodeToConsider; bool canUse = false; for (node = firstChild(); !canUse && node; node = node->nextSibling()) { - if (!node->hasTagName(sourceTag)) + if (lookingForStartNode && m_nextChildNodeToConsider != node) continue; - - if (lookingForPreviousNode) { - if (m_currentSourceNode == static_cast<HTMLSourceElement*>(node)) - lookingForPreviousNode = false; + lookingForStartNode = false; + + if (!node->hasTagName(sourceTag)) continue; - } - HTMLSourceElement* source = static_cast<HTMLSourceElement*>(node); + source = static_cast<HTMLSourceElement*>(node); // If candidate does not have a src attribute, or if its src attribute's value is the empty string ... jump down to the failed step below mediaURL = source->getNonEmptyURLAttribute(srcAttr); @@ -1647,26 +1659,108 @@ KURL HTMLMediaElement::selectNextSourceChild(ContentType *contentType, InvalidSo if (!isSafeToLoadURL(mediaURL, actionIfInvalid) || !dispatchBeforeLoadEvent(mediaURL.string())) goto check_again; - // Making it this far means the <source> looks reasonable + // Making it this far means the <source> looks reasonable. canUse = true; - if (contentType) - *contentType = ContentType(source->type()); check_again: if (!canUse && actionIfInvalid == Complain) source->scheduleErrorEvent(); - m_currentSourceNode = static_cast<HTMLSourceElement*>(node); } - if (!canUse) + if (canUse) { + if (contentType) + *contentType = ContentType(source->type()); + m_currentSourceNode = source; + m_nextChildNodeToConsider = source->nextSibling(); + if (!m_nextChildNodeToConsider) + m_nextChildNodeToConsider = sourceChildEndOfListValue(); + } else { m_currentSourceNode = 0; + m_nextChildNodeToConsider = sourceChildEndOfListValue(); + } + #if !LOG_DISABLED if (shouldLog) - LOG(Media, "HTMLMediaElement::selectNextSourceChild -> %s", canUse ? urlForLogging(mediaURL.string()).utf8().data() : ""); + LOG(Media, "HTMLMediaElement::selectNextSourceChild -> %p, %s", m_currentSourceNode, canUse ? urlForLogging(mediaURL.string()).utf8().data() : ""); #endif return canUse ? mediaURL : KURL(); } +void HTMLMediaElement::sourceWasAdded(HTMLSourceElement* source) +{ + LOG(Media, "HTMLMediaElement::sourceWasAdded(%p)", source); + +#if !LOG_DISABLED + if (source->hasTagName(sourceTag)) { + KURL url = source->getNonEmptyURLAttribute(srcAttr); + LOG(Media, "HTMLMediaElement::sourceWasAdded - 'src' is %s", urlForLogging(url).utf8().data()); + } +#endif + + // We should only consider a <source> element when there is not src attribute at all. + if (hasAttribute(srcAttr)) + return; + + // 4.8.8 - If a source element is inserted as a child of a media element that has no src + // attribute and whose networkState has the value NETWORK_EMPTY, the user agent must invoke + // the media element's resource selection algorithm. + if (networkState() == HTMLMediaElement::NETWORK_EMPTY) { + scheduleLoad(); + return; + } + + if (m_currentSourceNode && source == m_currentSourceNode->nextSibling()) { + LOG(Media, "HTMLMediaElement::sourceWasAdded - <source> inserted immediately after current source"); + m_nextChildNodeToConsider = source; + return; + } + + if (m_nextChildNodeToConsider != sourceChildEndOfListValue()) + return; + + // 4.8.9.5, resource selection algorithm, source elements section: + // 20 - Wait until the node after pointer is a node other than the end of the list. (This step might wait forever.) + // 21 - Asynchronously await a stable state... + // 22 - Set the element's delaying-the-load-event flag back to true (this delays the load event again, in case + // it hasn't been fired yet). + setShouldDelayLoadEvent(true); + + // 23 - Set the networkState back to NETWORK_LOADING. + m_networkState = NETWORK_LOADING; + + // 24 - Jump back to the find next candidate step above. + m_nextChildNodeToConsider = source; + scheduleNextSourceChild(); +} + +void HTMLMediaElement::sourceWillBeRemoved(HTMLSourceElement* source) +{ + LOG(Media, "HTMLMediaElement::sourceWillBeRemoved(%p)", source); + +#if !LOG_DISABLED + if (source->hasTagName(sourceTag)) { + KURL url = source->getNonEmptyURLAttribute(srcAttr); + LOG(Media, "HTMLMediaElement::sourceWillBeRemoved - 'src' is %s", urlForLogging(url).utf8().data()); + } +#endif + + if (source != m_currentSourceNode && source != m_nextChildNodeToConsider) + return; + + if (source == m_nextChildNodeToConsider) { + m_nextChildNodeToConsider = m_nextChildNodeToConsider->nextSibling(); + if (!m_nextChildNodeToConsider) + m_nextChildNodeToConsider = sourceChildEndOfListValue(); + LOG(Media, "HTMLMediaElement::sourceRemoved - m_nextChildNodeToConsider set to %p", m_nextChildNodeToConsider); + } else if (source == m_currentSourceNode) { + // Clear the current source node pointer, but don't change the movie as the spec says: + // 4.8.8 - Dynamically modifying a source element and its attribute when the element is already + // inserted in a video or audio element will have no effect. + m_currentSourceNode = 0; + LOG(Media, "HTMLMediaElement::sourceRemoved - m_currentSourceNode set to 0"); + } +} + void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*) { LOG(Media, "HTMLMediaElement::mediaPlayerTimeChanged"); @@ -2003,6 +2097,7 @@ void HTMLMediaElement::userCancelledLoad() m_player.clear(); #endif stopPeriodicTimers(); + m_loadState = WaitingForSource; // 2 - Set the error attribute to a new MediaError object whose code attribute is set to MEDIA_ERR_ABORTED. m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED); @@ -2338,24 +2433,9 @@ void HTMLMediaElement::setShouldDelayLoadEvent(bool shouldDelay) if (m_shouldDelayLoadEvent == shouldDelay) return; - // Don't decrement the load event delay if we are in the middle of a callback from - // the media engine. The load event is sent synchronously and may trigger a script that - // causes the document to be come inactive and that will clear the media engine, causing - // the return to be a rough one. - if (!shouldDelay && processingMediaPlayerCallback()) { - m_isWaitingToDecrementLoadEventDelayCount = true; - - // Instead of creating yet-another-timer, reuse the async event timer which is always - // used as a one-shot. - if (!m_asyncEventTimer.isActive()) - m_asyncEventTimer.startOneShot(0); - return; - } - LOG(Media, "HTMLMediaElement::setShouldDelayLoadEvent(%s)", boolString(shouldDelay)); m_shouldDelayLoadEvent = shouldDelay; - m_isWaitingToDecrementLoadEventDelayCount = false; if (shouldDelay) document()->incrementLoadEventDelayCount(); else diff --git a/WebCore/html/HTMLMediaElement.h b/WebCore/html/HTMLMediaElement.h index db75a9c..e5e7ae0 100644 --- a/WebCore/html/HTMLMediaElement.h +++ b/WebCore/html/HTMLMediaElement.h @@ -169,6 +169,9 @@ public: bool processingUserGesture() const; + void sourceWillBeRemoved(HTMLSourceElement*); + void sourceWasAdded(HTMLSourceElement*); + protected: HTMLMediaElement(const QualifiedName&, Document*); virtual ~HTMLMediaElement(); @@ -331,7 +334,9 @@ private: enum LoadState { WaitingForSource, LoadingFromSrcAttr, LoadingFromSourceElement }; LoadState m_loadState; HTMLSourceElement* m_currentSourceNode; - + Node* m_nextChildNodeToConsider; + Node* sourceChildEndOfListValue() { return static_cast<Node*>(this); } + OwnPtr<MediaPlayer> m_player; #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) RefPtr<Widget> m_proxyWidget; @@ -350,7 +355,6 @@ private: bool m_playing : 1; bool m_isWaitingUntilMediaCanStart : 1; bool m_shouldDelayLoadEvent : 1; - bool m_isWaitingToDecrementLoadEventDelayCount : 1; bool m_haveFiredLoadedData : 1; bool m_inActiveDocument : 1; bool m_autoplaying : 1; diff --git a/WebCore/html/HTMLObjectElement.cpp b/WebCore/html/HTMLObjectElement.cpp index e9c6f60..2b51286 100644 --- a/WebCore/html/HTMLObjectElement.cpp +++ b/WebCore/html/HTMLObjectElement.cpp @@ -25,7 +25,6 @@ #include "HTMLObjectElement.h" #include "Attribute.h" -#include "CSSHelper.h" #include "EventNames.h" #include "ExceptionCode.h" #include "Frame.h" @@ -34,6 +33,7 @@ #include "HTMLImageLoader.h" #include "HTMLNames.h" #include "HTMLParamElement.h" +#include "HTMLParserIdioms.h" #include "MIMETypeRegistry.h" #include "RenderEmbeddedObject.h" #include "RenderImage.h" @@ -77,7 +77,7 @@ void HTMLObjectElement::parseMappedAttribute(Attribute* attr) if (!isImageType() && m_imageLoader) m_imageLoader.clear(); } else if (attr->name() == dataAttr) { - m_url = deprecatedParseURL(attr->value()); + m_url = stripLeadingAndTrailingHTMLSpaces(attr->value()); if (renderer()) { setNeedsWidgetUpdate(true); if (isImageType()) { @@ -182,7 +182,7 @@ void HTMLObjectElement::parametersForPlugin(Vector<String>& paramNames, Vector<S // FIXME: url adjustment does not belong in this function. if (url.isEmpty() && urlParameter.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url"))) - urlParameter = deprecatedParseURL(p->value()); + urlParameter = stripLeadingAndTrailingHTMLSpaces(p->value()); // FIXME: serviceType calculation does not belong in this function. if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) { serviceType = p->value(); @@ -279,7 +279,10 @@ void HTMLObjectElement::updateWidget(bool onlyCreateNonNetscapePlugins) if (onlyCreateNonNetscapePlugins && wouldLoadAsNetscapePlugin(url, serviceType)) return; + ASSERT(!m_inBeforeLoadEventHandler); + m_inBeforeLoadEventHandler = true; bool beforeLoadAllowedLoad = dispatchBeforeLoadEvent(url); + m_inBeforeLoadEventHandler = false; // beforeload events can modify the DOM, potentially causing // RenderWidget::destroy() to be called. Ensure we haven't been diff --git a/WebCore/html/HTMLOptGroupElement.cpp b/WebCore/html/HTMLOptGroupElement.cpp index 091e0f2..987eb51 100644 --- a/WebCore/html/HTMLOptGroupElement.cpp +++ b/WebCore/html/HTMLOptGroupElement.cpp @@ -79,7 +79,7 @@ void HTMLOptGroupElement::parseMappedAttribute(Attribute* attr) void HTMLOptGroupElement::recalcSelectOptions() { - Node* select = parentNode(); + ContainerNode* select = parentNode(); while (select && !select->hasTagName(selectTag)) select = select->parentNode(); if (select) @@ -123,7 +123,7 @@ String HTMLOptGroupElement::groupLabelText() const HTMLSelectElement* HTMLOptGroupElement::ownerSelectElement() const { - Node* select = parentNode(); + ContainerNode* select = parentNode(); while (select && !select->hasTagName(selectTag)) select = select->parentNode(); diff --git a/WebCore/html/HTMLOptionElement.cpp b/WebCore/html/HTMLOptionElement.cpp index 3bf522c..67c3567 100644 --- a/WebCore/html/HTMLOptionElement.cpp +++ b/WebCore/html/HTMLOptionElement.cpp @@ -193,7 +193,7 @@ void HTMLOptionElement::childrenChanged(bool changedByParser, Node* beforeChange HTMLSelectElement* HTMLOptionElement::ownerSelectElement() const { - Node* select = parentNode(); + ContainerNode* select = parentNode(); while (select && !(select->hasTagName(selectTag) || select->hasTagName(keygenTag))) select = select->parentNode(); diff --git a/WebCore/html/HTMLPlugInElement.cpp b/WebCore/html/HTMLPlugInElement.cpp index 25ef751..bf2722b 100644 --- a/WebCore/html/HTMLPlugInElement.cpp +++ b/WebCore/html/HTMLPlugInElement.cpp @@ -49,10 +49,11 @@ using namespace HTMLNames; HTMLPlugInElement::HTMLPlugInElement(const QualifiedName& tagName, Document* doc) : HTMLFrameOwnerElement(tagName, doc) + , m_inBeforeLoadEventHandler(false) #if ENABLE(NETSCAPE_PLUGIN_API) , m_NPObject(0) - , m_isCapturingMouseEvents(false) #endif + , m_isCapturingMouseEvents(false) { } @@ -100,6 +101,12 @@ PassScriptInstance HTMLPlugInElement::getInstance() const Widget* HTMLPlugInElement::pluginWidget() const { + if (m_inBeforeLoadEventHandler) { + // The plug-in hasn't loaded yet, and it makes no sense to try to load if beforeload handler happened to touch the plug-in element. + // That would recursively call beforeload for the same element. + return 0; + } + RenderWidget* renderWidget = renderWidgetForJSBindings(); if (!renderWidget) return 0; diff --git a/WebCore/html/HTMLPlugInElement.h b/WebCore/html/HTMLPlugInElement.h index 5467177..44c6149 100644 --- a/WebCore/html/HTMLPlugInElement.h +++ b/WebCore/html/HTMLPlugInElement.h @@ -59,11 +59,15 @@ protected: virtual bool mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const; virtual void parseMappedAttribute(Attribute*); +<<<<<<< HEAD #if PLATFORM(ANDROID) // in Android, plugin has a focused mode where it accepts all the touch events. // so need to claim that plugin element supports focus instead of using the default. virtual bool supportsFocus() const; #endif +======= + bool m_inBeforeLoadEventHandler; +>>>>>>> webkit.org at r70209 private: virtual void defaultEventHandler(Event*); diff --git a/WebCore/html/HTMLSourceElement.cpp b/WebCore/html/HTMLSourceElement.cpp index 96c9829..59b3882 100644 --- a/WebCore/html/HTMLSourceElement.cpp +++ b/WebCore/html/HTMLSourceElement.cpp @@ -33,6 +33,7 @@ #include "HTMLDocument.h" #include "HTMLMediaElement.h" #include "HTMLNames.h" +#include "Logging.h" using namespace std; @@ -44,6 +45,7 @@ inline HTMLSourceElement::HTMLSourceElement(const QualifiedName& tagName, Docume : HTMLElement(tagName, document) , m_errorEventTimer(this, &HTMLSourceElement::errorEventTimerFired) { + LOG(Media, "HTMLSourceElement::HTMLSourceElement - %p", this); ASSERT(hasTagName(sourceTag)); } @@ -55,13 +57,17 @@ PassRefPtr<HTMLSourceElement> HTMLSourceElement::create(const QualifiedName& tag void HTMLSourceElement::insertedIntoTree(bool deep) { HTMLElement::insertedIntoTree(deep); - if (parentNode() && (parentNode()->hasTagName(audioTag) || parentNode()->hasTagName(videoTag))) { - HTMLMediaElement* media = static_cast<HTMLMediaElement*>(parentNode()); - if (media->networkState() == HTMLMediaElement::NETWORK_EMPTY) - media->scheduleLoad(); - } + if (parentNode() && (parentNode()->hasTagName(audioTag) || parentNode()->hasTagName(videoTag))) + static_cast<HTMLMediaElement*>(parentNode())->sourceWasAdded(this); } +void HTMLSourceElement::willRemove() +{ + if (parentNode() && (parentNode()->hasTagName(audioTag) || parentNode()->hasTagName(videoTag))) + static_cast<HTMLMediaElement*>(parentNode())->sourceWillBeRemoved(this); + HTMLElement::willRemove(); +} + void HTMLSourceElement::setSrc(const String& url) { setAttribute(srcAttr, url); @@ -89,6 +95,7 @@ void HTMLSourceElement::setType(const String& type) void HTMLSourceElement::scheduleErrorEvent() { + LOG(Media, "HTMLSourceElement::scheduleErrorEvent - %p", this); if (m_errorEventTimer.isActive()) return; @@ -97,11 +104,13 @@ void HTMLSourceElement::scheduleErrorEvent() void HTMLSourceElement::cancelPendingErrorEvent() { + LOG(Media, "HTMLSourceElement::cancelPendingErrorEvent - %p", this); m_errorEventTimer.stop(); } void HTMLSourceElement::errorEventTimerFired(Timer<HTMLSourceElement>*) { + LOG(Media, "HTMLSourceElement::errorEventTimerFired - %p", this); dispatchEvent(Event::create(eventNames().errorEvent, false, true)); } diff --git a/WebCore/html/HTMLSourceElement.h b/WebCore/html/HTMLSourceElement.h index 8aa1d06..cc1e5d7 100644 --- a/WebCore/html/HTMLSourceElement.h +++ b/WebCore/html/HTMLSourceElement.h @@ -50,6 +50,7 @@ private: HTMLSourceElement(const QualifiedName&, Document*); virtual void insertedIntoTree(bool); + virtual void willRemove(); virtual bool isURLAttribute(Attribute*) const; void errorEventTimerFired(Timer<HTMLSourceElement>*); diff --git a/WebCore/html/HTMLTableCellElement.cpp b/WebCore/html/HTMLTableCellElement.cpp index d90b125..0bd3cf5 100644 --- a/WebCore/html/HTMLTableCellElement.cpp +++ b/WebCore/html/HTMLTableCellElement.cpp @@ -123,7 +123,7 @@ void HTMLTableCellElement::parseMappedAttribute(Attribute* attr) // used by table cells to share style decls created by the enclosing table. void HTMLTableCellElement::additionalAttributeStyleDecls(Vector<CSSMutableStyleDeclaration*>& results) { - Node* p = parentNode(); + ContainerNode* p = parentNode(); while (p && !p->hasTagName(tableTag)) p = p->parentNode(); if (!p) @@ -173,4 +173,20 @@ void HTMLTableCellElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) addSubresourceURL(urls, document()->completeURL(getAttribute(backgroundAttr))); } +HTMLTableCellElement* HTMLTableCellElement::cellAbove() const +{ + RenderObject* cellRenderer = renderer(); + if (!cellRenderer) + return 0; + if (!cellRenderer->isTableCell()) + return 0; + + RenderTableCell* tableCellRenderer = toRenderTableCell(cellRenderer); + RenderTableCell* cellAboveRenderer = tableCellRenderer->table()->cellAbove(tableCellRenderer); + if (!cellAboveRenderer) + return 0; + + return static_cast<HTMLTableCellElement*>(cellAboveRenderer->node()); } + +} // namespace WebCore diff --git a/WebCore/html/HTMLTableCellElement.h b/WebCore/html/HTMLTableCellElement.h index 0c97413..f6d202b 100644 --- a/WebCore/html/HTMLTableCellElement.h +++ b/WebCore/html/HTMLTableCellElement.h @@ -53,6 +53,8 @@ public: void setRowSpan(int); String scope() const; + HTMLTableCellElement* cellAbove() const; + private: HTMLTableCellElement(const QualifiedName&, Document*); diff --git a/WebCore/html/HTMLTableColElement.cpp b/WebCore/html/HTMLTableColElement.cpp index 20b0f36..96af708 100644 --- a/WebCore/html/HTMLTableColElement.cpp +++ b/WebCore/html/HTMLTableColElement.cpp @@ -82,7 +82,7 @@ void HTMLTableColElement::additionalAttributeStyleDecls(Vector<CSSMutableStyleDe { if (!hasLocalName(colgroupTag)) return; - Node* p = parentNode(); + ContainerNode* p = parentNode(); while (p && !p->hasTagName(tableTag)) p = p->parentNode(); if (!p) diff --git a/WebCore/html/HTMLTableElement.cpp b/WebCore/html/HTMLTableElement.cpp index ef29bf6..fe823ea 100644 --- a/WebCore/html/HTMLTableElement.cpp +++ b/WebCore/html/HTMLTableElement.cpp @@ -31,6 +31,7 @@ #include "CSSValueKeywords.h" #include "ExceptionCode.h" #include "HTMLNames.h" +#include "HTMLParserIdioms.h" #include "HTMLTableCaptionElement.h" #include "HTMLTableRowElement.h" #include "HTMLTableRowsCollection.h" @@ -202,7 +203,7 @@ PassRefPtr<HTMLElement> HTMLTableElement::insertRow(int index, ExceptionCode& ec } } - Node* parent; + ContainerNode* parent; if (lastRow) parent = row ? row->parent() : lastRow->parent(); else { @@ -336,7 +337,7 @@ void HTMLTableElement::parseMappedAttribute(Attribute* attr) m_borderColorAttr = true; } } else if (attr->name() == backgroundAttr) { - String url = deprecatedParseURL(attr->value()); + String url = stripLeadingAndTrailingHTMLSpaces(attr->value()); if (!url.isEmpty()) addCSSImageProperty(attr, CSSPropertyBackgroundImage, document()->completeURL(url).string()); } else if (attr->name() == frameAttr) { diff --git a/WebCore/html/HTMLTablePartElement.cpp b/WebCore/html/HTMLTablePartElement.cpp index 316ace4..dfaecca 100644 --- a/WebCore/html/HTMLTablePartElement.cpp +++ b/WebCore/html/HTMLTablePartElement.cpp @@ -26,11 +26,11 @@ #include "HTMLTablePartElement.h" #include "Attribute.h" -#include "CSSHelper.h" #include "CSSPropertyNames.h" #include "CSSValueKeywords.h" #include "Document.h" #include "HTMLNames.h" +#include "HTMLParserIdioms.h" namespace WebCore { @@ -64,7 +64,7 @@ void HTMLTablePartElement::parseMappedAttribute(Attribute* attr) if (attr->name() == bgcolorAttr) addCSSColor(attr, CSSPropertyBackgroundColor, attr->value()); else if (attr->name() == backgroundAttr) { - String url = deprecatedParseURL(attr->value()); + String url = stripLeadingAndTrailingHTMLSpaces(attr->value()); if (!url.isEmpty()) addCSSImageProperty(attr, CSSPropertyBackgroundImage, document()->completeURL(url).string()); } else if (attr->name() == bordercolorAttr) { diff --git a/WebCore/html/HTMLTableRowElement.cpp b/WebCore/html/HTMLTableRowElement.cpp index e9b5cec..fbc253d 100644 --- a/WebCore/html/HTMLTableRowElement.cpp +++ b/WebCore/html/HTMLTableRowElement.cpp @@ -56,7 +56,7 @@ PassRefPtr<HTMLTableRowElement> HTMLTableRowElement::create(const QualifiedName& int HTMLTableRowElement::rowIndex() const { - Node *table = parentNode(); + ContainerNode* table = parentNode(); if (!table) return -1; table = table->parentNode(); diff --git a/WebCore/html/HTMLTableSectionElement.cpp b/WebCore/html/HTMLTableSectionElement.cpp index 982e035..5ef25f1 100644 --- a/WebCore/html/HTMLTableSectionElement.cpp +++ b/WebCore/html/HTMLTableSectionElement.cpp @@ -50,7 +50,7 @@ PassRefPtr<HTMLTableSectionElement> HTMLTableSectionElement::create(const Qualif // used by table row groups to share style decls created by the enclosing table. void HTMLTableSectionElement::additionalAttributeStyleDecls(Vector<CSSMutableStyleDeclaration*>& results) { - Node* p = parentNode(); + ContainerNode* p = parentNode(); while (p && !p->hasTagName(tableTag)) p = p->parentNode(); if (!p) diff --git a/WebCore/html/HTMLVideoElement.cpp b/WebCore/html/HTMLVideoElement.cpp index 219bb85..bbda53a 100644 --- a/WebCore/html/HTMLVideoElement.cpp +++ b/WebCore/html/HTMLVideoElement.cpp @@ -29,7 +29,6 @@ #include "HTMLVideoElement.h" #include "Attribute.h" -#include "CSSHelper.h" #include "CSSPropertyNames.h" #include "Chrome.h" #include "ChromeClient.h" diff --git a/WebCore/html/HiddenInputType.cpp b/WebCore/html/HiddenInputType.cpp index d97fe3a..76742ae 100644 --- a/WebCore/html/HiddenInputType.cpp +++ b/WebCore/html/HiddenInputType.cpp @@ -44,4 +44,9 @@ const AtomicString& HiddenInputType::formControlType() const { return InputTypeNames::hidden(); } +bool HiddenInputType::supportsValidation() const +{ + return false; +} + } // namespace WebCore diff --git a/WebCore/html/HiddenInputType.h b/WebCore/html/HiddenInputType.h index 564f99e..cc49f98 100644 --- a/WebCore/html/HiddenInputType.h +++ b/WebCore/html/HiddenInputType.h @@ -42,6 +42,7 @@ public: private: HiddenInputType(HTMLInputElement* element) : InputType(element) { } virtual const AtomicString& formControlType() const; + virtual bool supportsValidation() const; }; } // namespace WebCore diff --git a/WebCore/html/ImageDocument.cpp b/WebCore/html/ImageDocument.cpp index db53837..6361f43 100644 --- a/WebCore/html/ImageDocument.cpp +++ b/WebCore/html/ImageDocument.cpp @@ -32,6 +32,7 @@ #include "Frame.h" #include "FrameLoaderClient.h" #include "FrameView.h" +#include "HTMLHtmlElement.h" #include "HTMLImageElement.h" #include "HTMLNames.h" #include "LocalizedStrings.h" @@ -194,6 +195,9 @@ void ImageDocument::createDocumentStructure() RefPtr<Element> rootElement = Document::createElement(htmlTag, false); appendChild(rootElement, ec); +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + static_cast<HTMLHtmlElement*>(rootElement.get())->insertedByParser(); +#endif if (frame() && frame()->loader()) frame()->loader()->dispatchDocumentElementAvailable(); diff --git a/WebCore/html/ImageInputType.cpp b/WebCore/html/ImageInputType.cpp index 78b3981..604b052 100644 --- a/WebCore/html/ImageInputType.cpp +++ b/WebCore/html/ImageInputType.cpp @@ -45,4 +45,9 @@ const AtomicString& ImageInputType::formControlType() const return InputTypeNames::image(); } +bool ImageInputType::supportsValidation() const +{ + return false; +} + } // namespace WebCore diff --git a/WebCore/html/ImageInputType.h b/WebCore/html/ImageInputType.h index 00ac77b..be308b3 100644 --- a/WebCore/html/ImageInputType.h +++ b/WebCore/html/ImageInputType.h @@ -42,6 +42,7 @@ public: private: ImageInputType(HTMLInputElement* element) : InputType(element) { } virtual const AtomicString& formControlType() const; + virtual bool supportsValidation() const; }; } // namespace WebCore diff --git a/WebCore/html/InputType.cpp b/WebCore/html/InputType.cpp index c3435f7..1b2303a 100644 --- a/WebCore/html/InputType.cpp +++ b/WebCore/html/InputType.cpp @@ -30,6 +30,7 @@ #include "ButtonInputType.h" #include "CheckboxInputType.h" #include "ColorInputType.h" +#include "DateComponents.h" #include "DateInputType.h" #include "DateTimeInputType.h" #include "DateTimeLocalInputType.h" @@ -53,11 +54,15 @@ #include "TimeInputType.h" #include "URLInputType.h" #include "WeekInputType.h" +#include <limits> +#include <wtf/Assertions.h> #include <wtf/HashMap.h> #include <wtf/text/StringHash.h> namespace WebCore { +using namespace std; + typedef HashMap<String, PassOwnPtr<InputType> (*)(HTMLInputElement*), CaseFoldingHash> InputTypeFactoryMap; static PassOwnPtr<InputTypeFactoryMap> createInputTypeFactoryMap() { @@ -117,11 +122,130 @@ bool InputType::isTextType() const return false; } +double InputType::valueAsDate() const +{ + return DateComponents::invalidMilliseconds(); +} + +void InputType::setValueAsDate(double, ExceptionCode& ec) const +{ + ec = INVALID_STATE_ERR; +} + +double InputType::valueAsNumber() const +{ + return numeric_limits<double>::quiet_NaN(); +} + +void InputType::setValueAsNumber(double, ExceptionCode& ec) const +{ + ec = INVALID_STATE_ERR; +} + +bool InputType::supportsValidation() const +{ + return true; +} + +bool InputType::typeMismatchFor(const String&) const +{ + return false; +} + +bool InputType::typeMismatch() const +{ + return false; +} + +bool InputType::supportsRequired() const +{ + // Almost all validatable types support @required. + return supportsValidation(); +} + +bool InputType::valueMissing(const String&) const +{ + return false; +} + bool InputType::patternMismatch(const String&) const { return false; } +bool InputType::rangeUnderflow(const String&) const +{ + return false; +} + +bool InputType::rangeOverflow(const String&) const +{ + return false; +} + +double InputType::minimum() const +{ + ASSERT_NOT_REACHED(); + return 0; +} + +double InputType::maximum() const +{ + ASSERT_NOT_REACHED(); + return 0; +} + +bool InputType::stepMismatch(const String&, double) const +{ + // Non-supported types should be rejected by HTMLInputElement::getAllowedValueStep(). + ASSERT_NOT_REACHED(); + return false; +} + +double InputType::stepBase() const +{ + ASSERT_NOT_REACHED(); + return 0; +} + +double InputType::defaultStep() const +{ + return numeric_limits<double>::quiet_NaN(); +} + +double InputType::stepScaleFactor() const +{ + return numeric_limits<double>::quiet_NaN(); +} + +bool InputType::parsedStepValueShouldBeInteger() const +{ + return false; +} + +bool InputType::scaledStepValeuShouldBeInteger() const +{ + return false; +} + +double InputType::parseToDouble(const String&, double defaultValue) const +{ + return defaultValue; +} + +bool InputType::parseToDateComponents(const String&, DateComponents*) const +{ + ASSERT_NOT_REACHED(); + return false; +} + +String InputType::serialize(double) const +{ + ASSERT_NOT_REACHED(); + return String(); +} + + namespace InputTypeNames { // The type names must be lowercased because they will be the return values of diff --git a/WebCore/html/InputType.h b/WebCore/html/InputType.h index 3141f34..953b123 100644 --- a/WebCore/html/InputType.h +++ b/WebCore/html/InputType.h @@ -31,11 +31,13 @@ #ifndef InputType_h #define InputType_h +#include "ExceptionCode.h" #include <wtf/Forward.h> #include <wtf/Noncopyable.h> namespace WebCore { +class DateComponents; class HTMLInputElement; class InputType : public Noncopyable { @@ -48,11 +50,53 @@ public: virtual bool isTextType() const; virtual const AtomicString& formControlType() const = 0; + virtual double valueAsDate() const; + virtual void setValueAsDate(double, ExceptionCode&) const; + virtual double valueAsNumber() const; + virtual void setValueAsNumber(double, ExceptionCode&) const; + + // Validation-related functions + + virtual bool supportsValidation() const; + virtual bool typeMismatchFor(const String&) const; + // Type check for the current input value. We do nothing for some types + // though typeMismatchFor() does something for them because of value + // sanitization. + virtual bool typeMismatch() const; + virtual bool supportsRequired() const; + virtual bool valueMissing(const String&) const; virtual bool patternMismatch(const String&) const; + virtual bool rangeUnderflow(const String&) const; + virtual bool rangeOverflow(const String&) const; + virtual double minimum() const; + virtual double maximum() const; + virtual bool stepMismatch(const String&, double) const; + virtual double stepBase() const; + virtual double defaultStep() const; + virtual double stepScaleFactor() const; + virtual bool parsedStepValueShouldBeInteger() const; + virtual bool scaledStepValeuShouldBeInteger() const; + + // Parses the specified string for the type, and return + // the double value for the parsing result if the parsing + // succeeds; Returns defaultValue otherwise. This function can + // return NaN or Infinity only if defaultValue is NaN or Infinity. + virtual double parseToDouble(const String&, double defaultValue) const; + // Parses the specified string for this InputType, and returns true if it + // is successfully parsed. An instance pointed by the DateComponents* + // parameter will have parsed values and be modified even if the parsing + // fails. The DateComponents* parameter may be 0. + virtual bool parseToDateComponents(const String&, DateComponents*) const; + // Create a string representation of the specified double value for the + // input type. If NaN or Infinity is specified, this returns an empty + // string. This should not be called for types without valueAsNumber. + virtual String serialize(double) const; protected: InputType(HTMLInputElement* element) : m_element(element) { } HTMLInputElement* element() const { return m_element; } + // We can't make this a static const data member because VC++ doesn't like it. + static double defaultStepBase() { return 0.0; } private: // Raw pointer because the HTMLInputElement object owns this InputType object. diff --git a/WebCore/html/IsIndexInputType.cpp b/WebCore/html/IsIndexInputType.cpp index 80e0617..c3cff41 100644 --- a/WebCore/html/IsIndexInputType.cpp +++ b/WebCore/html/IsIndexInputType.cpp @@ -45,4 +45,9 @@ const AtomicString& IsIndexInputType::formControlType() const return emptyAtom; } +bool IsIndexInputType::supportsRequired() const +{ + return false; +} + } // namespace WebCore diff --git a/WebCore/html/IsIndexInputType.h b/WebCore/html/IsIndexInputType.h index 93a1c08..2d4e193 100644 --- a/WebCore/html/IsIndexInputType.h +++ b/WebCore/html/IsIndexInputType.h @@ -43,6 +43,7 @@ public: private: IsIndexInputType(HTMLInputElement* element) : TextFieldInputType(element) { }; virtual const AtomicString& formControlType() const; + virtual bool supportsRequired() const; }; } // namespace WebCore diff --git a/WebCore/html/MediaDocument.cpp b/WebCore/html/MediaDocument.cpp index 875141b..c4f0b14 100644 --- a/WebCore/html/MediaDocument.cpp +++ b/WebCore/html/MediaDocument.cpp @@ -33,6 +33,7 @@ #include "Frame.h" #include "FrameLoaderClient.h" #include "HTMLEmbedElement.h" +#include "HTMLHtmlElement.h" #include "HTMLNames.h" #include "HTMLVideoElement.h" #include "KeyboardEvent.h" @@ -71,6 +72,9 @@ void MediaDocumentParser::createDocumentStructure() ExceptionCode ec; RefPtr<Element> rootElement = document()->createElement(htmlTag, false); document()->appendChild(rootElement, ec); +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + static_cast<HTMLHtmlElement*>(rootElement.get())->insertedByParser(); +#endif if (document()->frame()) document()->frame()->loader()->dispatchDocumentElementAvailable(); diff --git a/WebCore/html/MonthInputType.cpp b/WebCore/html/MonthInputType.cpp index 54f78c6..cbde5cb 100644 --- a/WebCore/html/MonthInputType.cpp +++ b/WebCore/html/MonthInputType.cpp @@ -31,10 +31,19 @@ #include "config.h" #include "MonthInputType.h" +#include "DateComponents.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" +#include <wtf/MathExtras.h> #include <wtf/PassOwnPtr.h> namespace WebCore { +using namespace HTMLNames; + +static const double monthDefaultStep = 1.0; +static const double monthStepScaleFactor = 1.0; + PassOwnPtr<InputType> MonthInputType::create(HTMLInputElement* element) { return adoptPtr(new MonthInputType(element)); @@ -45,4 +54,72 @@ const AtomicString& MonthInputType::formControlType() const return InputTypeNames::month(); } +double MonthInputType::valueAsDate() const +{ + DateComponents date; + if (!parseToDateComponents(element()->value(), &date)) + return DateComponents::invalidMilliseconds(); + double msec = date.millisecondsSinceEpoch(); + ASSERT(isfinite(msec)); + return msec; +} + +void MonthInputType::setValueAsDate(double value, ExceptionCode&) const +{ + DateComponents date; + if (!date.setMillisecondsSinceEpochForMonth(value)) { + element()->setValue(String()); + return; + } + element()->setValue(date.toString()); +} + +double MonthInputType::minimum() const +{ + return parseToDouble(element()->fastGetAttribute(minAttr), DateComponents::minimumMonth()); +} + +double MonthInputType::maximum() const +{ + return parseToDouble(element()->fastGetAttribute(maxAttr), DateComponents::maximumMonth()); +} + +double MonthInputType::defaultStep() const +{ + return monthDefaultStep; +} + +double MonthInputType::stepScaleFactor() const +{ + return monthStepScaleFactor; +} + +bool MonthInputType::parsedStepValueShouldBeInteger() const +{ + return true; +} + +double MonthInputType::parseToDouble(const String& src, double defaultValue) const +{ + DateComponents date; + if (!parseToDateComponents(src, &date)) + return defaultValue; + double months = date.monthsSinceEpoch(); + ASSERT(isfinite(months)); + return months; +} + +bool MonthInputType::parseToDateComponentsInternal(const UChar* characters, unsigned length, DateComponents* out) const +{ + ASSERT(out); + unsigned end; + return out->parseMonth(characters, length, 0, end) && end == length; +} + +bool MonthInputType::setMillisecondToDateComponents(double value, DateComponents* date) const +{ + ASSERT(date); + return date->setMonthsSinceEpoch(value); +} + } // namespace WebCore diff --git a/WebCore/html/MonthInputType.h b/WebCore/html/MonthInputType.h index d605ffa..50cf7d5 100644 --- a/WebCore/html/MonthInputType.h +++ b/WebCore/html/MonthInputType.h @@ -31,17 +31,27 @@ #ifndef MonthInputType_h #define MonthInputType_h -#include "TextFieldInputType.h" +#include "BaseDateAndTimeInputType.h" namespace WebCore { -class MonthInputType : public TextFieldInputType { +class MonthInputType : public BaseDateAndTimeInputType { public: static PassOwnPtr<InputType> create(HTMLInputElement*); private: - MonthInputType(HTMLInputElement* element) : TextFieldInputType(element) { } + MonthInputType(HTMLInputElement* element) : BaseDateAndTimeInputType(element) { } virtual const AtomicString& formControlType() const; + virtual double valueAsDate() const; + virtual void setValueAsDate(double, ExceptionCode&) const; + virtual double parseToDouble(const String&, double) const; + virtual double minimum() const; + virtual double maximum() const; + virtual double defaultStep() const; + virtual double stepScaleFactor() const; + virtual bool parsedStepValueShouldBeInteger() const; + virtual bool parseToDateComponentsInternal(const UChar*, unsigned length, DateComponents*) const; + virtual bool setMillisecondToDateComponents(double, DateComponents*) const; }; } // namespace WebCore diff --git a/WebCore/html/NumberInputType.cpp b/WebCore/html/NumberInputType.cpp index 9aba5c3..a4e118c 100644 --- a/WebCore/html/NumberInputType.cpp +++ b/WebCore/html/NumberInputType.cpp @@ -31,10 +31,27 @@ #include "config.h" #include "NumberInputType.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" +#include "HTMLParserIdioms.h" +#include <limits> +#include <wtf/MathExtras.h> #include <wtf/PassOwnPtr.h> namespace WebCore { +using namespace HTMLNames; +using namespace std; + +// FIXME: Number values should be in the range of IEEE 754 single-precision +// floating point number. +// http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#real-numbers +static const double numberDefaultMinimum = -DBL_MAX; +static const double numberDefaultMaximum = DBL_MAX; + +static const double numberDefaultStep = 1.0; +static const double numberStepScaleFactor = 1.0; + PassOwnPtr<InputType> NumberInputType::create(HTMLInputElement* element) { return adoptPtr(new NumberInputType(element)); @@ -45,4 +62,98 @@ const AtomicString& NumberInputType::formControlType() const return InputTypeNames::number(); } +double NumberInputType::valueAsNumber() const +{ + return parseToDouble(element()->value(), numeric_limits<double>::quiet_NaN()); +} + +void NumberInputType::setValueAsNumber(double newValue, ExceptionCode&) const +{ + element()->setValue(serialize(newValue)); +} + +bool NumberInputType::typeMismatchFor(const String& value) const +{ + return !value.isEmpty() && !parseToDoubleForNumberType(value, 0); +} + +bool NumberInputType::typeMismatch() const +{ + ASSERT(!typeMismatchFor(element()->value())); + return false; +} + +bool NumberInputType::rangeUnderflow(const String& value) const +{ + const double nan = numeric_limits<double>::quiet_NaN(); + double doubleValue = parseToDouble(value, nan); + return isfinite(doubleValue) && doubleValue < minimum(); +} + +bool NumberInputType::rangeOverflow(const String& value) const +{ + const double nan = numeric_limits<double>::quiet_NaN(); + double doubleValue = parseToDouble(value, nan); + return isfinite(doubleValue) && doubleValue > maximum(); +} + +double NumberInputType::minimum() const +{ + return parseToDouble(element()->fastGetAttribute(minAttr), numberDefaultMinimum); +} + +double NumberInputType::maximum() const +{ + return parseToDouble(element()->fastGetAttribute(maxAttr), numberDefaultMaximum); +} + +bool NumberInputType::stepMismatch(const String& value, double step) const +{ + double doubleValue; + if (!parseToDoubleForNumberType(value, &doubleValue)) + return false; + doubleValue = fabs(doubleValue - stepBase()); + if (isinf(doubleValue)) + return false; + // double's fractional part size is DBL_MAN_DIG-bit. If the current value + // is greater than step*2^DBL_MANT_DIG, the following fmod() makes no sense. + if (doubleValue / pow(2.0, DBL_MANT_DIG) > step) + return false; + double remainder = fmod(doubleValue, step); + // Accepts errors in lower 7-bit. + double acceptableError = step / pow(2.0, DBL_MANT_DIG - 7); + return acceptableError < remainder && remainder < (step - acceptableError); +} + +double NumberInputType::stepBase() const +{ + return parseToDouble(element()->fastGetAttribute(minAttr), defaultStepBase()); +} + +double NumberInputType::defaultStep() const +{ + return numberDefaultStep; +} + +double NumberInputType::stepScaleFactor() const +{ + return numberStepScaleFactor; +} + +double NumberInputType::parseToDouble(const String& src, double defaultValue) const +{ + double numberValue; + if (!parseToDoubleForNumberType(src, &numberValue)) + return defaultValue; + ASSERT(isfinite(numberValue)); + return numberValue; +} + +String NumberInputType::serialize(double value) const +{ + if (!isfinite(value)) + return String(); + return serializeForNumberType(value); +} + } // namespace WebCore diff --git a/WebCore/html/NumberInputType.h b/WebCore/html/NumberInputType.h index 5347249..262955e 100644 --- a/WebCore/html/NumberInputType.h +++ b/WebCore/html/NumberInputType.h @@ -42,6 +42,20 @@ public: private: NumberInputType(HTMLInputElement* element) : TextFieldInputType(element) { } virtual const AtomicString& formControlType() const; + virtual double valueAsNumber() const; + virtual void setValueAsNumber(double, ExceptionCode&) const; + virtual bool typeMismatchFor(const String&) const; + virtual bool typeMismatch() const; + virtual bool rangeUnderflow(const String&) const; + virtual bool rangeOverflow(const String&) const; + virtual double minimum() const; + virtual double maximum() const; + virtual bool stepMismatch(const String&, double) const; + virtual double stepBase() const; + virtual double defaultStep() const; + virtual double stepScaleFactor() const; + virtual double parseToDouble(const String&, double) const; + virtual String serialize(double) const; }; } // namespace WebCore diff --git a/WebCore/html/PluginDocument.cpp b/WebCore/html/PluginDocument.cpp index ad11dfb..cebb949 100644 --- a/WebCore/html/PluginDocument.cpp +++ b/WebCore/html/PluginDocument.cpp @@ -29,8 +29,10 @@ #include "Frame.h" #include "FrameLoaderClient.h" #include "HTMLEmbedElement.h" +#include "HTMLHtmlElement.h" #include "HTMLNames.h" #include "MainResourceLoader.h" +#include "NodeList.h" #include "Page.h" #include "RawDataDocumentParser.h" #include "RenderEmbeddedObject.h" @@ -48,8 +50,6 @@ public: return adoptRef(new PluginDocumentParser(document)); } - static Widget* pluginWidgetFromDocument(Document*); - private: PluginDocumentParser(Document* document) : RawDataDocumentParser(document) @@ -64,25 +64,14 @@ private: HTMLEmbedElement* m_embedElement; }; -Widget* PluginDocumentParser::pluginWidgetFromDocument(Document* doc) -{ - ASSERT(doc); - RefPtr<Element> body = doc->body(); - if (body) { - RefPtr<Node> node = body->firstChild(); - if (node && node->renderer()) { - ASSERT(node->renderer()->isEmbeddedObject()); - return toRenderEmbeddedObject(node->renderer())->widget(); - } - } - return 0; -} - void PluginDocumentParser::createDocumentStructure() { ExceptionCode ec; RefPtr<Element> rootElement = document()->createElement(htmlTag, false); document()->appendChild(rootElement, ec); +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + static_cast<HTMLHtmlElement*>(rootElement.get())->insertedByParser(); +#endif if (document()->frame() && document()->frame()->loader()) document()->frame()->loader()->dispatchDocumentElementAvailable(); @@ -103,7 +92,9 @@ void PluginDocumentParser::createDocumentStructure() m_embedElement->setAttribute(nameAttr, "plugin"); m_embedElement->setAttribute(srcAttr, document()->url().string()); m_embedElement->setAttribute(typeAttr, document()->frame()->loader()->writer()->mimeType()); - + + static_cast<PluginDocument*>(document())->setPluginNode(m_embedElement); + body->appendChild(embedElement, ec); } @@ -125,8 +116,13 @@ void PluginDocumentParser::appendBytes(DocumentWriter*, const char*, int, bool) document()->updateLayout(); if (RenderPart* renderer = m_embedElement->renderPart()) { - frame->loader()->client()->redirectDataToPlugin(renderer->widget()); - frame->loader()->activeDocumentLoader()->mainResourceLoader()->setShouldBufferData(false); + if (Widget* widget = renderer->widget()) { + frame->loader()->client()->redirectDataToPlugin(widget); + // In a plugin document, the main resource is the plugin. If we have a null widget, that means + // the loading of the plugin was cancelled, which gives us a null mainResourceLoader(), so we + // need to have this call in a null check of the widget or of mainResourceLoader(). + frame->loader()->activeDocumentLoader()->mainResourceLoader()->setShouldBufferData(false); + } } finish(); @@ -134,11 +130,12 @@ void PluginDocumentParser::appendBytes(DocumentWriter*, const char*, int, bool) PluginDocument::PluginDocument(Frame* frame, const KURL& url) : HTMLDocument(frame, url) + , m_shouldLoadPluginManually(true) { setCompatibilityMode(QuirksMode); lockCompatibilityMode(); } - + PassRefPtr<DocumentParser> PluginDocument::createParser() { return PluginDocumentParser::create(this); @@ -146,16 +143,34 @@ PassRefPtr<DocumentParser> PluginDocument::createParser() Widget* PluginDocument::pluginWidget() { - return PluginDocumentParser::pluginWidgetFromDocument(this); + if (m_pluginNode && m_pluginNode->renderer()) { + ASSERT(m_pluginNode->renderer()->isEmbeddedObject()); + return toRenderEmbeddedObject(m_pluginNode->renderer())->widget(); + } + return 0; } Node* PluginDocument::pluginNode() { - RefPtr<Element> body_element = body(); - if (body_element) - return body_element->firstChild(); + return m_pluginNode.get(); +} - return 0; +void PluginDocument::detach() +{ + // Release the plugin node so that we don't have a circular reference. + m_pluginNode = 0; + HTMLDocument::detach(); +} + +void PluginDocument::cancelManualPluginLoad() +{ + // PluginDocument::cancelManualPluginLoad should only be called once, but there are issues + // with how many times we call beforeload on object elements. <rdar://problem/8441094>. + if (!shouldLoadPluginManually()) + return; + + frame()->loader()->activeDocumentLoader()->mainResourceLoader()->cancel(); + setShouldLoadPluginManually(false); } } diff --git a/WebCore/html/PluginDocument.h b/WebCore/html/PluginDocument.h index 3bb5d99..da0bb75 100644 --- a/WebCore/html/PluginDocument.h +++ b/WebCore/html/PluginDocument.h @@ -38,16 +38,44 @@ public: return adoptRef(new PluginDocument(frame, url)); } + void setPluginNode(Node* pluginNode) { m_pluginNode = pluginNode; } + Widget* pluginWidget(); Node* pluginNode(); virtual bool isPluginDocument() const { return true; } + virtual void detach(); + + void cancelManualPluginLoad(); + + bool shouldLoadPluginManually() { return m_shouldLoadPluginManually; } + private: PluginDocument(Frame*, const KURL&); virtual PassRefPtr<DocumentParser> createParser(); + + void setShouldLoadPluginManually(bool loadManually) { m_shouldLoadPluginManually = loadManually; } + + bool m_shouldLoadPluginManually; + RefPtr<Node> m_pluginNode; }; + +inline PluginDocument* toPluginDocument(Document* document) +{ + ASSERT(!document || document->isPluginDocument()); + return static_cast<PluginDocument*>(document); +} + +inline const PluginDocument* toPluginDocument(const Document* document) +{ + ASSERT(!document || document->isPluginDocument()); + return static_cast<const PluginDocument*>(document); +} + +// This will catch anyone doing an unnecessary cast. +void toPluginDocument(const PluginDocument*); } diff --git a/WebCore/html/RadioInputType.cpp b/WebCore/html/RadioInputType.cpp index a1c8d04..5df4bbc 100644 --- a/WebCore/html/RadioInputType.cpp +++ b/WebCore/html/RadioInputType.cpp @@ -31,6 +31,7 @@ #include "config.h" #include "RadioInputType.h" +#include "HTMLInputElement.h" #include <wtf/PassOwnPtr.h> namespace WebCore { @@ -45,4 +46,9 @@ const AtomicString& RadioInputType::formControlType() const return InputTypeNames::radio(); } +bool RadioInputType::valueMissing(const String&) const +{ + return !element()->checkedRadioButtons().checkedButtonForGroup(element()->name()); +} + } // namespace WebCore diff --git a/WebCore/html/RadioInputType.h b/WebCore/html/RadioInputType.h index 180c6dd..2ff2c41 100644 --- a/WebCore/html/RadioInputType.h +++ b/WebCore/html/RadioInputType.h @@ -42,6 +42,7 @@ public: private: RadioInputType(HTMLInputElement* element) : InputType(element) { } virtual const AtomicString& formControlType() const; + virtual bool valueMissing(const String&) const; }; } // namespace WebCore diff --git a/WebCore/html/RangeInputType.cpp b/WebCore/html/RangeInputType.cpp index f5f7322..7448071 100644 --- a/WebCore/html/RangeInputType.cpp +++ b/WebCore/html/RangeInputType.cpp @@ -31,10 +31,23 @@ #include "config.h" #include "RangeInputType.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" +#include "HTMLParserIdioms.h" +#include <limits> +#include <wtf/MathExtras.h> #include <wtf/PassOwnPtr.h> namespace WebCore { +using namespace HTMLNames; +using namespace std; + +static const double rangeDefaultMinimum = 0.0; +static const double rangeDefaultMaximum = 100.0; +static const double rangeDefaultStep = 1.0; +static const double rangeStepScaleFactor = 1.0; + PassOwnPtr<InputType> RangeInputType::create(HTMLInputElement* element) { return adoptPtr(new RangeInputType(element)); @@ -45,4 +58,88 @@ const AtomicString& RangeInputType::formControlType() const return InputTypeNames::range(); } +double RangeInputType::valueAsNumber() const +{ + return parseToDouble(element()->value(), numeric_limits<double>::quiet_NaN()); +} + +void RangeInputType::setValueAsNumber(double newValue, ExceptionCode&) const +{ + element()->setValue(serialize(newValue)); +} + +bool RangeInputType::supportsRequired() const +{ + return false; +} + +bool RangeInputType::rangeUnderflow(const String& value) const +{ + // Guaranteed by sanitization. + ASSERT_UNUSED(value, parseToDouble(value, numeric_limits<double>::quiet_NaN()) >= minimum()); + return false; +} + +bool RangeInputType::rangeOverflow(const String& value) const +{ + // Guaranteed by sanitization. + ASSERT_UNUSED(value, parseToDouble(value, numeric_limits<double>::quiet_NaN()) <= maximum()); + return false; +} + +double RangeInputType::minimum() const +{ + return parseToDouble(element()->fastGetAttribute(minAttr), rangeDefaultMinimum); +} + +double RangeInputType::maximum() const +{ + double max = parseToDouble(element()->fastGetAttribute(maxAttr), rangeDefaultMaximum); + // A remedy for the inconsistent min/max values. + // Sets the maximum to the default or the minimum value. + double min = minimum(); + if (max < min) + max = std::max(min, rangeDefaultMaximum); + return max; +} + +bool RangeInputType::stepMismatch(const String&, double) const +{ + // stepMismatch doesn't occur for type=range. RenderSlider guarantees the + // value matches to step on user input, and sanitization takes care + // of the general case. + return false; +} + +double RangeInputType::stepBase() const +{ + return minimum(); +} + +double RangeInputType::defaultStep() const +{ + return rangeDefaultStep; +} + +double RangeInputType::stepScaleFactor() const +{ + return rangeStepScaleFactor; +} + +double RangeInputType::parseToDouble(const String& src, double defaultValue) const +{ + double numberValue; + if (!parseToDoubleForNumberType(src, &numberValue)) + return defaultValue; + ASSERT(isfinite(numberValue)); + return numberValue; +} + +String RangeInputType::serialize(double value) const +{ + if (!isfinite(value)) + return String(); + return serializeForNumberType(value); +} + } // namespace WebCore diff --git a/WebCore/html/RangeInputType.h b/WebCore/html/RangeInputType.h index d42c617..0ff6f60 100644 --- a/WebCore/html/RangeInputType.h +++ b/WebCore/html/RangeInputType.h @@ -42,6 +42,19 @@ public: private: RangeInputType(HTMLInputElement* element) : InputType(element) { } virtual const AtomicString& formControlType() const; + virtual double valueAsNumber() const; + virtual void setValueAsNumber(double, ExceptionCode&) const; + virtual bool supportsRequired() const; + virtual bool rangeUnderflow(const String&) const; + virtual bool rangeOverflow(const String&) const; + virtual double minimum() const; + virtual double maximum() const; + virtual bool stepMismatch(const String&, double) const; + virtual double stepBase() const; + virtual double defaultStep() const; + virtual double stepScaleFactor() const; + virtual double parseToDouble(const String&, double) const; + virtual String serialize(double) const; }; } // namespace WebCore diff --git a/WebCore/html/ResetInputType.cpp b/WebCore/html/ResetInputType.cpp index 8b18a8d..1db7592 100644 --- a/WebCore/html/ResetInputType.cpp +++ b/WebCore/html/ResetInputType.cpp @@ -45,4 +45,9 @@ const AtomicString& ResetInputType::formControlType() const return InputTypeNames::reset(); } +bool ResetInputType::supportsValidation() const +{ + return false; +} + } // namespace WebCore diff --git a/WebCore/html/ResetInputType.h b/WebCore/html/ResetInputType.h index e0d8997..3f883a3 100644 --- a/WebCore/html/ResetInputType.h +++ b/WebCore/html/ResetInputType.h @@ -42,6 +42,7 @@ public: private: ResetInputType(HTMLInputElement* element) : InputType(element) { } virtual const AtomicString& formControlType() const; + virtual bool supportsValidation() const; }; } // namespace WebCore diff --git a/WebCore/html/SubmitInputType.cpp b/WebCore/html/SubmitInputType.cpp index dd13e6b..65934f9 100644 --- a/WebCore/html/SubmitInputType.cpp +++ b/WebCore/html/SubmitInputType.cpp @@ -45,4 +45,9 @@ const AtomicString& SubmitInputType::formControlType() const return InputTypeNames::submit(); } +bool SubmitInputType::supportsValidation() const +{ + return false; +} + } // namespace WebCore diff --git a/WebCore/html/SubmitInputType.h b/WebCore/html/SubmitInputType.h index 7ea448e..83fa5e5 100644 --- a/WebCore/html/SubmitInputType.h +++ b/WebCore/html/SubmitInputType.h @@ -42,6 +42,7 @@ public: private: SubmitInputType(HTMLInputElement* element) : InputType(element) { } virtual const AtomicString& formControlType() const; + virtual bool supportsValidation() const; }; } // namespace WebCore diff --git a/WebCore/html/TextFieldInputType.cpp b/WebCore/html/TextFieldInputType.cpp index e681b40..82382ef 100644 --- a/WebCore/html/TextFieldInputType.cpp +++ b/WebCore/html/TextFieldInputType.cpp @@ -31,6 +31,8 @@ #include "config.h" #include "TextFieldInputType.h" +#include <wtf/text/WTFString.h> + namespace WebCore { bool TextFieldInputType::isTextField() const @@ -38,4 +40,9 @@ bool TextFieldInputType::isTextField() const return true; } +bool TextFieldInputType::valueMissing(const String& value) const +{ + return value.isEmpty(); +} + } // namespace WebCore diff --git a/WebCore/html/TextFieldInputType.h b/WebCore/html/TextFieldInputType.h index fb33a01..9108c42 100644 --- a/WebCore/html/TextFieldInputType.h +++ b/WebCore/html/TextFieldInputType.h @@ -41,6 +41,7 @@ class TextFieldInputType : public InputType { protected: TextFieldInputType(HTMLInputElement* element) : InputType(element) { } virtual bool isTextField() const; + virtual bool valueMissing(const String&) const; }; } // namespace WebCore diff --git a/WebCore/html/TimeInputType.cpp b/WebCore/html/TimeInputType.cpp index 1564bc5..27dce90 100644 --- a/WebCore/html/TimeInputType.cpp +++ b/WebCore/html/TimeInputType.cpp @@ -31,10 +31,18 @@ #include "config.h" #include "TimeInputType.h" +#include "DateComponents.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" #include <wtf/PassOwnPtr.h> namespace WebCore { +using namespace HTMLNames; + +static const double timeDefaultStep = 60.0; +static const double timeStepScaleFactor = 1000.0; + PassOwnPtr<InputType> TimeInputType::create(HTMLInputElement* element) { return adoptPtr(new TimeInputType(element)); @@ -45,4 +53,42 @@ const AtomicString& TimeInputType::formControlType() const return InputTypeNames::time(); } +double TimeInputType::minimum() const +{ + return parseToDouble(element()->fastGetAttribute(minAttr), DateComponents::minimumTime()); +} + +double TimeInputType::maximum() const +{ + return parseToDouble(element()->fastGetAttribute(maxAttr), DateComponents::maximumTime()); +} + +double TimeInputType::defaultStep() const +{ + return timeDefaultStep; +} + +double TimeInputType::stepScaleFactor() const +{ + return timeStepScaleFactor; +} + +bool TimeInputType::scaledStepValeuShouldBeInteger() const +{ + return true; +} + +bool TimeInputType::parseToDateComponentsInternal(const UChar* characters, unsigned length, DateComponents* out) const +{ + ASSERT(out); + unsigned end; + return out->parseTime(characters, length, 0, end) && end == length; +} + +bool TimeInputType::setMillisecondToDateComponents(double value, DateComponents* date) const +{ + ASSERT(date); + return date->setMillisecondsSinceMidnight(value); +} + } // namespace WebCore diff --git a/WebCore/html/TimeInputType.h b/WebCore/html/TimeInputType.h index 9530f7d..6070fa0 100644 --- a/WebCore/html/TimeInputType.h +++ b/WebCore/html/TimeInputType.h @@ -31,17 +31,24 @@ #ifndef TimeInputType_h #define TimeInputType_h -#include "TextFieldInputType.h" +#include "BaseDateAndTimeInputType.h" namespace WebCore { -class TimeInputType : public TextFieldInputType { +class TimeInputType : public BaseDateAndTimeInputType { public: static PassOwnPtr<InputType> create(HTMLInputElement*); private: - TimeInputType(HTMLInputElement* element) : TextFieldInputType(element) { } + TimeInputType(HTMLInputElement* element) : BaseDateAndTimeInputType(element) { } virtual const AtomicString& formControlType() const; + virtual double minimum() const; + virtual double maximum() const; + virtual double defaultStep() const; + virtual double stepScaleFactor() const; + virtual bool scaledStepValeuShouldBeInteger() const; + virtual bool parseToDateComponentsInternal(const UChar*, unsigned length, DateComponents*) const; + virtual bool setMillisecondToDateComponents(double, DateComponents*) const; }; } // namespace WebCore diff --git a/WebCore/html/URLInputType.cpp b/WebCore/html/URLInputType.cpp index 2afdcde..517ffad 100644 --- a/WebCore/html/URLInputType.cpp +++ b/WebCore/html/URLInputType.cpp @@ -31,6 +31,8 @@ #include "config.h" #include "URLInputType.h" +#include "HTMLInputElement.h" +#include "KURL.h" #include <wtf/PassOwnPtr.h> namespace WebCore { @@ -45,4 +47,14 @@ const AtomicString& URLInputType::formControlType() const return InputTypeNames::url(); } +bool URLInputType::typeMismatchFor(const String& value) const +{ + return !value.isEmpty() && !KURL(KURL(), value).isValid(); +} + +bool URLInputType::typeMismatch() const +{ + return typeMismatchFor(element()->value()); +} + } // namespace WebCore diff --git a/WebCore/html/URLInputType.h b/WebCore/html/URLInputType.h index 85d4f9f..82ab1b7 100644 --- a/WebCore/html/URLInputType.h +++ b/WebCore/html/URLInputType.h @@ -42,6 +42,8 @@ public: private: URLInputType(HTMLInputElement* element) : BaseTextInputType(element) { } virtual const AtomicString& formControlType() const; + virtual bool typeMismatchFor(const String&) const; + virtual bool typeMismatch() const; }; } // namespace WebCore diff --git a/WebCore/html/ValidityState.cpp b/WebCore/html/ValidityState.cpp index f18469e..57fb438 100644 --- a/WebCore/html/ValidityState.cpp +++ b/WebCore/html/ValidityState.cpp @@ -83,12 +83,7 @@ bool ValidityState::typeMismatch() const { if (!m_control->hasTagName(inputTag)) return false; - - HTMLInputElement* input = static_cast<HTMLInputElement*>(m_control); - String value = input->value(); - if (value.isEmpty()) - return false; - return input->typeMismatch(value); + return static_cast<HTMLInputElement*>(m_control)->typeMismatch(); } bool ValidityState::patternMismatch() const diff --git a/WebCore/html/WeekInputType.cpp b/WebCore/html/WeekInputType.cpp index 0b4ab30..a5836dc 100644 --- a/WebCore/html/WeekInputType.cpp +++ b/WebCore/html/WeekInputType.cpp @@ -31,10 +31,19 @@ #include "config.h" #include "WeekInputType.h" +#include "DateComponents.h" +#include "HTMLInputElement.h" +#include "HTMLNames.h" #include <wtf/PassOwnPtr.h> namespace WebCore { +using namespace HTMLNames; + +static const double weekDefaultStepBase = -259200000.0; // The first day of 1970-W01. +static const double weekDefaultStep = 1.0; +static const double weekStepScaleFactor = 604800000.0; + PassOwnPtr<InputType> WeekInputType::create(HTMLInputElement* element) { return adoptPtr(new WeekInputType(element)); @@ -45,4 +54,47 @@ const AtomicString& WeekInputType::formControlType() const return InputTypeNames::week(); } +double WeekInputType::minimum() const +{ + return parseToDouble(element()->fastGetAttribute(minAttr), DateComponents::minimumWeek()); +} + +double WeekInputType::maximum() const +{ + return parseToDouble(element()->fastGetAttribute(maxAttr), DateComponents::maximumWeek()); +} + +double WeekInputType::stepBase() const +{ + return parseToDouble(element()->fastGetAttribute(minAttr), weekDefaultStepBase); +} + +double WeekInputType::defaultStep() const +{ + return weekDefaultStep; +} + +double WeekInputType::stepScaleFactor() const +{ + return weekStepScaleFactor; +} + +bool WeekInputType::parsedStepValueShouldBeInteger() const +{ + return true; +} + +bool WeekInputType::parseToDateComponentsInternal(const UChar* characters, unsigned length, DateComponents* out) const +{ + ASSERT(out); + unsigned end; + return out->parseWeek(characters, length, 0, end) && end == length; +} + +bool WeekInputType::setMillisecondToDateComponents(double value, DateComponents* date) const +{ + ASSERT(date); + return date->setMillisecondsSinceEpochForWeek(value); +} + } // namespace WebCore diff --git a/WebCore/html/WeekInputType.h b/WebCore/html/WeekInputType.h index 7b6ee23..437164b 100644 --- a/WebCore/html/WeekInputType.h +++ b/WebCore/html/WeekInputType.h @@ -31,17 +31,25 @@ #ifndef WeekInputType_h #define WeekInputType_h -#include "TextFieldInputType.h" +#include "BaseDateAndTimeInputType.h" namespace WebCore { -class WeekInputType : public TextFieldInputType { +class WeekInputType : public BaseDateAndTimeInputType { public: static PassOwnPtr<InputType> create(HTMLInputElement*); private: - WeekInputType(HTMLInputElement* element) : TextFieldInputType(element) { } + WeekInputType(HTMLInputElement* element) : BaseDateAndTimeInputType(element) { } virtual const AtomicString& formControlType() const; + virtual double minimum() const; + virtual double maximum() const; + virtual double stepBase() const; + virtual double defaultStep() const; + virtual double stepScaleFactor() const; + virtual bool parsedStepValueShouldBeInteger() const; + virtual bool parseToDateComponentsInternal(const UChar*, unsigned length, DateComponents*) const; + virtual bool setMillisecondToDateComponents(double, DateComponents*) const; }; } // namespace WebCore diff --git a/WebCore/html/canvas/ArrayBuffer.cpp b/WebCore/html/canvas/ArrayBuffer.cpp index 3b204ff..014cc1e 100644 --- a/WebCore/html/canvas/ArrayBuffer.cpp +++ b/WebCore/html/canvas/ArrayBuffer.cpp @@ -25,7 +25,7 @@ #include "config.h" -#if ENABLE(3D_CANVAS) +#if ENABLE(3D_CANVAS) || ENABLE(BLOB) #include "ArrayBuffer.h" @@ -93,4 +93,4 @@ void* ArrayBuffer::tryAllocate(unsigned numElements, unsigned elementByteSize) } -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(3D_CANVAS) || ENABLE(BLOB) diff --git a/WebCore/html/canvas/ArrayBuffer.idl b/WebCore/html/canvas/ArrayBuffer.idl index 92098e5..79a4685 100644 --- a/WebCore/html/canvas/ArrayBuffer.idl +++ b/WebCore/html/canvas/ArrayBuffer.idl @@ -26,10 +26,11 @@ module html { interface [ - Conditional=3D_CANVAS, + Conditional=3D_CANVAS|BLOB, CanBeConstructed, CustomConstructFunction, - V8CustomConstructor + NoStaticTables, + V8CustomConstructor, ] ArrayBuffer { readonly attribute int byteLength; }; diff --git a/WebCore/html/canvas/ArrayBufferView.cpp b/WebCore/html/canvas/ArrayBufferView.cpp index 485d18b..7f41bda 100644 --- a/WebCore/html/canvas/ArrayBufferView.cpp +++ b/WebCore/html/canvas/ArrayBufferView.cpp @@ -25,7 +25,7 @@ #include "config.h" -#if ENABLE(3D_CANVAS) +#if ENABLE(3D_CANVAS) || ENABLE(BLOB) #include "ArrayBufferView.h" @@ -106,4 +106,4 @@ void ArrayBufferView::calculateOffsetAndLength(int start, int end, unsigned arra } -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(3D_CANVAS) || ENABLE(BLOB) diff --git a/WebCore/html/canvas/ArrayBufferView.idl b/WebCore/html/canvas/ArrayBufferView.idl index 450345e..74a3fe3 100644 --- a/WebCore/html/canvas/ArrayBufferView.idl +++ b/WebCore/html/canvas/ArrayBufferView.idl @@ -24,7 +24,7 @@ */ module html { - interface [Conditional=3D_CANVAS, CustomToJS, OmitConstructor] ArrayBufferView { + interface [Conditional=3D_CANVAS|BLOB, CustomToJS, NoStaticTables, OmitConstructor] ArrayBufferView { readonly attribute ArrayBuffer buffer; readonly attribute unsigned long byteOffset; readonly attribute unsigned long byteLength; diff --git a/WebCore/html/canvas/CanvasGradient.cpp b/WebCore/html/canvas/CanvasGradient.cpp index fd48194..7c98a82 100644 --- a/WebCore/html/canvas/CanvasGradient.cpp +++ b/WebCore/html/canvas/CanvasGradient.cpp @@ -27,6 +27,8 @@ #include "config.h" #include "CanvasGradient.h" +#include "CanvasPattern.h" +#include "CanvasStyle.h" #include "CSSParser.h" #include "ExceptionCode.h" @@ -52,7 +54,7 @@ void CanvasGradient::addColorStop(float value, const String& color, ExceptionCod } RGBA32 rgba = 0; - if (!CSSParser::parseColor(rgba, color)) { + if (!parseColorOrCurrentColor(rgba, color, 0 /*canvas*/)) { if (!m_dashbardCompatibilityMode) ec = SYNTAX_ERR; return; diff --git a/WebCore/html/canvas/CanvasRenderingContext2D.cpp b/WebCore/html/canvas/CanvasRenderingContext2D.cpp index 161a891..b1d7b23 100644 --- a/WebCore/html/canvas/CanvasRenderingContext2D.cpp +++ b/WebCore/html/canvas/CanvasRenderingContext2D.cpp @@ -128,10 +128,10 @@ CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, bo return; if (!p->settings()->accelerated2dCanvasEnabled()) return; - m_context3D = p->chrome()->client()->getSharedGraphicsContext3D(); - if (m_context3D) { - if (GraphicsContext* c = drawingContext()) { - m_drawingBuffer = DrawingBuffer::create(m_context3D.get(), IntSize(canvas->width(), canvas->height())); + if (GraphicsContext* c = drawingContext()) { + m_context3D = p->sharedGraphicsContext3D(); + if (m_context3D) { + m_drawingBuffer = m_context3D->graphicsContext3D()->createDrawingBuffer(IntSize(canvas->width(), canvas->height())); c->setSharedGraphicsContext3D(m_context3D.get(), m_drawingBuffer.get(), IntSize(canvas->width(), canvas->height())); } } @@ -167,8 +167,8 @@ void CanvasRenderingContext2D::reset() m_stateStack.first() = State(); m_path.clear(); #if ENABLE(ACCELERATED_2D_CANVAS) - if (m_context3D) { - if (GraphicsContext* c = drawingContext()) { + if (GraphicsContext* c = drawingContext()) { + if (m_context3D) { m_drawingBuffer->reset(IntSize(canvas()->width(), canvas()->height())); c->setSharedGraphicsContext3D(m_context3D.get(), m_drawingBuffer.get(), IntSize(canvas()->width(), canvas()->height())); } @@ -231,7 +231,7 @@ void CanvasRenderingContext2D::setAllAttributesToDefault() if (!context) return; - context->setShadow(FloatSize(), 0, Color::transparent, DeviceColorSpace); + context->setShadow(FloatSize(), 0, Color::transparent, ColorSpaceDeviceRGB); context->setAlpha(1); context->setCompositeOperation(CompositeSourceOver); } @@ -249,7 +249,13 @@ void CanvasRenderingContext2D::setStrokeStyle(PassRefPtr<CanvasStyle> style) if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentColor(*style)) return; - checkOrigin(style->canvasPattern()); + if (style->isCurrentColor()) { + if (style->hasOverrideAlpha()) + style = CanvasStyle::createFromRGBA(colorWithOverrideAlpha(currentColor(canvas()), style->overrideAlpha())); + else + style = CanvasStyle::createFromRGBA(currentColor(canvas())); + } else + checkOrigin(style->canvasPattern()); state().m_strokeStyle = style; GraphicsContext* c = drawingContext(); @@ -272,7 +278,13 @@ void CanvasRenderingContext2D::setFillStyle(PassRefPtr<CanvasStyle> style) if (state().m_fillStyle && state().m_fillStyle->isEquivalentColor(*style)) return; - checkOrigin(style->canvasPattern()); + if (style->isCurrentColor()) { + if (style->hasOverrideAlpha()) + style = CanvasStyle::createFromRGBA(colorWithOverrideAlpha(currentColor(canvas()), style->overrideAlpha())); + else + style = CanvasStyle::createFromRGBA(currentColor(canvas())); + } else + checkOrigin(style->canvasPattern()); state().m_fillStyle = style; GraphicsContext* c = drawingContext(); @@ -394,7 +406,7 @@ String CanvasRenderingContext2D::shadowColor() const void CanvasRenderingContext2D::setShadowColor(const String& color) { - if (!CSSParser::parseColor(state().m_shadowColor, color)) + if (!parseColorOrCurrentColor(state().m_shadowColor, color, canvas())) return; applyShadow(); @@ -982,7 +994,7 @@ void CanvasRenderingContext2D::setShadow(float width, float height, float blur) void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color) { - if (!CSSParser::parseColor(state().m_shadowColor, color)) + if (!parseColorOrCurrentColor(state().m_shadowColor, color, canvas())) return; state().m_shadowOffset = FloatSize(width, height); @@ -1000,14 +1012,14 @@ void CanvasRenderingContext2D::setShadow(float width, float height, float blur, if (!c) return; - c->setShadow(IntSize(width, -height), state().m_shadowBlur, state().m_shadowColor, DeviceColorSpace); + c->setShadow(IntSize(width, -height), state().m_shadowBlur, state().m_shadowColor, ColorSpaceDeviceRGB); } void CanvasRenderingContext2D::setShadow(float width, float height, float blur, const String& color, float alpha) { RGBA32 rgba; - if (!CSSParser::parseColor(rgba, color)) + if (!parseColorOrCurrentColor(rgba, color, canvas())) return; state().m_shadowColor = colorWithOverrideAlpha(rgba, alpha); @@ -1018,7 +1030,7 @@ void CanvasRenderingContext2D::setShadow(float width, float height, float blur, if (!c) return; - c->setShadow(IntSize(width, -height), state().m_shadowBlur, state().m_shadowColor, DeviceColorSpace); + c->setShadow(IntSize(width, -height), state().m_shadowBlur, state().m_shadowColor, ColorSpaceDeviceRGB); } void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float grayLevel, float alpha) @@ -1031,7 +1043,7 @@ void CanvasRenderingContext2D::setShadow(float width, float height, float blur, if (!c) return; - c->setShadow(IntSize(width, -height), state().m_shadowBlur, state().m_shadowColor, DeviceColorSpace); + c->setShadow(IntSize(width, -height), state().m_shadowBlur, state().m_shadowColor, ColorSpaceDeviceRGB); } void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float r, float g, float b, float a) @@ -1044,7 +1056,7 @@ void CanvasRenderingContext2D::setShadow(float width, float height, float blur, if (!c) return; - c->setShadow(IntSize(width, -height), state().m_shadowBlur, state().m_shadowColor, DeviceColorSpace); + c->setShadow(IntSize(width, -height), state().m_shadowBlur, state().m_shadowColor, ColorSpaceDeviceRGB); } void CanvasRenderingContext2D::setShadow(float width, float height, float blur, float c, float m, float y, float k, float a) @@ -1064,7 +1076,7 @@ void CanvasRenderingContext2D::setShadow(float width, float height, float blur, CGContextSetShadowWithColor(dc->platformContext(), adjustedShadowSize(width, -height), blur, shadowColor); CGColorRelease(shadowColor); #else - dc->setShadow(IntSize(width, -height), blur, state().m_shadowColor, DeviceColorSpace); + dc->setShadow(IntSize(width, -height), blur, state().m_shadowColor, ColorSpaceDeviceRGB); #endif } @@ -1084,7 +1096,7 @@ void CanvasRenderingContext2D::applyShadow() float width = state().m_shadowOffset.width(); float height = state().m_shadowOffset.height(); - c->setShadow(FloatSize(width, -height), state().m_shadowBlur, state().m_shadowColor, DeviceColorSpace); + c->setShadow(FloatSize(width, -height), state().m_shadowBlur, state().m_shadowColor, ColorSpaceDeviceRGB); } static IntSize size(HTMLImageElement* image) @@ -1186,7 +1198,7 @@ void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRec FloatRect sourceRect = c->roundToDevicePixels(normalizedSrcRect); FloatRect destRect = c->roundToDevicePixels(normalizedDstRect); - c->drawImage(cachedImage->image(), DeviceColorSpace, destRect, sourceRect, state().m_globalComposite); + c->drawImage(cachedImage->image(), ColorSpaceDeviceRGB, destRect, sourceRect, state().m_globalComposite); didDraw(destRect); } @@ -1268,7 +1280,7 @@ void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas, const sourceCanvas->makeRenderingResultsAvailable(); #endif - c->drawImageBuffer(buffer, DeviceColorSpace, destRect, sourceRect, state().m_globalComposite); + c->drawImageBuffer(buffer, ColorSpaceDeviceRGB, destRect, sourceRect, state().m_globalComposite); didDraw(destRect); } @@ -1371,7 +1383,7 @@ void CanvasRenderingContext2D::drawImageFromRect(HTMLImageElement* image, op = CompositeSourceOver; FloatRect destRect = FloatRect(dx, dy, dw, dh); - c->drawImage(cachedImage->image(), DeviceColorSpace, destRect, FloatRect(sx, sy, sw, sh), op); + c->drawImage(cachedImage->image(), ColorSpaceDeviceRGB, destRect, FloatRect(sx, sy, sw, sh), op); didDraw(destRect); } @@ -1402,9 +1414,9 @@ PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createLinearGradient(float return 0; } - PassRefPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0), FloatPoint(x1, y1)); + RefPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0), FloatPoint(x1, y1)); prepareGradientForDashboard(gradient.get()); - return gradient; + return gradient.release(); } PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createRadialGradient(float x0, float y0, float r0, float x1, float y1, float r1, ExceptionCode& ec) @@ -1413,9 +1425,15 @@ PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createRadialGradient(float ec = NOT_SUPPORTED_ERR; return 0; } - PassRefPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1); + + if (r0 < 0 || r1 < 0) { + ec = INDEX_SIZE_ERR; + return 0; + } + + RefPtr<CanvasGradient> gradient = CanvasGradient::create(FloatPoint(x0, y0), r0, FloatPoint(x1, y1), r1); prepareGradientForDashboard(gradient.get()); - return gradient; + return gradient.release(); } PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLImageElement* image, @@ -1513,7 +1531,7 @@ static PassRefPtr<ImageData> createEmptyImageData(const IntSize& size) { RefPtr<ImageData> data = ImageData::create(size.width(), size.height()); memset(data->data()->data()->data(), 0, data->data()->data()->length()); - return data.get(); + return data.release(); } PassRefPtr<ImageData> CanvasRenderingContext2D::createImageData(PassRefPtr<ImageData> imageData, ExceptionCode& ec) const @@ -1614,16 +1632,16 @@ void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy, FloatRect clipRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight); clipRect.intersect(IntRect(0, 0, data->width(), data->height())); IntSize destOffset(static_cast<int>(dx), static_cast<int>(dy)); - IntRect sourceRect = enclosingIntRect(clipRect); - sourceRect.move(destOffset); - sourceRect.intersect(IntRect(IntPoint(), buffer->size())); - if (sourceRect.isEmpty()) + IntRect destRect = enclosingIntRect(clipRect); + destRect.move(destOffset); + destRect.intersect(IntRect(IntPoint(), buffer->size())); + if (destRect.isEmpty()) return; + IntRect sourceRect(destRect); sourceRect.move(-destOffset); - IntPoint destPoint(destOffset.width(), destOffset.height()); - buffer->putUnmultipliedImageData(data, sourceRect, destPoint); - didDraw(sourceRect, CanvasDidDrawApplyNone); // ignore transform, shadow and clip + buffer->putUnmultipliedImageData(data, sourceRect, IntPoint(destOffset)); + didDraw(destRect, CanvasDidDrawApplyNone); // ignore transform, shadow and clip } String CanvasRenderingContext2D::font() const @@ -1732,7 +1750,7 @@ PassRefPtr<TextMetrics> CanvasRenderingContext2D::measureText(const String& text Font::setCodePath(oldCodePath); #endif - return metrics; + return metrics.release(); } void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, float y, bool fill, float /*maxWidth*/, bool /*useMaxWidth*/) @@ -1749,7 +1767,7 @@ void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, flo // FIXME: Need to turn off font smoothing. RenderStyle* computedStyle = canvas()->computedStyle(); - bool rtl = computedStyle ? computedStyle->direction() == RTL : false; + bool rtl = computedStyle ? !computedStyle->isLeftToRightDirection() : false; bool override = computedStyle ? computedStyle->unicodeBidi() == Override : false; unsigned length = text.length(); @@ -1812,9 +1830,9 @@ void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, flo GraphicsContext* maskImageContext = maskImage->context(); if (fill) - maskImageContext->setFillColor(Color::black, DeviceColorSpace); + maskImageContext->setFillColor(Color::black, ColorSpaceDeviceRGB); else { - maskImageContext->setStrokeColor(Color::black, DeviceColorSpace); + maskImageContext->setStrokeColor(Color::black, ColorSpaceDeviceRGB); maskImageContext->setStrokeThickness(c->strokeThickness()); } diff --git a/WebCore/html/canvas/CanvasRenderingContext2D.h b/WebCore/html/canvas/CanvasRenderingContext2D.h index 2c88a31..f51c5e9 100644 --- a/WebCore/html/canvas/CanvasRenderingContext2D.h +++ b/WebCore/html/canvas/CanvasRenderingContext2D.h @@ -294,7 +294,7 @@ private: #endif #if ENABLE(ACCELERATED_2D_CANVAS) - OwnPtr<DrawingBuffer> m_drawingBuffer; + RefPtr<DrawingBuffer> m_drawingBuffer; RefPtr<SharedGraphicsContext3D> m_context3D; #endif }; diff --git a/WebCore/html/canvas/CanvasStyle.cpp b/WebCore/html/canvas/CanvasStyle.cpp index fd3c6e5..a4e87e3 100644 --- a/WebCore/html/canvas/CanvasStyle.cpp +++ b/WebCore/html/canvas/CanvasStyle.cpp @@ -30,9 +30,11 @@ #include "CanvasStyle.h" #include "CSSParser.h" +#include "CSSPropertyNames.h" #include "CanvasGradient.h" #include "CanvasPattern.h" #include "GraphicsContext.h" +#include "HTMLCanvasElement.h" #include <wtf/Assertions.h> #include <wtf/PassRefPtr.h> @@ -49,6 +51,49 @@ namespace WebCore { +enum ColorParseResult { ParsedRGBA, ParsedCurrentColor, ParseFailed }; + +static ColorParseResult parseColor(RGBA32& parsedColor, const String& colorString) +{ + if (equalIgnoringCase(colorString, "currentcolor")) + return ParsedCurrentColor; + if (CSSParser::parseColor(parsedColor, colorString)) + return ParsedRGBA; + return ParseFailed; +} + +RGBA32 currentColor(HTMLCanvasElement* canvas) +{ + if (!canvas || !canvas->inDocument()) + return Color::black; + RGBA32 rgba = Color::black; + CSSParser::parseColor(rgba, canvas->style()->getPropertyValue(CSSPropertyColor)); + return rgba; +} + +bool parseColorOrCurrentColor(RGBA32& parsedColor, const String& colorString, HTMLCanvasElement* canvas) +{ + ColorParseResult parseResult = parseColor(parsedColor, colorString); + switch (parseResult) { + case ParsedRGBA: + return true; + case ParsedCurrentColor: + parsedColor = currentColor(canvas); + return true; + case ParseFailed: + return false; + default: + ASSERT_NOT_REACHED(); + return false; + } +} + +CanvasStyle::CanvasStyle(Type type, float overrideAlpha) + : m_type(type) + , m_overrideAlpha(overrideAlpha) +{ +} + CanvasStyle::CanvasStyle(RGBA32 rgba) : m_type(RGBA) , m_rgba(rgba) @@ -89,17 +134,35 @@ CanvasStyle::CanvasStyle(PassRefPtr<CanvasPattern> pattern) PassRefPtr<CanvasStyle> CanvasStyle::createFromString(const String& color) { RGBA32 rgba; - if (!CSSParser::parseColor(rgba, color)) + ColorParseResult parseResult = parseColor(rgba, color); + switch (parseResult) { + case ParsedRGBA: + return adoptRef(new CanvasStyle(rgba)); + case ParsedCurrentColor: + return adoptRef(new CanvasStyle(CurrentColor)); + case ParseFailed: return 0; - return adoptRef(new CanvasStyle(rgba)); + default: + ASSERT_NOT_REACHED(); + return 0; + } } PassRefPtr<CanvasStyle> CanvasStyle::createFromStringWithOverrideAlpha(const String& color, float alpha) { RGBA32 rgba; - if (!CSSParser::parseColor(rgba, color)) + ColorParseResult parseResult = parseColor(rgba, color); + switch (parseResult) { + case ParsedRGBA: + return adoptRef(new CanvasStyle(colorWithOverrideAlpha(rgba, alpha))); + case ParsedCurrentColor: + return adoptRef(new CanvasStyle(CurrentColorWithOverrideAlpha, alpha)); + case ParseFailed: + return 0; + default: + ASSERT_NOT_REACHED(); return 0; - return adoptRef(new CanvasStyle(colorWithOverrideAlpha(rgba, alpha))); + } } PassRefPtr<CanvasStyle> CanvasStyle::createFromGradient(PassRefPtr<CanvasGradient> gradient) @@ -121,16 +184,18 @@ bool CanvasStyle::isEquivalentColor(const CanvasStyle& other) const return false; switch (m_type) { - case CanvasStyle::RGBA: + case RGBA: return m_rgba == other.m_rgba; - case CanvasStyle::CMYKA: + case CMYKA: return m_cmyka.c == other.m_cmyka.c && m_cmyka.m == other.m_cmyka.m && m_cmyka.y == other.m_cmyka.y && m_cmyka.k == other.m_cmyka.k && m_cmyka.a == other.m_cmyka.a; - case CanvasStyle::Gradient: - case CanvasStyle::ImagePattern: + case Gradient: + case ImagePattern: + case CurrentColor: + case CurrentColorWithOverrideAlpha: return false; } @@ -164,7 +229,7 @@ void CanvasStyle::applyStrokeColor(GraphicsContext* context) return; switch (m_type) { case RGBA: - context->setStrokeColor(m_rgba, DeviceColorSpace); + context->setStrokeColor(m_rgba, ColorSpaceDeviceRGB); break; case CMYKA: { // FIXME: Do this through platform-independent GraphicsContext API. @@ -178,7 +243,7 @@ void CanvasStyle::applyStrokeColor(GraphicsContext* context) currentPen.setColor(clr); context->platformContext()->setPen(currentPen); #else - context->setStrokeColor(m_rgba, DeviceColorSpace); + context->setStrokeColor(m_rgba, ColorSpaceDeviceRGB); #endif break; } @@ -188,6 +253,10 @@ void CanvasStyle::applyStrokeColor(GraphicsContext* context) case ImagePattern: context->setStrokePattern(canvasPattern()->pattern()); break; + case CurrentColor: + case CurrentColorWithOverrideAlpha: + ASSERT_NOT_REACHED(); + break; } } @@ -197,7 +266,7 @@ void CanvasStyle::applyFillColor(GraphicsContext* context) return; switch (m_type) { case RGBA: - context->setFillColor(m_rgba, DeviceColorSpace); + context->setFillColor(m_rgba, ColorSpaceDeviceRGB); break; case CMYKA: { // FIXME: Do this through platform-independent GraphicsContext API. @@ -211,7 +280,7 @@ void CanvasStyle::applyFillColor(GraphicsContext* context) currentBrush.setColor(clr); context->platformContext()->setBrush(currentBrush); #else - context->setFillColor(m_rgba, DeviceColorSpace); + context->setFillColor(m_rgba, ColorSpaceDeviceRGB); #endif break; } @@ -221,6 +290,10 @@ void CanvasStyle::applyFillColor(GraphicsContext* context) case ImagePattern: context->setFillPattern(canvasPattern()->pattern()); break; + case CurrentColor: + case CurrentColorWithOverrideAlpha: + ASSERT_NOT_REACHED(); + break; } } diff --git a/WebCore/html/canvas/CanvasStyle.h b/WebCore/html/canvas/CanvasStyle.h index 3ca760a..91dc923 100644 --- a/WebCore/html/canvas/CanvasStyle.h +++ b/WebCore/html/canvas/CanvasStyle.h @@ -29,12 +29,14 @@ #include "Color.h" #include "PlatformString.h" +#include <wtf/Assertions.h> namespace WebCore { class CanvasGradient; class CanvasPattern; class GraphicsContext; + class HTMLCanvasElement; class CanvasStyle : public RefCounted<CanvasStyle> { public: @@ -47,7 +49,11 @@ namespace WebCore { static PassRefPtr<CanvasStyle> createFromGradient(PassRefPtr<CanvasGradient>); static PassRefPtr<CanvasStyle> createFromPattern(PassRefPtr<CanvasPattern>); - String color() const { return Color(m_rgba).serialized(); } + bool isCurrentColor() const { return m_type == CurrentColor || m_type == CurrentColorWithOverrideAlpha; } + bool hasOverrideAlpha() const { return m_type == CurrentColorWithOverrideAlpha; } + float overrideAlpha() const { ASSERT(m_type == CurrentColorWithOverrideAlpha); return m_overrideAlpha; } + + String color() const { ASSERT(m_type == RGBA || m_type == CMYKA); return Color(m_rgba).serialized(); } CanvasGradient* canvasGradient() const { return m_gradient.get(); } CanvasPattern* canvasPattern() const { return m_pattern.get(); } @@ -59,6 +65,9 @@ namespace WebCore { bool isEquivalentCMYKA(float c, float m, float y, float k, float a) const; private: + enum Type { RGBA, CMYKA, Gradient, ImagePattern, CurrentColor, CurrentColorWithOverrideAlpha }; + + CanvasStyle(Type, float overrideAlpha = 0); CanvasStyle(RGBA32 rgba); CanvasStyle(float grayLevel, float alpha); CanvasStyle(float r, float g, float b, float a); @@ -66,11 +75,12 @@ namespace WebCore { CanvasStyle(PassRefPtr<CanvasGradient>); CanvasStyle(PassRefPtr<CanvasPattern>); - enum Type { RGBA, CMYKA, Gradient, ImagePattern }; - Type m_type; - RGBA32 m_rgba; + union { + RGBA32 m_rgba; + float m_overrideAlpha; + }; RefPtr<CanvasGradient> m_gradient; RefPtr<CanvasPattern> m_pattern; @@ -86,6 +96,9 @@ namespace WebCore { } m_cmyka; }; + RGBA32 currentColor(HTMLCanvasElement*); + bool parseColorOrCurrentColor(RGBA32& parsedColor, const String& colorString, HTMLCanvasElement*); + } // namespace WebCore #endif diff --git a/WebCore/html/canvas/Float32Array.cpp b/WebCore/html/canvas/Float32Array.cpp index e6e8439..e918d8f 100644 --- a/WebCore/html/canvas/Float32Array.cpp +++ b/WebCore/html/canvas/Float32Array.cpp @@ -26,7 +26,7 @@ #include "config.h" -#if ENABLE(3D_CANVAS) +#if ENABLE(3D_CANVAS) || ENABLE(BLOB) #include "Float32Array.h" @@ -59,4 +59,4 @@ PassRefPtr<ArrayBufferView> Float32Array::slice(int start, int end) const } -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(3D_CANVAS) || ENABLE(BLOB) diff --git a/WebCore/html/canvas/Float32Array.idl b/WebCore/html/canvas/Float32Array.idl index 5a939ca..c3c0a2d 100644 --- a/WebCore/html/canvas/Float32Array.idl +++ b/WebCore/html/canvas/Float32Array.idl @@ -26,13 +26,14 @@ module html { interface [ - Conditional=3D_CANVAS, + Conditional=3D_CANVAS|BLOB, CanBeConstructed, CustomConstructFunction, V8CustomConstructor, HasNumericIndexGetter, HasCustomIndexSetter, GenerateNativeConverter, + NoStaticTables, CustomToJS, DontCheckEnums ] Float32Array : ArrayBufferView { diff --git a/WebCore/html/canvas/Int16Array.cpp b/WebCore/html/canvas/Int16Array.cpp index f3f9742..635ea5e 100644 --- a/WebCore/html/canvas/Int16Array.cpp +++ b/WebCore/html/canvas/Int16Array.cpp @@ -25,7 +25,7 @@ #include "config.h" -#if ENABLE(3D_CANVAS) +#if ENABLE(3D_CANVAS) || ENABLE(BLOB) #include "Int16Array.h" @@ -58,4 +58,4 @@ PassRefPtr<ArrayBufferView> Int16Array::slice(int start, int end) const } -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(3D_CANVAS) || ENABLE(BLOB) diff --git a/WebCore/html/canvas/Int16Array.idl b/WebCore/html/canvas/Int16Array.idl index 02417f8..7980a69 100644 --- a/WebCore/html/canvas/Int16Array.idl +++ b/WebCore/html/canvas/Int16Array.idl @@ -25,13 +25,14 @@ module html { interface [ - Conditional=3D_CANVAS, + Conditional=3D_CANVAS|BLOB, CanBeConstructed, CustomConstructFunction, V8CustomConstructor, HasNumericIndexGetter, HasCustomIndexSetter, GenerateNativeConverter, + NoStaticTables, CustomToJS, DontCheckEnums ] Int16Array : ArrayBufferView { diff --git a/WebCore/html/canvas/Int32Array.cpp b/WebCore/html/canvas/Int32Array.cpp index 423c36b..cc926a3 100644 --- a/WebCore/html/canvas/Int32Array.cpp +++ b/WebCore/html/canvas/Int32Array.cpp @@ -26,7 +26,7 @@ #include "config.h" -#if ENABLE(3D_CANVAS) +#if ENABLE(3D_CANVAS) || ENABLE(BLOB) #include "Int32Array.h" @@ -59,4 +59,4 @@ PassRefPtr<ArrayBufferView> Int32Array::slice(int start, int end) const } -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(3D_CANVAS) || ENABLE(BLOB) diff --git a/WebCore/html/canvas/Int32Array.h b/WebCore/html/canvas/Int32Array.h index 72fb579..bd05450 100644 --- a/WebCore/html/canvas/Int32Array.h +++ b/WebCore/html/canvas/Int32Array.h @@ -37,8 +37,10 @@ class Int32Array : public IntegralTypedArrayBase<int> { static PassRefPtr<Int32Array> create(int* array, unsigned length); static PassRefPtr<Int32Array> create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length); +#if !COMPILER(RVCT) using TypedArrayBase<int>::set; using IntegralTypedArrayBase<int>::set; +#endif private: Int32Array(PassRefPtr<ArrayBuffer> buffer, diff --git a/WebCore/html/canvas/Int32Array.idl b/WebCore/html/canvas/Int32Array.idl index 6977d00..bd1554d 100644 --- a/WebCore/html/canvas/Int32Array.idl +++ b/WebCore/html/canvas/Int32Array.idl @@ -26,13 +26,14 @@ module html { interface [ - Conditional=3D_CANVAS, + Conditional=3D_CANVAS|BLOB, CanBeConstructed, CustomConstructFunction, V8CustomConstructor, HasNumericIndexGetter, HasCustomIndexSetter, GenerateNativeConverter, + NoStaticTables, CustomToJS, DontCheckEnums ] Int32Array : ArrayBufferView { diff --git a/WebCore/html/canvas/Int8Array.cpp b/WebCore/html/canvas/Int8Array.cpp index 20ff32a..c2dd2fa 100644 --- a/WebCore/html/canvas/Int8Array.cpp +++ b/WebCore/html/canvas/Int8Array.cpp @@ -26,7 +26,7 @@ #include "config.h" -#if ENABLE(3D_CANVAS) +#if ENABLE(3D_CANVAS) || ENABLE(BLOB) #include "Int8Array.h" @@ -59,4 +59,4 @@ PassRefPtr<ArrayBufferView> Int8Array::slice(int start, int end) const } -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(3D_CANVAS) || ENABLE(BLOB) diff --git a/WebCore/html/canvas/Int8Array.idl b/WebCore/html/canvas/Int8Array.idl index 4dba9e4..ec0bdb7 100644 --- a/WebCore/html/canvas/Int8Array.idl +++ b/WebCore/html/canvas/Int8Array.idl @@ -26,13 +26,14 @@ module html { interface [ - Conditional=3D_CANVAS, + Conditional=3D_CANVAS|BLOB, CanBeConstructed, CustomConstructFunction, V8CustomConstructor, HasNumericIndexGetter, HasCustomIndexSetter, GenerateNativeConverter, + NoStaticTables, CustomToJS, DontCheckEnums ] Int8Array : ArrayBufferView { diff --git a/WebCore/html/canvas/Uint16Array.cpp b/WebCore/html/canvas/Uint16Array.cpp index 4656173..a0f891c 100644 --- a/WebCore/html/canvas/Uint16Array.cpp +++ b/WebCore/html/canvas/Uint16Array.cpp @@ -26,7 +26,7 @@ #include "config.h" -#if ENABLE(3D_CANVAS) +#if ENABLE(3D_CANVAS) || ENABLE(BLOB) #include "Uint16Array.h" @@ -59,4 +59,4 @@ PassRefPtr<ArrayBufferView> Uint16Array::slice(int start, int end) const } -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(3D_CANVAS) || ENABLE(BLOB) diff --git a/WebCore/html/canvas/Uint16Array.idl b/WebCore/html/canvas/Uint16Array.idl index de1e5e0..75a7499 100644 --- a/WebCore/html/canvas/Uint16Array.idl +++ b/WebCore/html/canvas/Uint16Array.idl @@ -26,13 +26,14 @@ module html { interface [ - Conditional=3D_CANVAS, + Conditional=3D_CANVAS|BLOB, CanBeConstructed, CustomConstructFunction, V8CustomConstructor, HasNumericIndexGetter, HasCustomIndexSetter, GenerateNativeConverter, + NoStaticTables, CustomToJS, DontCheckEnums ] Uint16Array : ArrayBufferView { diff --git a/WebCore/html/canvas/Uint32Array.cpp b/WebCore/html/canvas/Uint32Array.cpp index 3f43bef..f49a83a 100644 --- a/WebCore/html/canvas/Uint32Array.cpp +++ b/WebCore/html/canvas/Uint32Array.cpp @@ -26,7 +26,7 @@ #include "config.h" -#if ENABLE(3D_CANVAS) +#if ENABLE(3D_CANVAS) || ENABLE(BLOB) #include "Uint32Array.h" @@ -59,4 +59,4 @@ PassRefPtr<ArrayBufferView> Uint32Array::slice(int start, int end) const } -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(3D_CANVAS) || ENABLE(BLOB) diff --git a/WebCore/html/canvas/Uint32Array.idl b/WebCore/html/canvas/Uint32Array.idl index ce632dd..06e17c6 100644 --- a/WebCore/html/canvas/Uint32Array.idl +++ b/WebCore/html/canvas/Uint32Array.idl @@ -26,13 +26,14 @@ module html { interface [ - Conditional=3D_CANVAS, + Conditional=3D_CANVAS|BLOB, CanBeConstructed, CustomConstructFunction, V8CustomConstructor, HasNumericIndexGetter, HasCustomIndexSetter, GenerateNativeConverter, + NoStaticTables, CustomToJS, DontCheckEnums ] Uint32Array : ArrayBufferView { diff --git a/WebCore/html/canvas/Uint8Array.cpp b/WebCore/html/canvas/Uint8Array.cpp index 13b7022..6c785f9 100644 --- a/WebCore/html/canvas/Uint8Array.cpp +++ b/WebCore/html/canvas/Uint8Array.cpp @@ -26,7 +26,7 @@ #include "config.h" -#if ENABLE(3D_CANVAS) +#if ENABLE(3D_CANVAS) || ENABLE(BLOB) #include "Uint8Array.h" @@ -59,4 +59,4 @@ PassRefPtr<ArrayBufferView> Uint8Array::slice(int start, int end) const } -#endif // ENABLE(3D_CANVAS) +#endif // ENABLE(3D_CANVAS) || ENABLE(BLOB) diff --git a/WebCore/html/canvas/Uint8Array.h b/WebCore/html/canvas/Uint8Array.h index 6e20b42..fce63da 100644 --- a/WebCore/html/canvas/Uint8Array.h +++ b/WebCore/html/canvas/Uint8Array.h @@ -39,8 +39,10 @@ class Uint8Array : public IntegralTypedArrayBase<unsigned char> { static PassRefPtr<Uint8Array> create(unsigned char* array, unsigned length); static PassRefPtr<Uint8Array> create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length); +#if !COMPILER(RVCT) using TypedArrayBase<unsigned char>::set; using IntegralTypedArrayBase<unsigned char>::set; +#endif private: Uint8Array(PassRefPtr<ArrayBuffer> buffer, diff --git a/WebCore/html/canvas/Uint8Array.idl b/WebCore/html/canvas/Uint8Array.idl index c520844..bd28023 100644 --- a/WebCore/html/canvas/Uint8Array.idl +++ b/WebCore/html/canvas/Uint8Array.idl @@ -26,13 +26,14 @@ module html { interface [ - Conditional=3D_CANVAS, + Conditional=3D_CANVAS|BLOB, CanBeConstructed, CustomConstructFunction, V8CustomConstructor, HasNumericIndexGetter, HasCustomIndexSetter, GenerateNativeConverter, + NoStaticTables, CustomToJS, DontCheckEnums ] Uint8Array : ArrayBufferView { diff --git a/WebCore/html/canvas/WebGLProgram.cpp b/WebCore/html/canvas/WebGLProgram.cpp index 0853b67..e4ffa80 100644 --- a/WebCore/html/canvas/WebGLProgram.cpp +++ b/WebCore/html/canvas/WebGLProgram.cpp @@ -40,7 +40,7 @@ PassRefPtr<WebGLProgram> WebGLProgram::create(WebGLRenderingContext* ctx) WebGLProgram::WebGLProgram(WebGLRenderingContext* ctx) : WebGLObject(ctx) - , m_linkFailure(false) + , m_linkStatus(false) { setObject(context()->graphicsContext3D()->createProgram()); } diff --git a/WebCore/html/canvas/WebGLProgram.h b/WebCore/html/canvas/WebGLProgram.h index e5548eb..3b88fdd 100644 --- a/WebCore/html/canvas/WebGLProgram.h +++ b/WebCore/html/canvas/WebGLProgram.h @@ -50,11 +50,8 @@ public: bool isUsingVertexAttrib0() const; - // Return true means getProgramParameter(LINK_STATUS) should return - // false; return false means we should actually call - // getProgramParameter(LINK_STATUS) to find out. - bool isLinkFailureFlagSet() const { return m_linkFailure; } - void setLinkFailureFlag(bool failed) { m_linkFailure = failed; } + bool getLinkStatus() const { return m_linkStatus; } + void setLinkStatus(bool status) { m_linkStatus = status; } WebGLShader* getAttachedShader(GraphicsContext3D::WebGLEnumType); bool attachShader(WebGLShader*); @@ -70,7 +67,7 @@ private: Vector<int> m_activeAttribLocations; - bool m_linkFailure; + bool m_linkStatus; RefPtr<WebGLShader> m_vertexShader; RefPtr<WebGLShader> m_fragmentShader; diff --git a/WebCore/html/canvas/WebGLRenderingContext.cpp b/WebCore/html/canvas/WebGLRenderingContext.cpp index d1bb0cd..a8751da 100644 --- a/WebCore/html/canvas/WebGLRenderingContext.cpp +++ b/WebCore/html/canvas/WebGLRenderingContext.cpp @@ -88,15 +88,15 @@ PassOwnPtr<WebGLRenderingContext> WebGLRenderingContext::create(HTMLCanvasElemen { HostWindow* hostWindow = canvas->document()->view()->root()->hostWindow(); GraphicsContext3D::Attributes emptyAttributes; - OwnPtr<GraphicsContext3D> context(GraphicsContext3D::create(attrs ? attrs->attributes() : emptyAttributes, hostWindow)); + RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(attrs ? attrs->attributes() : emptyAttributes, hostWindow)); if (!context) return 0; - return new WebGLRenderingContext(canvas, context.release()); + return new WebGLRenderingContext(canvas, context); } -WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, PassOwnPtr<GraphicsContext3D> context) +WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, PassRefPtr<GraphicsContext3D> context) : CanvasRenderingContext(passedCanvas) , m_context(context) , m_needsUpdate(true) @@ -1484,10 +1484,7 @@ WebGLGetInfo WebGLRenderingContext::getProgramParameter(WebGLProgram* program, u m_context->getProgramiv(objectOrZero(program), pname, &value); return WebGLGetInfo(static_cast<bool>(value)); case GraphicsContext3D::LINK_STATUS: - if (program->isLinkFailureFlagSet()) - return WebGLGetInfo(false); - m_context->getProgramiv(objectOrZero(program), pname, &value); - return WebGLGetInfo(static_cast<bool>(value)); + return WebGLGetInfo(program->getLinkStatus()); case GraphicsContext3D::INFO_LOG_LENGTH: case GraphicsContext3D::ATTACHED_SHADERS: case GraphicsContext3D::ACTIVE_ATTRIBUTES: @@ -1897,14 +1894,17 @@ void WebGLRenderingContext::linkProgram(WebGLProgram* program, ExceptionCode& ec return; if (!isGLES2Compliant()) { if (!program->getAttachedShader(GraphicsContext3D::VERTEX_SHADER) || !program->getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER)) { - program->setLinkFailureFlag(true); + program->setLinkStatus(false); return; } - program->setLinkFailureFlag(false); } m_context->linkProgram(objectOrZero(program)); program->cacheActiveAttribLocations(); + // cache link status + int value = 0; + m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::LINK_STATUS, &value); + program->setLinkStatus(static_cast<bool>(value)); cleanupAfterGraphicsCall(false); } @@ -2714,11 +2714,12 @@ void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* locatio void WebGLRenderingContext::useProgram(WebGLProgram* program, ExceptionCode& ec) { + UNUSED_PARAM(ec); if (program && program->context() != this) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } - if (program && program->object() && !getProgramParameter(program, GraphicsContext3D::LINK_STATUS, ec).getBool()) { + if (program && program->object() && !program->getLinkStatus()) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); cleanupAfterGraphicsCall(false); return; diff --git a/WebCore/html/canvas/WebGLRenderingContext.h b/WebCore/html/canvas/WebGLRenderingContext.h index f507054..c4c856c 100644 --- a/WebCore/html/canvas/WebGLRenderingContext.h +++ b/WebCore/html/canvas/WebGLRenderingContext.h @@ -291,7 +291,7 @@ public: private: friend class WebGLObject; - WebGLRenderingContext(HTMLCanvasElement*, PassOwnPtr<GraphicsContext3D>); + WebGLRenderingContext(HTMLCanvasElement*, PassRefPtr<GraphicsContext3D>); void addObject(WebGLObject*); void detachAndRemoveAllObjects(); @@ -329,7 +329,7 @@ public: PassRefPtr<Image> videoFrameToImage(HTMLVideoElement* video); - OwnPtr<GraphicsContext3D> m_context; + RefPtr<GraphicsContext3D> m_context; bool m_needsUpdate; bool m_markedCanvasDirty; // FIXME: I think this is broken -- it does not increment any diff --git a/WebCore/html/parser/CSSPreloadScanner.cpp b/WebCore/html/parser/CSSPreloadScanner.cpp index 6ac923d..23364f9 100644 --- a/WebCore/html/parser/CSSPreloadScanner.cpp +++ b/WebCore/html/parser/CSSPreloadScanner.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2010 Apple Inc. All Rights Reserved. * Copyright (C) 2009 Torch Mobile, Inc. http://www.torchmobile.com/ * Copyright (C) 2010 Google Inc. All Rights Reserved. * @@ -28,23 +28,18 @@ #include "config.h" #include "CSSPreloadScanner.h" -#include "CSSHelper.h" #include "CachedCSSStyleSheet.h" #include "CachedResourceLoader.h" #include "Document.h" +#include "HTMLParserIdioms.h" #include "HTMLToken.h" namespace WebCore { -static inline bool isWhitespace(UChar c) -{ - return c == ' ' || c == '\n' || c == '\r' || c == '\t'; -} - CSSPreloadScanner::CSSPreloadScanner(Document* document) - : m_document(document) + : m_state(Initial) + , m_document(document) { - reset(); } void CSSPreloadScanner::reset() @@ -59,10 +54,8 @@ void CSSPreloadScanner::scan(const HTMLToken& token, bool scanningBody) m_scanningBody = scanningBody; const HTMLToken::DataVector& characters = token.characters(); - for (HTMLToken::DataVector::const_iterator iter = characters.begin(); - iter != characters.end(); ++iter) { + for (HTMLToken::DataVector::const_iterator iter = characters.begin(); iter != characters.end(); ++iter) tokenize(*iter); - } } inline void CSSPreloadScanner::tokenize(UChar c) @@ -104,7 +97,7 @@ inline void CSSPreloadScanner::tokenize(UChar c) m_state = Initial; break; case Rule: - if (isWhitespace(c)) + if (isHTMLSpace(c)) m_state = AfterRule; else if (c == ';') m_state = Initial; @@ -112,7 +105,7 @@ inline void CSSPreloadScanner::tokenize(UChar c) m_rule.append(c); break; case AfterRule: - if (isWhitespace(c)) + if (isHTMLSpace(c)) ; else if (c == ';') m_state = Initial; @@ -122,7 +115,7 @@ inline void CSSPreloadScanner::tokenize(UChar c) } break; case RuleValue: - if (isWhitespace(c)) + if (isHTMLSpace(c)) m_state = AfterRuleValue; else if (c == ';') { emitRule(); @@ -131,7 +124,7 @@ inline void CSSPreloadScanner::tokenize(UChar c) m_ruleValue.append(c); break; case AfterRuleValue: - if (isWhitespace(c)) + if (isHTMLSpace(c)) ; else if (c == ';') { emitRule(); @@ -144,14 +137,56 @@ inline void CSSPreloadScanner::tokenize(UChar c) } } +static String parseCSSStringOrURL(const UChar* characters, size_t length) +{ + size_t offset = 0; + size_t reducedLength = length; + + while (reducedLength && isHTMLSpace(characters[offset])) { + ++offset; + --reducedLength; + } + while (reducedLength && isHTMLSpace(characters[offset + reducedLength - 1])) + --reducedLength; + + if (reducedLength >= 5 + && (characters[offset] == 'u' || characters[offset] == 'U') + && (characters[offset + 1] == 'r' || characters[offset + 1] == 'R') + && (characters[offset + 2] == 'l' || characters[offset + 2] == 'L') + && characters[offset + 3] == '(' + && characters[offset + reducedLength - 1] == ')') { + offset += 4; + reducedLength -= 5; + } + + while (reducedLength && isHTMLSpace(characters[offset])) { + ++offset; + --reducedLength; + } + while (reducedLength && isHTMLSpace(characters[offset + reducedLength - 1])) + --reducedLength; + + if (reducedLength < 2 || characters[offset] != characters[offset + reducedLength - 1] || !(characters[offset] == '\'' || characters[offset] == '"')) + return String(); + offset++; + reducedLength -= 2; + + while (reducedLength && isHTMLSpace(characters[offset])) { + ++offset; + --reducedLength; + } + while (reducedLength && isHTMLSpace(characters[offset + reducedLength - 1])) + --reducedLength; + + return String(characters + offset, reducedLength); +} + void CSSPreloadScanner::emitRule() { - String rule(m_rule.data(), m_rule.size()); - if (equalIgnoringCase(rule, "import") && !m_ruleValue.isEmpty()) { - String value(m_ruleValue.data(), m_ruleValue.size()); - String url = deprecatedParseURL(value); - if (!url.isEmpty()) - m_document->cachedResourceLoader()->preload(CachedResource::CSSStyleSheet, url, String(), m_scanningBody); + if (equalIgnoringCase("import", m_rule.data(), m_rule.size())) { + String value = parseCSSStringOrURL(m_ruleValue.data(), m_ruleValue.size()); + if (!value.isEmpty()) + m_document->cachedResourceLoader()->preload(CachedResource::CSSStyleSheet, value, String(), m_scanningBody); } m_rule.clear(); m_ruleValue.clear(); diff --git a/WebCore/html/parser/HTMLConstructionSite.cpp b/WebCore/html/parser/HTMLConstructionSite.cpp index 6215bba..7201ac7 100644 --- a/WebCore/html/parser/HTMLConstructionSite.cpp +++ b/WebCore/html/parser/HTMLConstructionSite.cpp @@ -168,9 +168,12 @@ void HTMLConstructionSite::dispatchDocumentElementAvailableIfNeeded() void HTMLConstructionSite::insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken& token) { - RefPtr<Element> element = HTMLHtmlElement::create(m_document); + RefPtr<HTMLHtmlElement> element = HTMLHtmlElement::create(m_document); element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission); - m_openElements.pushHTMLHtmlElement(attach(m_document, element.release())); + m_openElements.pushHTMLHtmlElement(attach<Element>(m_document, element.get())); +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + element->insertedByParser(); +#endif dispatchDocumentElementAvailableIfNeeded(); } @@ -234,13 +237,6 @@ PassRefPtr<Element> HTMLConstructionSite::attachToCurrent(PassRefPtr<Element> ch return attach(currentElement(), child); } -void HTMLConstructionSite::insertHTMLHtmlElement(AtomicHTMLToken& token) -{ - ASSERT(!shouldFosterParent()); - m_openElements.pushHTMLHtmlElement(attachToCurrent(createHTMLElement(token))); - dispatchDocumentElementAvailableIfNeeded(); -} - void HTMLConstructionSite::insertHTMLHeadElement(AtomicHTMLToken& token) { ASSERT(!shouldFosterParent()); diff --git a/WebCore/html/parser/HTMLConstructionSite.h b/WebCore/html/parser/HTMLConstructionSite.h index 6bed6a7..8b09bf5 100644 --- a/WebCore/html/parser/HTMLConstructionSite.h +++ b/WebCore/html/parser/HTMLConstructionSite.h @@ -54,7 +54,6 @@ public: void insertHTMLElement(AtomicHTMLToken&); void insertSelfClosingHTMLElement(AtomicHTMLToken&); void insertFormattingElement(AtomicHTMLToken&); - void insertHTMLHtmlElement(AtomicHTMLToken&); void insertHTMLHeadElement(AtomicHTMLToken&); void insertHTMLBodyElement(AtomicHTMLToken&); void insertHTMLFormElement(AtomicHTMLToken&, bool isDemoted = false); diff --git a/WebCore/html/parser/HTMLDocumentParser.cpp b/WebCore/html/parser/HTMLDocumentParser.cpp index dc19c96..743e5d5 100644 --- a/WebCore/html/parser/HTMLDocumentParser.cpp +++ b/WebCore/html/parser/HTMLDocumentParser.cpp @@ -36,11 +36,13 @@ #include "HTMLScriptRunner.h" #include "HTMLTreeBuilder.h" #include "HTMLDocument.h" +#include "InspectorInstrumentation.h" #include "NestingLevelIncrementer.h" #include "Settings.h" #include "XSSAuditor.h" #include <wtf/CurrentTime.h> +<<<<<<< HEAD #ifdef ANDROID_INSTRUMENT #include "TimeCounter.h" #endif @@ -49,6 +51,8 @@ #include "InspectorTimelineAgent.h" #endif +======= +>>>>>>> webkit.org at r70209 namespace WebCore { using namespace HTMLNames; @@ -214,9 +218,12 @@ void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode) // ASSERT that this object is both attached to the Document and protected. ASSERT(refCount() >= 2); - // We tell the InspectorTimelineAgent about every pump, even if we + // We tell the InspectorInstrumentation about every pump, even if we // end up pumping nothing. It can filter out empty pumps itself. - willPumpLexer(); + // FIXME: m_input.current().length() is only accurate if we + // end up parsing the whole buffer in this pump. We should pass how + // much we parsed as part of didWriteHTML instead of willWriteHTML. + InspectorInstrumentationCookie cookie = InspectorInstrumentation::willWriteHTML(document(), m_input.current().length(), m_tokenizer->lineNumber()); HTMLParserScheduler::PumpSession session; // FIXME: This loop body has is now too long and needs cleanup. @@ -260,26 +267,7 @@ void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode) m_preloadScanner->scan(); } - didPumpLexer(); -} - -void HTMLDocumentParser::willPumpLexer() -{ -#if ENABLE(INSPECTOR) - // FIXME: m_input.current().length() is only accurate if we - // end up parsing the whole buffer in this pump. We should pass how - // much we parsed as part of didWriteHTML instead of willWriteHTML. - if (InspectorTimelineAgent* timelineAgent = document()->inspectorTimelineAgent()) - timelineAgent->willWriteHTML(m_input.current().length(), m_tokenizer->lineNumber()); -#endif -} - -void HTMLDocumentParser::didPumpLexer() -{ -#if ENABLE(INSPECTOR) - if (InspectorTimelineAgent* timelineAgent = document()->inspectorTimelineAgent()) - timelineAgent->didWriteHTML(m_tokenizer->lineNumber()); -#endif + InspectorInstrumentation::didWriteHTML(cookie, m_tokenizer->lineNumber()); } bool HTMLDocumentParser::hasInsertionPoint() diff --git a/WebCore/html/parser/HTMLDocumentParser.h b/WebCore/html/parser/HTMLDocumentParser.h index e65a582..d9625f1 100644 --- a/WebCore/html/parser/HTMLDocumentParser.h +++ b/WebCore/html/parser/HTMLDocumentParser.h @@ -103,9 +103,6 @@ private: // CachedResourceClient virtual void notifyFinished(CachedResource*); - void willPumpLexer(); - void didPumpLexer(); - enum SynchronousMode { AllowYield, ForceSynchronous, diff --git a/WebCore/html/parser/HTMLElementStack.cpp b/WebCore/html/parser/HTMLElementStack.cpp index 123778d..6b96291 100644 --- a/WebCore/html/parser/HTMLElementStack.cpp +++ b/WebCore/html/parser/HTMLElementStack.cpp @@ -113,6 +113,12 @@ inline bool isButtonScopeMarker(Element* element) || element->hasTagName(buttonTag); } +inline bool isSelectScopeMarker(Element* element) +{ + return !element->hasTagName(optgroupTag) + && !element->hasTagName(optionTag); +} + } HTMLElementStack::ElementRecord::ElementRecord(PassRefPtr<Element> element, PassOwnPtr<ElementRecord> next) @@ -486,6 +492,17 @@ bool HTMLElementStack::inButtonScope(const QualifiedName& tagName) const return inButtonScope(tagName.localName()); } +bool HTMLElementStack::inSelectScope(const AtomicString& targetTag) const +{ + return inScopeCommon<isSelectScopeMarker>(m_top.get(), targetTag); +} + +bool HTMLElementStack::inSelectScope(const QualifiedName& tagName) const +{ + // FIXME: Is localName() right for non-html elements? + return inSelectScope(tagName.localName()); +} + Element* HTMLElementStack::htmlElement() const { ASSERT(m_htmlElement); diff --git a/WebCore/html/parser/HTMLElementStack.h b/WebCore/html/parser/HTMLElementStack.h index 47fa603..8a8e160 100644 --- a/WebCore/html/parser/HTMLElementStack.h +++ b/WebCore/html/parser/HTMLElementStack.h @@ -117,6 +117,8 @@ public: bool inTableScope(const QualifiedName&) const; bool inButtonScope(const AtomicString& tagName) const; bool inButtonScope(const QualifiedName&) const; + bool inSelectScope(const AtomicString& tagName) const; + bool inSelectScope(const QualifiedName&) const; bool hasOnlyHTMLElementsInScope() const; bool hasNumberedHeaderElementInScope() const; diff --git a/WebCore/html/parser/HTMLParserIdioms.cpp b/WebCore/html/parser/HTMLParserIdioms.cpp index a558cf5..f093eb2 100644 --- a/WebCore/html/parser/HTMLParserIdioms.cpp +++ b/WebCore/html/parser/HTMLParserIdioms.cpp @@ -43,7 +43,7 @@ String stripLeadingAndTrailingHTMLSpaces(const String& string) } if (numLeadingSpaces == length) - return emptyAtom; + return string.isNull() ? string : emptyAtom.string(); unsigned numTrailingSpaces; for (numTrailingSpaces = 0; numTrailingSpaces < length; ++numTrailingSpaces) { @@ -53,7 +53,7 @@ String stripLeadingAndTrailingHTMLSpaces(const String& string) ASSERT(numLeadingSpaces + numTrailingSpaces < length); - return string.substring(numLeadingSpaces, length - numTrailingSpaces); + return string.substring(numLeadingSpaces, length - (numLeadingSpaces + numTrailingSpaces)); } String serializeForNumberType(double number) diff --git a/WebCore/html/parser/HTMLParserIdioms.h b/WebCore/html/parser/HTMLParserIdioms.h index f4704f7..4839138 100644 --- a/WebCore/html/parser/HTMLParserIdioms.h +++ b/WebCore/html/parser/HTMLParserIdioms.h @@ -52,8 +52,17 @@ bool parseHTMLInteger(const String&, int&); inline bool isHTMLSpace(UChar character) { - // FIXME: Consider branch permutations as we did in isASCIISpace. - return character == '\t' || character == '\x0A' || character == '\x0C' || character == '\x0D' || character == ' '; + // Histogram from Apple's page load test combined with some ad hoc browsing some other test suites. + // + // 82%: 216330 non-space characters, all > U+0020 + // 11%: 30017 plain space characters, U+0020 + // 5%: 12099 newline characters, U+000A + // 2%: 5346 tab characters, U+0009 + // + // No other characters seen. No U+000C or U+000D, and no other control characters. + // Accordingly, we check for non-spaces first, then space, then newline, then tab, then the other characters. + + return character <= ' ' && (character == ' ' || character == '\n' || character == '\t' || character == '\r' || character == '\f'); } inline bool isNotHTMLSpace(UChar character) diff --git a/WebCore/html/parser/HTMLPreloadScanner.cpp b/WebCore/html/parser/HTMLPreloadScanner.cpp index 7859dd8..5c86579 100644 --- a/WebCore/html/parser/HTMLPreloadScanner.cpp +++ b/WebCore/html/parser/HTMLPreloadScanner.cpp @@ -28,13 +28,13 @@ #include "config.h" #include "HTMLPreloadScanner.h" -#include "CSSHelper.h" #include "CachedResourceLoader.h" #include "Document.h" #include "HTMLDocumentParser.h" #include "HTMLTokenizer.h" #include "HTMLLinkElement.h" #include "HTMLNames.h" +#include "HTMLParserIdioms.h" namespace WebCore { @@ -90,7 +90,7 @@ public: // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#attribute-name-state if (!m_urlToLoad.isEmpty()) return; - m_urlToLoad = deprecatedParseURL(attributeValue); + m_urlToLoad = stripLeadingAndTrailingHTMLSpaces(attributeValue); } void preload(Document* document, bool scanningBody) diff --git a/WebCore/html/parser/HTMLTreeBuilder.cpp b/WebCore/html/parser/HTMLTreeBuilder.cpp index 355dc8d..5f90285 100644 --- a/WebCore/html/parser/HTMLTreeBuilder.cpp +++ b/WebCore/html/parser/HTMLTreeBuilder.cpp @@ -1422,7 +1422,7 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token) || token.name() == keygenTag || token.name() == textareaTag) { parseError(token); - if (!m_tree.openElements()->inTableScope(selectTag)) { + if (!m_tree.openElements()->inSelectScope(selectTag)) { ASSERT(isParsingFragment()); return; } @@ -1849,7 +1849,7 @@ void HTMLTreeBuilder::processEndTagForInCell(AtomicHTMLToken& token) || token.name() == trTag || isTableBodyContextTag(token.name())) { if (!m_tree.openElements()->inTableScope(token.name())) { - ASSERT(isParsingFragment()); + ASSERT(isTableBodyContextTag(token.name()) || isParsingFragment()); parseError(token); return; } @@ -2279,7 +2279,7 @@ void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token) return; } if (token.name() == selectTag) { - if (!m_tree.openElements()->inTableScope(token.name())) { + if (!m_tree.openElements()->inSelectScope(token.name())) { ASSERT(isParsingFragment()); parseError(token); return; |