summaryrefslogtreecommitdiff
path: root/Source/WebCore/html
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/html')
-rw-r--r--Source/WebCore/html/BaseCheckableInputType.cpp10
-rw-r--r--Source/WebCore/html/BaseCheckableInputType.h4
-rw-r--r--Source/WebCore/html/BaseDateAndTimeInputType.cpp42
-rw-r--r--Source/WebCore/html/BaseDateAndTimeInputType.h11
-rw-r--r--Source/WebCore/html/CollectionType.h1
-rw-r--r--Source/WebCore/html/DOMURL.cpp2
-rw-r--r--Source/WebCore/html/DateInputType.cpp14
-rw-r--r--Source/WebCore/html/DateTimeInputType.cpp18
-rw-r--r--Source/WebCore/html/DateTimeInputType.h2
-rw-r--r--Source/WebCore/html/DateTimeLocalInputType.cpp14
-rw-r--r--Source/WebCore/html/FileInputType.cpp39
-rw-r--r--Source/WebCore/html/FileInputType.h14
-rw-r--r--Source/WebCore/html/FormAssociatedElement.cpp15
-rw-r--r--Source/WebCore/html/FormAssociatedElement.h7
-rw-r--r--Source/WebCore/html/FormController.cpp181
-rw-r--r--Source/WebCore/html/FormController.h138
-rw-r--r--Source/WebCore/html/HTMLButtonElement.cpp5
-rw-r--r--Source/WebCore/html/HTMLButtonElement.h2
-rw-r--r--Source/WebCore/html/HTMLButtonElement.idl2
-rw-r--r--Source/WebCore/html/HTMLCollection.cpp8
-rw-r--r--Source/WebCore/html/HTMLElement.cpp2
-rw-r--r--Source/WebCore/html/HTMLFormCollection.cpp1
-rw-r--r--Source/WebCore/html/HTMLFormCollection.h2
-rw-r--r--Source/WebCore/html/HTMLFormControlElement.cpp11
-rw-r--r--Source/WebCore/html/HTMLFormControlElement.h7
-rw-r--r--Source/WebCore/html/HTMLFormControlElementWithState.cpp20
-rw-r--r--Source/WebCore/html/HTMLFormControlElementWithState.h7
-rw-r--r--Source/WebCore/html/HTMLFormElement.cpp5
-rw-r--r--Source/WebCore/html/HTMLInputElement.cpp115
-rw-r--r--Source/WebCore/html/HTMLInputElement.h27
-rw-r--r--Source/WebCore/html/HTMLKeygenElement.idl2
-rw-r--r--Source/WebCore/html/HTMLMediaElement.cpp65
-rw-r--r--Source/WebCore/html/HTMLMediaElement.h1
-rw-r--r--Source/WebCore/html/HTMLMetaElement.cpp2
-rw-r--r--Source/WebCore/html/HTMLObjectElement.cpp6
-rw-r--r--Source/WebCore/html/HTMLObjectElement.h6
-rw-r--r--Source/WebCore/html/HTMLPropertiesCollection.cpp2
-rw-r--r--Source/WebCore/html/HTMLSelectElement.cpp20
-rw-r--r--Source/WebCore/html/HTMLSelectElement.h6
-rw-r--r--Source/WebCore/html/HTMLSelectElement.idl3
-rw-r--r--Source/WebCore/html/HTMLStyleElement.cpp78
-rw-r--r--Source/WebCore/html/HTMLStyleElement.h15
-rw-r--r--Source/WebCore/html/HTMLTextAreaElement.cpp12
-rw-r--r--Source/WebCore/html/HTMLTextAreaElement.h4
-rw-r--r--Source/WebCore/html/HTMLTextAreaElement.idl2
-rw-r--r--Source/WebCore/html/HiddenInputType.cpp11
-rw-r--r--Source/WebCore/html/HiddenInputType.h4
-rw-r--r--Source/WebCore/html/InputType.cpp158
-rw-r--r--Source/WebCore/html/InputType.h42
-rw-r--r--Source/WebCore/html/LabelsNodeList.cpp5
-rw-r--r--Source/WebCore/html/MediaController.cpp5
-rw-r--r--Source/WebCore/html/MediaDocument.cpp4
-rw-r--r--Source/WebCore/html/MediaFragmentURIParser.cpp16
-rw-r--r--Source/WebCore/html/MonthInputType.cpp22
-rw-r--r--Source/WebCore/html/MonthInputType.h4
-rw-r--r--Source/WebCore/html/NumberInputType.cpp148
-rw-r--r--Source/WebCore/html/NumberInputType.h10
-rw-r--r--Source/WebCore/html/PasswordInputType.cpp7
-rw-r--r--Source/WebCore/html/PasswordInputType.h4
-rw-r--r--Source/WebCore/html/RadioInputType.cpp5
-rw-r--r--Source/WebCore/html/RadioInputType.h2
-rw-r--r--Source/WebCore/html/RadioNodeList.cpp4
-rw-r--r--Source/WebCore/html/RadioNodeList.h6
-rw-r--r--Source/WebCore/html/RangeInputType.cpp70
-rw-r--r--Source/WebCore/html/RangeInputType.h8
-rw-r--r--Source/WebCore/html/SearchInputType.cpp30
-rw-r--r--Source/WebCore/html/SearchInputType.h6
-rw-r--r--Source/WebCore/html/StepRange.cpp106
-rw-r--r--Source/WebCore/html/StepRange.h64
-rw-r--r--Source/WebCore/html/TextFieldInputType.cpp10
-rw-r--r--Source/WebCore/html/TextFieldInputType.h2
-rw-r--r--Source/WebCore/html/TimeInputType.cpp18
-rw-r--r--Source/WebCore/html/TimeInputType.h2
-rw-r--r--Source/WebCore/html/WeekInputType.cpp14
-rw-r--r--Source/WebCore/html/canvas/CanvasRenderingContext.cpp5
-rw-r--r--Source/WebCore/html/canvas/WebGLDepthTexture.cpp65
-rw-r--r--Source/WebCore/html/canvas/WebGLDepthTexture.h49
-rw-r--r--Source/WebCore/html/canvas/WebGLDepthTexture.idl33
-rw-r--r--Source/WebCore/html/canvas/WebGLExtension.h1
-rw-r--r--Source/WebCore/html/canvas/WebGLFramebuffer.cpp627
-rw-r--r--Source/WebCore/html/canvas/WebGLFramebuffer.h46
-rw-r--r--Source/WebCore/html/canvas/WebGLRenderingContext.cpp181
-rw-r--r--Source/WebCore/html/canvas/WebGLRenderingContext.h12
-rw-r--r--Source/WebCore/html/parser/HTMLConstructionSite.h1
-rw-r--r--Source/WebCore/html/parser/HTMLParserIdioms.cpp39
-rw-r--r--Source/WebCore/html/parser/HTMLParserIdioms.h7
-rw-r--r--Source/WebCore/html/parser/HTMLParserScheduler.cpp1
-rw-r--r--Source/WebCore/html/parser/HTMLParserScheduler.h6
-rw-r--r--Source/WebCore/html/shadow/CalendarPickerElement.cpp2
-rw-r--r--Source/WebCore/html/shadow/HTMLContentElement.cpp4
-rw-r--r--Source/WebCore/html/shadow/InsertionPoint.cpp8
-rw-r--r--Source/WebCore/html/shadow/InsertionPoint.h1
-rw-r--r--Source/WebCore/html/shadow/MediaControlElements.cpp11
-rw-r--r--Source/WebCore/html/shadow/MediaControlElements.h4
-rw-r--r--Source/WebCore/html/shadow/MediaControlRootElementChromium.cpp179
-rw-r--r--Source/WebCore/html/shadow/MediaControlRootElementChromium.h33
-rw-r--r--Source/WebCore/html/shadow/SliderThumbElement.cpp94
-rw-r--r--Source/WebCore/html/shadow/TextControlInnerElements.cpp4
-rw-r--r--Source/WebCore/html/track/LoadableTextTrack.cpp3
-rw-r--r--Source/WebCore/html/track/LoadableTextTrack.h1
-rw-r--r--Source/WebCore/html/track/TextTrack.cpp1
-rw-r--r--Source/WebCore/html/track/TextTrackCue.cpp73
-rw-r--r--Source/WebCore/html/track/TextTrackCue.h5
-rw-r--r--Source/WebCore/html/track/TextTrackList.idl1
-rw-r--r--Source/WebCore/html/track/WebVTTParser.h3
105 files changed, 2151 insertions, 1086 deletions
diff --git a/Source/WebCore/html/BaseCheckableInputType.cpp b/Source/WebCore/html/BaseCheckableInputType.cpp
index f578acbe7..1900ad296 100644
--- a/Source/WebCore/html/BaseCheckableInputType.cpp
+++ b/Source/WebCore/html/BaseCheckableInputType.cpp
@@ -32,6 +32,7 @@
#include "config.h"
#include "BaseCheckableInputType.h"
+#include "FormController.h"
#include "FormDataList.h"
#include "HTMLInputElement.h"
#include "HTMLNames.h"
@@ -42,15 +43,14 @@ namespace WebCore {
using namespace HTMLNames;
-bool BaseCheckableInputType::saveFormControlState(String& result) const
+FormControlState BaseCheckableInputType::saveFormControlState() const
{
- result = element()->checked() ? "on" : "off";
- return true;
+ return FormControlState(element()->checked() ? "on" : "off");
}
-void BaseCheckableInputType::restoreFormControlState(const String& state)
+void BaseCheckableInputType::restoreFormControlState(const FormControlState& state)
{
- element()->setChecked(state == "on");
+ element()->setChecked(state.value() == "on");
}
bool BaseCheckableInputType::appendFormData(FormDataList& encoding, bool) const
diff --git a/Source/WebCore/html/BaseCheckableInputType.h b/Source/WebCore/html/BaseCheckableInputType.h
index 860d6fd90..5f8a66522 100644
--- a/Source/WebCore/html/BaseCheckableInputType.h
+++ b/Source/WebCore/html/BaseCheckableInputType.h
@@ -42,8 +42,8 @@ protected:
virtual void handleKeydownEvent(KeyboardEvent*);
private:
- virtual bool saveFormControlState(String&) const OVERRIDE;
- virtual void restoreFormControlState(const String&) OVERRIDE;
+ virtual FormControlState saveFormControlState() const OVERRIDE;
+ virtual void restoreFormControlState(const FormControlState&) OVERRIDE;
virtual bool appendFormData(FormDataList&, bool) const OVERRIDE;
virtual void handleKeypressEvent(KeyboardEvent*) OVERRIDE;
virtual bool canSetStringValue() const OVERRIDE;
diff --git a/Source/WebCore/html/BaseDateAndTimeInputType.cpp b/Source/WebCore/html/BaseDateAndTimeInputType.cpp
index 4c7309191..48471cb65 100644
--- a/Source/WebCore/html/BaseDateAndTimeInputType.cpp
+++ b/Source/WebCore/html/BaseDateAndTimeInputType.cpp
@@ -47,12 +47,12 @@ namespace WebCore {
using namespace HTMLNames;
using namespace std;
-static const double msecPerMinute = 60 * 1000;
-static const double msecPerSecond = 1000;
+static const int msecPerMinute = 60 * 1000;
+static const int msecPerSecond = 1000;
double BaseDateAndTimeInputType::valueAsDate() const
{
- return parseToDouble(element()->value(), DateComponents::invalidMilliseconds());
+ return valueAsDouble();
}
void BaseDateAndTimeInputType::setValueAsDate(double value, ExceptionCode&) const
@@ -60,12 +60,12 @@ void BaseDateAndTimeInputType::setValueAsDate(double value, ExceptionCode&) cons
element()->setValue(serializeWithMilliseconds(value));
}
-double BaseDateAndTimeInputType::valueAsNumber() const
+double BaseDateAndTimeInputType::valueAsDouble() const
{
- return parseToDouble(element()->value(), numeric_limits<double>::quiet_NaN());
+ return parseToDouble(element()->value());
}
-void BaseDateAndTimeInputType::setValueAsNumber(double newValue, TextFieldEventBehavior eventBehavior, ExceptionCode&) const
+void BaseDateAndTimeInputType::setValueAsDecimal(const Decimal& newValue, TextFieldEventBehavior eventBehavior, ExceptionCode&) const
{
element()->setValue(serialize(newValue), eventBehavior);
}
@@ -80,13 +80,13 @@ bool BaseDateAndTimeInputType::typeMismatch() const
return typeMismatchFor(element()->value());
}
-double BaseDateAndTimeInputType::defaultValueForStepUp() const
+Decimal BaseDateAndTimeInputType::defaultValueForStepUp() const
{
double ms = currentTimeMS();
double utcOffset = calculateUTCOffset();
double dstOffset = calculateDSTOffset(ms, utcOffset);
int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
- return ms + (offset * msPerMinute);
+ return Decimal::fromDouble(ms + (offset * msPerMinute));
}
bool BaseDateAndTimeInputType::isSteppable() const
@@ -108,16 +108,22 @@ void BaseDateAndTimeInputType::handleWheelEvent(WheelEvent* event)
handleWheelEventForSpinButton(event);
}
-double BaseDateAndTimeInputType::parseToDouble(const String& src, double defaultValue) const
+double BaseDateAndTimeInputType::parseToDouble(const String& source) const
{
DateComponents date;
- if (!parseToDateComponents(src, &date))
- return defaultValue;
+ if (!parseToDateComponents(source, &date))
+ return DateComponents::invalidMilliseconds();
double msec = date.millisecondsSinceEpoch();
ASSERT(isfinite(msec));
return msec;
}
+Decimal BaseDateAndTimeInputType::parseToNumber(const String& source, const Decimal& defaultValue) const
+{
+ const double doubleValue = parseToDouble(source);
+ return isfinite(doubleValue) ? Decimal::fromDouble(doubleValue) : defaultValue;
+}
+
bool BaseDateAndTimeInputType::parseToDateComponents(const String& source, DateComponents* out) const
{
if (source.isEmpty())
@@ -128,31 +134,31 @@ bool BaseDateAndTimeInputType::parseToDateComponents(const String& source, DateC
return parseToDateComponentsInternal(source.characters(), source.length(), out);
}
-String BaseDateAndTimeInputType::serialize(double value) const
+String BaseDateAndTimeInputType::serialize(const Decimal& value) const
{
- if (!isfinite(value))
+ if (!value.isFinite())
return String();
DateComponents date;
- if (!setMillisecondToDateComponents(value, &date))
+ if (!setMillisecondToDateComponents(value.toDouble(), &date))
return String();
return serializeWithComponents(date);
}
String BaseDateAndTimeInputType::serializeWithComponents(const DateComponents& date) const
{
- double step;
+ Decimal step;
if (!element()->getAllowedValueStep(&step))
return date.toString();
- if (!fmod(step, msecPerMinute))
+ if (step.remainder(msecPerMinute).isZero())
return date.toString(DateComponents::None);
- if (!fmod(step, msecPerSecond))
+ if (step.remainder(msecPerSecond).isZero())
return date.toString(DateComponents::Second);
return date.toString(DateComponents::Millisecond);
}
String BaseDateAndTimeInputType::serializeWithMilliseconds(double value) const
{
- return serialize(value);
+ return serialize(Decimal::fromDouble(value));
}
String BaseDateAndTimeInputType::localizeValue(const String& proposedValue) const
diff --git a/Source/WebCore/html/BaseDateAndTimeInputType.h b/Source/WebCore/html/BaseDateAndTimeInputType.h
index da9519101..1658c1fe0 100644
--- a/Source/WebCore/html/BaseDateAndTimeInputType.h
+++ b/Source/WebCore/html/BaseDateAndTimeInputType.h
@@ -42,7 +42,7 @@ class BaseDateAndTimeInputType : public TextFieldInputType {
protected:
BaseDateAndTimeInputType(HTMLInputElement* element) : TextFieldInputType(element) { }
virtual void handleKeydownEvent(KeyboardEvent*) OVERRIDE;
- virtual double parseToDouble(const String&, double) const OVERRIDE;
+ virtual Decimal parseToNumber(const String&, const Decimal&) const OVERRIDE;
virtual bool parseToDateComponents(const String&, DateComponents*) const OVERRIDE;
String serializeWithComponents(const DateComponents&) const;
@@ -52,19 +52,20 @@ private:
virtual DateComponents::Type dateType() const = 0;
virtual double valueAsDate() const OVERRIDE;
virtual void setValueAsDate(double, ExceptionCode&) const OVERRIDE;
- virtual double valueAsNumber() const OVERRIDE;
- virtual void setValueAsNumber(double, TextFieldEventBehavior, ExceptionCode&) const OVERRIDE;
+ virtual double valueAsDouble() const OVERRIDE;
+ virtual void setValueAsDecimal(const Decimal&, TextFieldEventBehavior, ExceptionCode&) const OVERRIDE;
virtual bool typeMismatchFor(const String&) const OVERRIDE;
virtual bool typeMismatch() const OVERRIDE;
- virtual double defaultValueForStepUp() const OVERRIDE;
+ virtual Decimal defaultValueForStepUp() const OVERRIDE;
virtual bool isSteppable() const OVERRIDE;
virtual void handleWheelEvent(WheelEvent*) OVERRIDE;
- virtual String serialize(double) const OVERRIDE;
+ virtual String serialize(const Decimal&) const OVERRIDE;
virtual String serializeWithMilliseconds(double) const;
virtual String localizeValue(const String&) const OVERRIDE;
virtual String visibleValue() const OVERRIDE;
virtual String convertFromVisibleValue(const String&) const OVERRIDE;
virtual String sanitizeValue(const String&) const OVERRIDE;
+ double parseToDouble(const String&) const;
};
} // namespace WebCore
diff --git a/Source/WebCore/html/CollectionType.h b/Source/WebCore/html/CollectionType.h
index 5bed4d89a..dd71d918b 100644
--- a/Source/WebCore/html/CollectionType.h
+++ b/Source/WebCore/html/CollectionType.h
@@ -51,7 +51,6 @@ enum CollectionType {
TSectionRows, // all row elements in this table section
TRCells, // all cells in this row
SelectOptions,
- SelectedOptions,
DataListOptions,
MapAreas,
diff --git a/Source/WebCore/html/DOMURL.cpp b/Source/WebCore/html/DOMURL.cpp
index 37c6520e6..4f9780dcd 100644
--- a/Source/WebCore/html/DOMURL.cpp
+++ b/Source/WebCore/html/DOMURL.cpp
@@ -78,7 +78,7 @@ String DOMURL::createObjectURL(ScriptExecutionContext* scriptExecutionContext, B
if (publicURL.isEmpty())
return String();
- ThreadableBlobRegistry::registerBlobURL(publicURL, blob->url());
+ ThreadableBlobRegistry::registerBlobURL(scriptExecutionContext->securityOrigin(), publicURL, blob->url());
scriptExecutionContext->publicURLManager().blobURLs().add(publicURL.string());
return publicURL.string();
diff --git a/Source/WebCore/html/DateInputType.cpp b/Source/WebCore/html/DateInputType.cpp
index 88b312065..f5d1a0293 100644
--- a/Source/WebCore/html/DateInputType.cpp
+++ b/Source/WebCore/html/DateInputType.cpp
@@ -45,9 +45,9 @@ namespace WebCore {
using namespace HTMLNames;
-static const double dateDefaultStep = 1.0;
-static const double dateDefaultStepBase = 0.0;
-static const double dateStepScaleFactor = 86400000.0;
+static const int dateDefaultStep = 1;
+static const int dateDefaultStepBase = 0;
+static const int dateStepScaleFactor = 86400000;
inline DateInputType::DateInputType(HTMLInputElement* element)
: BaseDateAndTimeInputType(element)
@@ -73,10 +73,10 @@ StepRange DateInputType::createStepRange(AnyStepHandling anyStepHandling) const
{
DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (dateDefaultStep, dateDefaultStepBase, dateStepScaleFactor, StepRange::ParsedStepValueShouldBeInteger));
- double stepBase = parseToDouble(element()->fastGetAttribute(minAttr), 0);
- double minimum = parseToDouble(element()->fastGetAttribute(minAttr), DateComponents::minimumDate());
- double maximum = parseToDouble(element()->fastGetAttribute(maxAttr), DateComponents::maximumDate());
- StepRange::DoubleWithDecimalPlacesOrMissing step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
+ const Decimal stepBase = parseToNumber(element()->fastGetAttribute(minAttr), 0);
+ const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), Decimal::fromDouble(DateComponents::minimumDate()));
+ const Decimal maximum = parseToNumber(element()->fastGetAttribute(maxAttr), Decimal::fromDouble(DateComponents::maximumDate()));
+ const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
return StepRange(stepBase, minimum, maximum, step, stepDescription);
}
diff --git a/Source/WebCore/html/DateTimeInputType.cpp b/Source/WebCore/html/DateTimeInputType.cpp
index 6cefd9d8d..78a9184f6 100644
--- a/Source/WebCore/html/DateTimeInputType.cpp
+++ b/Source/WebCore/html/DateTimeInputType.cpp
@@ -43,9 +43,9 @@ namespace WebCore {
using namespace HTMLNames;
-static const double dateTimeDefaultStep = 60.0;
-static const double dateTimeDefaultStepBase = 0.0;
-static const double dateTimeStepScaleFactor = 1000.0;
+static const int dateTimeDefaultStep = 60;
+static const int dateTimeDefaultStepBase = 0;
+static const int dateTimeStepScaleFactor = 1000;
PassOwnPtr<InputType> DateTimeInputType::create(HTMLInputElement* element)
{
@@ -62,19 +62,19 @@ DateComponents::Type DateTimeInputType::dateType() const
return DateComponents::DateTime;
}
-double DateTimeInputType::defaultValueForStepUp() const
+Decimal DateTimeInputType::defaultValueForStepUp() const
{
- return currentTimeMS();
+ return Decimal::fromDouble(currentTimeMS());
}
StepRange DateTimeInputType::createStepRange(AnyStepHandling anyStepHandling) const
{
DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (dateTimeDefaultStep, dateTimeDefaultStepBase, dateTimeStepScaleFactor, StepRange::ScaledStepValueShouldBeInteger));
- double stepBase = parseToDouble(element()->fastGetAttribute(minAttr), 0);
- double minimum = parseToDouble(element()->fastGetAttribute(minAttr), DateComponents::minimumDateTime());
- double maximum = parseToDouble(element()->fastGetAttribute(maxAttr), DateComponents::maximumDateTime());
- StepRange::DoubleWithDecimalPlacesOrMissing step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
+ const Decimal stepBase = parseToNumber(element()->fastGetAttribute(minAttr), 0);
+ const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), Decimal::fromDouble(DateComponents::minimumDateTime()));
+ const Decimal maximum = parseToNumber(element()->fastGetAttribute(maxAttr), Decimal::fromDouble(DateComponents::maximumDateTime()));
+ const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
return StepRange(stepBase, minimum, maximum, step, stepDescription);
}
diff --git a/Source/WebCore/html/DateTimeInputType.h b/Source/WebCore/html/DateTimeInputType.h
index e80886f32..d1f4a78aa 100644
--- a/Source/WebCore/html/DateTimeInputType.h
+++ b/Source/WebCore/html/DateTimeInputType.h
@@ -46,7 +46,7 @@ private:
virtual const AtomicString& formControlType() const OVERRIDE;
virtual DateComponents::Type dateType() const OVERRIDE;
virtual StepRange createStepRange(AnyStepHandling) const OVERRIDE;
- virtual double defaultValueForStepUp() const OVERRIDE;
+ virtual Decimal defaultValueForStepUp() const OVERRIDE;
virtual bool parseToDateComponentsInternal(const UChar*, unsigned length, DateComponents*) const OVERRIDE;
virtual bool setMillisecondToDateComponents(double, DateComponents*) const OVERRIDE;
virtual bool isDateTimeField() const OVERRIDE;
diff --git a/Source/WebCore/html/DateTimeLocalInputType.cpp b/Source/WebCore/html/DateTimeLocalInputType.cpp
index b657050ed..38e449fba 100644
--- a/Source/WebCore/html/DateTimeLocalInputType.cpp
+++ b/Source/WebCore/html/DateTimeLocalInputType.cpp
@@ -42,9 +42,9 @@ namespace WebCore {
using namespace HTMLNames;
-static const double dateTimeLocalDefaultStep = 60.0;
-static const double dateTimeLocalDefaultStepBase = 0.0;
-static const double dateTimeLocalStepScaleFactor = 1000.0;
+static const int dateTimeLocalDefaultStep = 60;
+static const int dateTimeLocalDefaultStepBase = 0;
+static const int dateTimeLocalStepScaleFactor = 1000;
PassOwnPtr<InputType> DateTimeLocalInputType::create(HTMLInputElement* element)
{
@@ -77,10 +77,10 @@ StepRange DateTimeLocalInputType::createStepRange(AnyStepHandling anyStepHandlin
{
DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (dateTimeLocalDefaultStep, dateTimeLocalDefaultStepBase, dateTimeLocalStepScaleFactor, StepRange::ScaledStepValueShouldBeInteger));
- double stepBase = parseToDouble(element()->fastGetAttribute(minAttr), 0);
- double minimum = parseToDouble(element()->fastGetAttribute(minAttr), DateComponents::minimumDateTime());
- double maximum = parseToDouble(element()->fastGetAttribute(maxAttr), DateComponents::maximumDateTime());
- StepRange::DoubleWithDecimalPlacesOrMissing step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
+ const Decimal stepBase = parseToNumber(element()->fastGetAttribute(minAttr), 0);
+ const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), Decimal::fromDouble(DateComponents::minimumDateTime()));
+ const Decimal maximum = parseToNumber(element()->fastGetAttribute(maxAttr), Decimal::fromDouble(DateComponents::maximumDateTime()));
+ const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
return StepRange(stepBase, minimum, maximum, step, stepDescription);
}
diff --git a/Source/WebCore/html/FileInputType.cpp b/Source/WebCore/html/FileInputType.cpp
index 72b675691..f164511d8 100644
--- a/Source/WebCore/html/FileInputType.cpp
+++ b/Source/WebCore/html/FileInputType.cpp
@@ -23,11 +23,13 @@
#include "FileInputType.h"
#include "Chrome.h"
+#include "DragData.h"
#include "ElementShadow.h"
#include "Event.h"
#include "File.h"
#include "FileList.h"
#include "FileSystem.h"
+#include "FormController.h"
#include "FormDataList.h"
#include "Frame.h"
#include "HTMLInputElement.h"
@@ -99,11 +101,13 @@ const AtomicString& FileInputType::formControlType() const
return InputTypeNames::file();
}
-bool FileInputType::saveFormControlState(String& result) const
+FormControlState FileInputType::saveFormControlState() const
{
if (m_fileList->isEmpty())
- return false;
- result = String();
+ return FormControlState();
+ // FIXME: FormControlState should be capable to have multiple strings and we
+ // should stop the following ugly string concatenation.
+ StringBuilder result;
unsigned numFiles = m_fileList->length();
for (unsigned i = 0; i < numFiles; ++i) {
result.append(m_fileList->item(i)->path());
@@ -111,14 +115,14 @@ bool FileInputType::saveFormControlState(String& result) const
result.append(m_fileList->item(i)->name());
result.append('\0');
}
- return true;
+ return FormControlState(result.toString());
}
-void FileInputType::restoreFormControlState(const String& state)
+void FileInputType::restoreFormControlState(const FormControlState& state)
{
Vector<FileChooserFileInfo> files;
Vector<String> paths;
- state.split('\0', paths);
+ state.value().split('\0', paths);
for (unsigned i = 0; i < paths.size(); ++i) {
Vector<String> pathAndName;
paths[i].split('\1', pathAndName);
@@ -187,6 +191,7 @@ void FileInputType::handleDOMActivateEvent(Event* event)
settings.allowsMultipleFiles = input->fastHasAttribute(multipleAttr);
#endif
settings.acceptMIMETypes = input->acceptMIMETypes();
+ settings.acceptFileExtensions = input->acceptFileExtensions();
settings.selectedFiles = m_fileList->paths();
#if ENABLE(MEDIA_CAPTURE)
settings.capture = input->capture();
@@ -374,6 +379,7 @@ void FileInputType::receiveDropForDirectoryUpload(const Vector<String>& paths)
settings.allowsMultipleFiles = true;
settings.selectedFiles.append(paths[0]);
settings.acceptMIMETypes = input->acceptMIMETypes();
+ settings.acceptFileExtensions = input->acceptFileExtensions();
chrome->enumerateChosenDirectory(newFileChooser(settings));
}
}
@@ -389,16 +395,25 @@ void FileInputType::updateRendering(PassRefPtr<Icon> icon)
element()->renderer()->repaint();
}
-void FileInputType::receiveDroppedFiles(const Vector<String>& paths)
+bool FileInputType::receiveDroppedFiles(const DragData* dragData)
{
+ Vector<String> paths;
+ dragData->asFilenames(paths);
+ if (paths.isEmpty())
+ return false;
+
HTMLInputElement* input = element();
#if ENABLE(DIRECTORY_UPLOAD)
if (input->fastHasAttribute(webkitdirectoryAttr)) {
receiveDropForDirectoryUpload(paths);
- return;
+ return true;
}
#endif
+#if ENABLE(FILE_SYSTEM)
+ m_droppedFileSystemId = dragData->droppedFileSystemId();
+#endif
+
Vector<FileChooserFileInfo> files;
for (unsigned i = 0; i < paths.size(); ++i)
files.append(FileChooserFileInfo(paths[i]));
@@ -410,8 +425,16 @@ void FileInputType::receiveDroppedFiles(const Vector<String>& paths)
firstFileOnly.append(files[0]);
filesChosen(firstFileOnly);
}
+ return true;
}
+#if ENABLE(FILE_SYSTEM)
+String FileInputType::droppedFileSystemId()
+{
+ return m_droppedFileSystemId;
+}
+#endif
+
Icon* FileInputType::icon() const
{
return m_icon.get();
diff --git a/Source/WebCore/html/FileInputType.h b/Source/WebCore/html/FileInputType.h
index 1f9fbce39..903639ec0 100644
--- a/Source/WebCore/html/FileInputType.h
+++ b/Source/WebCore/html/FileInputType.h
@@ -39,6 +39,7 @@
namespace WebCore {
+class DragData;
class FileList;
class FileInputType : public BaseClickableWithKeyInputType, private FileChooserClient, private FileIconLoaderClient {
@@ -48,8 +49,8 @@ public:
private:
FileInputType(HTMLInputElement*);
virtual const AtomicString& formControlType() const OVERRIDE;
- virtual bool saveFormControlState(String&) const OVERRIDE;
- virtual void restoreFormControlState(const String&) OVERRIDE;
+ virtual FormControlState saveFormControlState() const OVERRIDE;
+ virtual void restoreFormControlState(const FormControlState&) OVERRIDE;
virtual bool appendFormData(FormDataList&, bool) const OVERRIDE;
virtual bool valueMissing(const String&) const OVERRIDE;
virtual String valueMissingText() const OVERRIDE;
@@ -62,7 +63,10 @@ private:
virtual bool canSetValue(const String&) OVERRIDE;
virtual bool getTypeSpecificValue(String&) OVERRIDE; // Checked first, before internal storage or the value attribute.
virtual void setValue(const String&, bool valueChanged, TextFieldEventBehavior) OVERRIDE;
- virtual void receiveDroppedFiles(const Vector<String>&) OVERRIDE;
+ virtual bool receiveDroppedFiles(const DragData*) OVERRIDE;
+#if ENABLE(FILE_SYSTEM)
+ virtual String droppedFileSystemId() OVERRIDE;
+#endif
virtual Icon* icon() const OVERRIDE;
virtual bool isFileUpload() const OVERRIDE;
virtual void createShadowSubtree() OVERRIDE;
@@ -83,6 +87,10 @@ private:
RefPtr<FileList> m_fileList;
RefPtr<Icon> m_icon;
+
+#if ENABLE(FILE_SYSTEM)
+ String m_droppedFileSystemId;
+#endif
};
} // namespace WebCore
diff --git a/Source/WebCore/html/FormAssociatedElement.cpp b/Source/WebCore/html/FormAssociatedElement.cpp
index 390c149ba..21791f096 100644
--- a/Source/WebCore/html/FormAssociatedElement.cpp
+++ b/Source/WebCore/html/FormAssociatedElement.cpp
@@ -25,6 +25,7 @@
#include "config.h"
#include "FormAssociatedElement.h"
+#include "FormController.h"
#include "HTMLFormControlElement.h"
#include "HTMLFormElement.h"
#include "HTMLNames.h"
@@ -57,7 +58,7 @@ void FormAssociatedElement::didMoveToNewDocument(Document* oldDocument)
{
HTMLElement* element = toHTMLElement(this);
if (oldDocument && element->fastHasAttribute(formAttr))
- oldDocument->unregisterFormElementWithFormAttribute(this);
+ oldDocument->formController()->unregisterFormElementWithFormAttribute(this);
}
void FormAssociatedElement::insertedInto(ContainerNode* insertionPoint)
@@ -68,14 +69,14 @@ void FormAssociatedElement::insertedInto(ContainerNode* insertionPoint)
HTMLElement* element = toHTMLElement(this);
if (element->fastHasAttribute(formAttr))
- element->document()->registerFormElementWithFormAttribute(this);
+ element->document()->formController()->registerFormElementWithFormAttribute(this);
}
void FormAssociatedElement::removedFrom(ContainerNode* insertionPoint)
{
HTMLElement* element = toHTMLElement(this);
if (insertionPoint->inDocument() && element->fastHasAttribute(formAttr))
- element->document()->unregisterFormElementWithFormAttribute(this);
+ element->document()->formController()->unregisterFormElementWithFormAttribute(this);
// If the form and element are both in the same tree, preserve the connection to the form.
// Otherwise, null out our form and remove ourselves from the form's list of elements.
if (m_form && element->highestAncestor() != m_form->highestAncestor())
@@ -152,7 +153,7 @@ void FormAssociatedElement::formAttributeChanged()
if (!element->fastHasAttribute(formAttr)) {
// The form attribute removed. We need to reset form owner here.
setForm(element->findFormAncestor());
- element->document()->unregisterFormElementWithFormAttribute(this);
+ element->document()->formController()->unregisterFormElementWithFormAttribute(this);
} else
resetFormOwner();
}
@@ -220,6 +221,12 @@ void FormAssociatedElement::setCustomValidity(const String& error)
m_customValidationMessage = error;
}
+const AtomicString& FormAssociatedElement::name() const
+{
+ const AtomicString& name = toHTMLElement(this)->getNameAttribute();
+ return name.isNull() ? emptyAtom : name;
+}
+
const HTMLElement* toHTMLElement(const FormAssociatedElement* associatedElement)
{
if (associatedElement->isFormControlElement())
diff --git a/Source/WebCore/html/FormAssociatedElement.h b/Source/WebCore/html/FormAssociatedElement.h
index 4c9cda00c..5a47ea076 100644
--- a/Source/WebCore/html/FormAssociatedElement.h
+++ b/Source/WebCore/html/FormAssociatedElement.h
@@ -48,7 +48,10 @@ public:
virtual bool isFormControlElement() const = 0;
virtual bool isEnumeratable() const = 0;
- const AtomicString& name() const { return formControlName(); }
+ // Returns the 'name' attribute value. If this element has no name
+ // attribute, it returns an empty string instead of null string.
+ // Note that the 'name' IDL attribute doesn't use this function.
+ virtual const AtomicString& name() const;
// Override in derived classes to get the encoded name=value pair for submitting.
// Return true for a successful control (see HTML4-17.13.2).
@@ -95,8 +98,6 @@ protected:
String customValidationMessage() const;
private:
- virtual const AtomicString& formControlName() const = 0;
-
virtual void refFormAssociatedElement() = 0;
virtual void derefFormAssociatedElement() = 0;
diff --git a/Source/WebCore/html/FormController.cpp b/Source/WebCore/html/FormController.cpp
new file mode 100644
index 000000000..80d01f2ca
--- /dev/null
+++ b/Source/WebCore/html/FormController.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2006, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2011, 2012 Google Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "FormController.h"
+
+#include "HTMLFormControlElementWithState.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+FormController::FormController()
+{
+}
+
+FormController::~FormController()
+{
+}
+
+Vector<String> FormController::formElementsState() const
+{
+ Vector<String> stateVector;
+ stateVector.reserveInitialCapacity(m_formElementsWithState.size() * 3);
+ typedef FormElementListHashSet::const_iterator Iterator;
+ Iterator end = m_formElementsWithState.end();
+ for (Iterator it = m_formElementsWithState.begin(); it != end; ++it) {
+ HTMLFormControlElementWithState* elementWithState = *it;
+ if (!elementWithState->shouldSaveAndRestoreFormControlState())
+ continue;
+ FormControlState state = elementWithState->saveFormControlState();
+ if (!state.hasValue())
+ continue;
+ stateVector.append(elementWithState->name().string());
+ stateVector.append(elementWithState->formControlType().string());
+ stateVector.append(state.value());
+ }
+ return stateVector;
+}
+
+static bool isNotFormControlTypeCharacter(UChar ch)
+{
+ return ch != '-' && (ch > 'z' || ch < 'a');
+}
+
+void FormController::setStateForNewFormElements(const Vector<String>& stateVector)
+{
+ // Walk the state vector backwards so that the value to use for each
+ // name/type pair first is the one at the end of each individual vector
+ // in the FormElementStateMap. We're using them like stacks.
+ typedef FormElementStateMap::iterator Iterator;
+ m_formElementsWithState.clear();
+
+ if (stateVector.size() % 3)
+ return;
+ for (size_t i = 0; i < stateVector.size(); i += 3) {
+ if (stateVector[i + 1].find(isNotFormControlTypeCharacter) != notFound)
+ return;
+ }
+
+ for (size_t i = stateVector.size() / 3 * 3; i; i -= 3) {
+ AtomicString name = stateVector[i - 3];
+ AtomicString type = stateVector[i - 2];
+ const String& value = stateVector[i - 1];
+ FormElementKey key(name.impl(), type.impl());
+ Iterator it = m_stateForNewFormElements.find(key);
+ if (it != m_stateForNewFormElements.end())
+ it->second.append(value);
+ else {
+ Vector<String> valueList(1);
+ valueList[0] = value;
+ m_stateForNewFormElements.set(key, valueList);
+ }
+ }
+}
+
+bool FormController::hasStateForNewFormElements() const
+{
+ return !m_stateForNewFormElements.isEmpty();
+}
+
+FormControlState FormController::takeStateForFormElement(AtomicStringImpl* name, AtomicStringImpl* type)
+{
+ typedef FormElementStateMap::iterator Iterator;
+ Iterator it = m_stateForNewFormElements.find(FormElementKey(name, type));
+ if (it == m_stateForNewFormElements.end())
+ return FormControlState();
+ ASSERT(it->second.size());
+ FormControlState state(it->second.last());
+ if (it->second.size() > 1)
+ it->second.removeLast();
+ else
+ m_stateForNewFormElements.remove(it);
+ return state;
+}
+
+void FormController::registerFormElementWithFormAttribute(FormAssociatedElement* element)
+{
+ ASSERT(toHTMLElement(element)->fastHasAttribute(formAttr));
+ m_formElementsWithFormAttribute.add(element);
+}
+
+void FormController::unregisterFormElementWithFormAttribute(FormAssociatedElement* element)
+{
+ m_formElementsWithFormAttribute.remove(element);
+}
+
+void FormController::resetFormElementsOwner()
+{
+ typedef FormAssociatedElementListHashSet::iterator Iterator;
+ Iterator end = m_formElementsWithFormAttribute.end();
+ for (Iterator it = m_formElementsWithFormAttribute.begin(); it != end; ++it)
+ (*it)->resetFormOwner();
+}
+
+FormElementKey::FormElementKey(AtomicStringImpl* name, AtomicStringImpl* type)
+ : m_name(name), m_type(type)
+{
+ ref();
+}
+
+FormElementKey::~FormElementKey()
+{
+ deref();
+}
+
+FormElementKey::FormElementKey(const FormElementKey& other)
+ : m_name(other.name()), m_type(other.type())
+{
+ ref();
+}
+
+FormElementKey& FormElementKey::operator=(const FormElementKey& other)
+{
+ other.ref();
+ deref();
+ m_name = other.name();
+ m_type = other.type();
+ return *this;
+}
+
+void FormElementKey::ref() const
+{
+ if (name())
+ name()->ref();
+ if (type())
+ type()->ref();
+}
+
+void FormElementKey::deref() const
+{
+ if (name())
+ name()->deref();
+ if (type())
+ type()->deref();
+}
+
+unsigned FormElementKeyHash::hash(const FormElementKey& key)
+{
+ return StringHasher::hashMemory<sizeof(FormElementKey)>(&key);
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/html/FormController.h b/Source/WebCore/html/FormController.h
new file mode 100644
index 000000000..0f2207adf
--- /dev/null
+++ b/Source/WebCore/html/FormController.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2011, 2012 Google Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef FormController_h
+#define FormController_h
+
+#include "CheckedRadioButtons.h"
+#include <wtf/Forward.h>
+#include <wtf/ListHashSet.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class FormAssociatedElement;
+class HTMLFormControlElementWithState;
+
+class FormElementKey {
+public:
+ FormElementKey(AtomicStringImpl* = 0, AtomicStringImpl* = 0);
+ ~FormElementKey();
+ FormElementKey(const FormElementKey&);
+ FormElementKey& operator=(const FormElementKey&);
+
+ AtomicStringImpl* name() const { return m_name; }
+ AtomicStringImpl* type() const { return m_type; }
+
+ // Hash table deleted values, which are only constructed and never copied or destroyed.
+ FormElementKey(WTF::HashTableDeletedValueType) : m_name(hashTableDeletedValue()) { }
+ bool isHashTableDeletedValue() const { return m_name == hashTableDeletedValue(); }
+
+private:
+ void ref() const;
+ void deref() const;
+
+ static AtomicStringImpl* hashTableDeletedValue() { return reinterpret_cast<AtomicStringImpl*>(-1); }
+
+ AtomicStringImpl* m_name;
+ AtomicStringImpl* m_type;
+};
+
+inline bool operator==(const FormElementKey& a, const FormElementKey& b)
+{
+ return a.name() == b.name() && a.type() == b.type();
+}
+
+struct FormElementKeyHash {
+ static unsigned hash(const FormElementKey&);
+ static bool equal(const FormElementKey& a, const FormElementKey& b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+struct FormElementKeyHashTraits : WTF::GenericHashTraits<FormElementKey> {
+ static void constructDeletedValue(FormElementKey& slot) { new (NotNull, &slot) FormElementKey(WTF::HashTableDeletedValue); }
+ static bool isDeletedValue(const FormElementKey& value) { return value.isHashTableDeletedValue(); }
+};
+
+class FormControlState {
+public:
+ FormControlState() : m_type(TypeSkip) { }
+ explicit FormControlState(const String& value) : m_type(TypeRestore), m_value(value) { }
+ FormControlState(const FormControlState& another) : m_type(another.m_type), m_value(another.m_value) { }
+ FormControlState& operator=(const FormControlState&);
+
+ bool hasValue() const { return m_type == TypeRestore; }
+ String value() const { return m_value; }
+
+private:
+ enum Type { TypeSkip, TypeRestore };
+ Type m_type;
+ String m_value;
+};
+
+inline FormControlState& FormControlState::operator=(const FormControlState& another)
+{
+ m_type = another.m_type;
+ m_value = another.m_value;
+ return *this;
+}
+
+class FormController {
+public:
+ static PassOwnPtr<FormController> create()
+ {
+ return adoptPtr(new FormController);
+ }
+ ~FormController();
+
+ CheckedRadioButtons& checkedRadioButtons() { return m_checkedRadioButtons; }
+
+ void registerFormElementWithState(HTMLFormControlElementWithState* control) { m_formElementsWithState.add(control); }
+ void unregisterFormElementWithState(HTMLFormControlElementWithState* control) { m_formElementsWithState.remove(control); }
+ // This should be callled only by Document::formElementsState().
+ Vector<String> formElementsState() const;
+ // This should be callled only by Document::setStateForNewFormElements().
+ void setStateForNewFormElements(const Vector<String>&);
+ bool hasStateForNewFormElements() const;
+ FormControlState takeStateForFormElement(AtomicStringImpl* name, AtomicStringImpl* type);
+
+ void registerFormElementWithFormAttribute(FormAssociatedElement*);
+ void unregisterFormElementWithFormAttribute(FormAssociatedElement*);
+ void resetFormElementsOwner();
+
+private:
+ FormController();
+
+ CheckedRadioButtons m_checkedRadioButtons;
+
+ typedef ListHashSet<HTMLFormControlElementWithState*, 64> FormElementListHashSet;
+ FormElementListHashSet m_formElementsWithState;
+ typedef ListHashSet<RefPtr<FormAssociatedElement>, 32> FormAssociatedElementListHashSet;
+ FormAssociatedElementListHashSet m_formElementsWithFormAttribute;
+
+ typedef HashMap<FormElementKey, Vector<String>, FormElementKeyHash, FormElementKeyHashTraits> FormElementStateMap;
+ FormElementStateMap m_stateForNewFormElements;
+
+};
+
+} // namespace WebCore
+#endif
diff --git a/Source/WebCore/html/HTMLButtonElement.cpp b/Source/WebCore/html/HTMLButtonElement.cpp
index f14419d3b..d82a1a737 100644
--- a/Source/WebCore/html/HTMLButtonElement.cpp
+++ b/Source/WebCore/html/HTMLButtonElement.cpp
@@ -53,6 +53,11 @@ PassRefPtr<HTMLButtonElement> HTMLButtonElement::create(const QualifiedName& tag
return adoptRef(new HTMLButtonElement(tagName, document, form));
}
+void HTMLButtonElement::setType(const AtomicString& type)
+{
+ setAttribute(typeAttr, type);
+}
+
RenderObject* HTMLButtonElement::createRenderer(RenderArena* arena, RenderStyle*)
{
return new (arena) RenderButton(this);
diff --git a/Source/WebCore/html/HTMLButtonElement.h b/Source/WebCore/html/HTMLButtonElement.h
index c8dd27edf..7bf99b7b8 100644
--- a/Source/WebCore/html/HTMLButtonElement.h
+++ b/Source/WebCore/html/HTMLButtonElement.h
@@ -32,6 +32,8 @@ class HTMLButtonElement : public HTMLFormControlElement {
public:
static PassRefPtr<HTMLButtonElement> create(const QualifiedName&, Document*, HTMLFormElement*);
+ void setType(const AtomicString&);
+
String value() const;
private:
diff --git a/Source/WebCore/html/HTMLButtonElement.idl b/Source/WebCore/html/HTMLButtonElement.idl
index 692fd612a..02e91abef 100644
--- a/Source/WebCore/html/HTMLButtonElement.idl
+++ b/Source/WebCore/html/HTMLButtonElement.idl
@@ -30,7 +30,7 @@ module html {
attribute [Reflect] boolean formNoValidate;
attribute [Reflect] DOMString formTarget;
attribute [Reflect] DOMString name;
- readonly attribute DOMString type;
+ attribute [TreatNullAs=NullString] DOMString type;
attribute [Reflect] DOMString value;
readonly attribute boolean willValidate;
diff --git a/Source/WebCore/html/HTMLCollection.cpp b/Source/WebCore/html/HTMLCollection.cpp
index a908da0a3..c20c464e8 100644
--- a/Source/WebCore/html/HTMLCollection.cpp
+++ b/Source/WebCore/html/HTMLCollection.cpp
@@ -61,7 +61,6 @@ bool HTMLCollection::shouldIncludeChildren(CollectionType type)
case MapAreas:
case OtherCollection:
case SelectOptions:
- case SelectedOptions:
case DataListOptions:
case WindowNamedItems:
#if ENABLE(MICRODATA)
@@ -119,13 +118,6 @@ inline bool HTMLCollection::isAcceptableElement(Element* element) const
return element->hasLocalName(trTag);
case SelectOptions:
return element->hasLocalName(optionTag);
- case SelectedOptions:
- if (element->hasLocalName(optionTag)) {
- HTMLOptionElement* option = static_cast<HTMLOptionElement*>(element);
- if (option->selected())
- return true;
- }
- return false;
case DataListOptions:
if (element->hasLocalName(optionTag)) {
HTMLOptionElement* option = static_cast<HTMLOptionElement*>(element);
diff --git a/Source/WebCore/html/HTMLElement.cpp b/Source/WebCore/html/HTMLElement.cpp
index 3d4ee8d29..50152cad1 100644
--- a/Source/WebCore/html/HTMLElement.cpp
+++ b/Source/WebCore/html/HTMLElement.cpp
@@ -578,7 +578,7 @@ void HTMLElement::insertAdjacentHTML(const String& where, const String& markup,
Element* contextElement = contextElementForInsertion(where, this, ec);
if (!contextElement)
return;
- RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(markup, this, AllowScriptingContent, ec);
+ RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(markup, contextElement, AllowScriptingContent, ec);
if (!fragment)
return;
insertAdjacent(where, fragment.get(), ec);
diff --git a/Source/WebCore/html/HTMLFormCollection.cpp b/Source/WebCore/html/HTMLFormCollection.cpp
index cb3cca954..d9b6a5dff 100644
--- a/Source/WebCore/html/HTMLFormCollection.cpp
+++ b/Source/WebCore/html/HTMLFormCollection.cpp
@@ -38,7 +38,6 @@ using namespace HTMLNames;
HTMLFormCollection::HTMLFormCollection(HTMLElement* base)
: HTMLCollection(base, FormControls)
- , currentPos(0)
{
}
diff --git a/Source/WebCore/html/HTMLFormCollection.h b/Source/WebCore/html/HTMLFormCollection.h
index 32fb1eb0b..315ea68b6 100644
--- a/Source/WebCore/html/HTMLFormCollection.h
+++ b/Source/WebCore/html/HTMLFormCollection.h
@@ -57,8 +57,6 @@ private:
const Vector<FormAssociatedElement*>& formControlElements() const;
const Vector<HTMLImageElement*>& formImageElements() const;
unsigned numberOfFormControlElements() const;
-
- mutable int currentPos;
};
} //namespace
diff --git a/Source/WebCore/html/HTMLFormControlElement.cpp b/Source/WebCore/html/HTMLFormControlElement.cpp
index 0a51392e1..d09814865 100644
--- a/Source/WebCore/html/HTMLFormControlElement.cpp
+++ b/Source/WebCore/html/HTMLFormControlElement.cpp
@@ -241,17 +241,6 @@ void HTMLFormControlElement::removedFrom(ContainerNode* insertionPoint)
FormAssociatedElement::removedFrom(insertionPoint);
}
-const AtomicString& HTMLFormControlElement::formControlName() const
-{
- const AtomicString& name = getNameAttribute();
- return name.isNull() ? emptyAtom : name;
-}
-
-void HTMLFormControlElement::setName(const AtomicString& value)
-{
- setAttribute(nameAttr, value);
-}
-
bool HTMLFormControlElement::wasChangedSinceLastFormControlChangeEvent() const
{
return m_wasChangedSinceLastFormControlChangeEvent;
diff --git a/Source/WebCore/html/HTMLFormControlElement.h b/Source/WebCore/html/HTMLFormControlElement.h
index 5fac956b4..b3a9354ca 100644
--- a/Source/WebCore/html/HTMLFormControlElement.h
+++ b/Source/WebCore/html/HTMLFormControlElement.h
@@ -77,9 +77,6 @@ public:
const AtomicString& type() const { return formControlType(); }
- void setName(const AtomicString& name);
-
- virtual const AtomicString& formControlName() const OVERRIDE;
virtual const AtomicString& formControlType() const OVERRIDE = 0;
virtual bool isEnabledFormControl() const { return !disabled(); }
virtual bool isReadOnlyFormControl() const { return readOnly(); }
@@ -109,8 +106,8 @@ public:
static HTMLFormControlElement* enclosingFormControlElement(Node*);
- using TreeShared<ContainerNode>::ref;
- using TreeShared<ContainerNode>::deref;
+ using Node::ref;
+ using Node::deref;
protected:
HTMLFormControlElement(const QualifiedName& tagName, Document*, HTMLFormElement*);
diff --git a/Source/WebCore/html/HTMLFormControlElementWithState.cpp b/Source/WebCore/html/HTMLFormControlElementWithState.cpp
index bf94c54d9..4152224ee 100644
--- a/Source/WebCore/html/HTMLFormControlElementWithState.cpp
+++ b/Source/WebCore/html/HTMLFormControlElementWithState.cpp
@@ -25,6 +25,7 @@
#include "config.h"
#include "HTMLFormControlElementWithState.h"
+#include "FormController.h"
#include "HTMLFormElement.h"
namespace WebCore {
@@ -32,19 +33,19 @@ namespace WebCore {
HTMLFormControlElementWithState::HTMLFormControlElementWithState(const QualifiedName& tagName, Document* doc, HTMLFormElement* f)
: HTMLFormControlElement(tagName, doc, f)
{
- document()->registerFormElementWithState(this);
+ document()->formController()->registerFormElementWithState(this);
}
HTMLFormControlElementWithState::~HTMLFormControlElementWithState()
{
- document()->unregisterFormElementWithState(this);
+ document()->formController()->unregisterFormElementWithState(this);
}
void HTMLFormControlElementWithState::didMoveToNewDocument(Document* oldDocument)
{
if (oldDocument)
- oldDocument->unregisterFormElementWithState(this);
- document()->registerFormElementWithState(this);
+ oldDocument->formController()->unregisterFormElementWithState(this);
+ document()->formController()->registerFormElementWithState(this);
HTMLFormControlElement::didMoveToNewDocument(oldDocument);
}
@@ -61,6 +62,11 @@ bool HTMLFormControlElementWithState::shouldSaveAndRestoreFormControlState() con
return attached() && shouldAutocomplete();
}
+FormControlState HTMLFormControlElementWithState::saveFormControlState() const
+{
+ return FormControlState();
+}
+
void HTMLFormControlElementWithState::finishParsingChildren()
{
HTMLFormControlElement::finishParsingChildren();
@@ -72,9 +78,9 @@ void HTMLFormControlElementWithState::finishParsingChildren()
return;
Document* doc = document();
- if (doc->hasStateForNewFormElements()) {
- String state;
- if (doc->takeStateForFormElement(name().impl(), type().impl(), state))
+ if (doc->formController()->hasStateForNewFormElements()) {
+ FormControlState state = doc->formController()->takeStateForFormElement(name().impl(), type().impl());
+ if (state.hasValue())
restoreFormControlState(state);
}
}
diff --git a/Source/WebCore/html/HTMLFormControlElementWithState.h b/Source/WebCore/html/HTMLFormControlElementWithState.h
index 73de3260b..0af98f8d8 100644
--- a/Source/WebCore/html/HTMLFormControlElementWithState.h
+++ b/Source/WebCore/html/HTMLFormControlElementWithState.h
@@ -28,6 +28,8 @@
namespace WebCore {
+class FormControlState;
+
class HTMLFormControlElementWithState : public HTMLFormControlElement {
public:
virtual ~HTMLFormControlElementWithState();
@@ -35,8 +37,9 @@ public:
virtual bool canContainRangeEndPoint() const { return false; }
bool shouldSaveAndRestoreFormControlState() const;
- virtual bool saveFormControlState(String&) const { return false; }
- virtual void restoreFormControlState(const String&) { }
+ virtual FormControlState saveFormControlState() const;
+ // The specified FormControlState must have one string value.
+ virtual void restoreFormControlState(const FormControlState&) { }
protected:
HTMLFormControlElementWithState(const QualifiedName& tagName, Document*, HTMLFormElement*);
diff --git a/Source/WebCore/html/HTMLFormElement.cpp b/Source/WebCore/html/HTMLFormElement.cpp
index ea54b93ba..719b46eac 100644
--- a/Source/WebCore/html/HTMLFormElement.cpp
+++ b/Source/WebCore/html/HTMLFormElement.cpp
@@ -34,6 +34,7 @@
#include "EventNames.h"
#include "FileList.h"
#include "FileSystem.h"
+#include "FormController.h"
#include "FormData.h"
#include "FormDataList.h"
#include "FormState.h"
@@ -144,7 +145,7 @@ void HTMLFormElement::didNotifyDescendantInsertions(ContainerNode* insertionPoin
ASSERT(insertionPoint->inDocument());
HTMLElement::didNotifyDescendantInsertions(insertionPoint);
if (hasID())
- document()->resetFormElementsOwner();
+ document()->formController()->resetFormElementsOwner();
}
static inline Node* findRoot(Node* n)
@@ -163,7 +164,7 @@ void HTMLFormElement::removedFrom(ContainerNode* insertionPoint)
associatedElements[i]->formRemovedFromTree(root);
HTMLElement::removedFrom(insertionPoint);
if (insertionPoint->inDocument() && hasID())
- document()->resetFormElementsOwner();
+ document()->formController()->resetFormElementsOwner();
}
void HTMLFormElement::handleLocalEvents(Event* event)
diff --git a/Source/WebCore/html/HTMLInputElement.cpp b/Source/WebCore/html/HTMLInputElement.cpp
index 9248f0bc2..4a8107ee5 100644
--- a/Source/WebCore/html/HTMLInputElement.cpp
+++ b/Source/WebCore/html/HTMLInputElement.cpp
@@ -37,6 +37,7 @@
#include "EventNames.h"
#include "ExceptionCode.h"
#include "FileList.h"
+#include "FormController.h"
#include "Frame.h"
#include "HTMLCollection.h"
#include "HTMLDataListElement.h"
@@ -127,10 +128,10 @@ HTMLInputElement::~HTMLInputElement()
// setForm(0) may register this to a document-level radio button group.
// We should unregister it to avoid accessing a deleted object.
if (isRadioButton())
- document()->checkedRadioButtons().removeButton(this);
+ document()->formController()->checkedRadioButtons().removeButton(this);
}
-const AtomicString& HTMLInputElement::formControlName() const
+const AtomicString& HTMLInputElement::name() const
{
return m_name.isNull() ? emptyAtom : m_name;
}
@@ -273,7 +274,7 @@ bool HTMLInputElement::stepMismatch() const
return willValidate() && m_inputType->stepMismatch(value());
}
-bool HTMLInputElement::getAllowedValueStep(double* step) const
+bool HTMLInputElement::getAllowedValueStep(Decimal* step) const
{
return m_inputType->getAllowedValueStep(step);
}
@@ -295,15 +296,26 @@ void HTMLInputElement::stepDown(int n, ExceptionCode& ec)
bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const
{
- if (isTextField())
- return HTMLTextFormControlElement::isFocusable();
- return HTMLTextFormControlElement::isKeyboardFocusable(event) && m_inputType->isKeyboardFocusable();
+ return m_inputType->isKeyboardFocusable(event);
}
bool HTMLInputElement::isMouseFocusable() const
{
- if (isTextField())
- return HTMLTextFormControlElement::isFocusable();
+ return m_inputType->isMouseFocusable();
+}
+
+bool HTMLInputElement::isTextFormControlFocusable() const
+{
+ return HTMLTextFormControlElement::isFocusable();
+}
+
+bool HTMLInputElement::isTextFormControlKeyboardFocusable(KeyboardEvent* event) const
+{
+ return HTMLTextFormControlElement::isKeyboardFocusable(event);
+}
+
+bool HTMLInputElement::isTextFormControlMouseFocusable() const
+{
return HTMLTextFormControlElement::isMouseFocusable();
}
@@ -456,7 +468,6 @@ void HTMLInputElement::subtreeHasChanged()
{
ASSERT(isTextField());
ASSERT(renderer());
- RenderTextControlSingleLine* renderTextControl = toRenderTextControlSingleLine(renderer());
bool wasChanged = wasChangedSinceLastFormControlChangeEvent();
setChangedSinceLastFormControlChangeEvent(true);
@@ -472,12 +483,7 @@ void HTMLInputElement::subtreeHasChanged()
// Recalc for :invalid and hasUnacceptableValue() change.
setNeedsStyleRecalc();
- if (cancelButtonElement())
- renderTextControl->updateCancelButtonVisibility();
-
- // If the incremental attribute is set, then dispatch the search event
- if (searchEventsShouldBeDispatched() && isSearchField() && m_inputType)
- static_cast<SearchInputType*>(m_inputType.get())->startSearchEventTimer();
+ m_inputType->subtreeHasChanged();
if (!wasChanged && focused()) {
if (Frame* frame = document()->frame())
@@ -498,12 +504,12 @@ const AtomicString& HTMLInputElement::formControlType() const
return m_inputType->formControlType();
}
-bool HTMLInputElement::saveFormControlState(String& result) const
+FormControlState HTMLInputElement::saveFormControlState() const
{
- return m_inputType->saveFormControlState(result);
+ return m_inputType->saveFormControlState();
}
-void HTMLInputElement::restoreFormControlState(const String& state)
+void HTMLInputElement::restoreFormControlState(const FormControlState& state)
{
m_inputType->restoreFormControlState(state);
m_stateRestored = true;
@@ -553,7 +559,7 @@ void HTMLInputElement::collectStyleForAttribute(const Attribute& attribute, Styl
} else if (attribute.name() == borderAttr && isImageButton())
applyBorderAttributeToStyle(attribute, style);
else
- return HTMLTextFormControlElement::collectStyleForAttribute(attribute, style);
+ HTMLTextFormControlElement::collectStyleForAttribute(attribute, style);
}
void HTMLInputElement::parseAttribute(const Attribute& attribute)
@@ -949,7 +955,7 @@ void HTMLInputElement::setValueAsDate(double value, ExceptionCode& ec)
double HTMLInputElement::valueAsNumber() const
{
- return m_inputType->valueAsNumber();
+ return m_inputType->valueAsDouble();
}
void HTMLInputElement::setValueAsNumber(double newValue, ExceptionCode& ec, TextFieldEventBehavior eventBehavior)
@@ -958,7 +964,7 @@ void HTMLInputElement::setValueAsNumber(double newValue, ExceptionCode& ec, Text
ec = NOT_SUPPORTED_ERR;
return;
}
- m_inputType->setValueAsNumber(newValue, eventBehavior, ec);
+ m_inputType->setValueAsDouble(newValue, eventBehavior, ec);
}
String HTMLInputElement::placeholder() const
@@ -971,11 +977,6 @@ void HTMLInputElement::setPlaceholder(const String& value)
setAttribute(placeholderAttr, value);
}
-bool HTMLInputElement::searchEventsShouldBeDispatched() const
-{
- return hasAttribute(incrementalAttr);
-}
-
void HTMLInputElement::setValueFromRenderer(const String& value)
{
// File upload controls will never use this.
@@ -1134,7 +1135,7 @@ static inline bool isRFC2616TokenCharacter(UChar ch)
return isASCII(ch) && ch > ' ' && ch != '"' && ch != '(' && ch != ')' && ch != ',' && ch != '/' && (ch < ':' || ch > '@') && (ch < '[' || ch > ']') && ch != '{' && ch != '}' && ch != 0x7f;
}
-static inline bool isValidMIMEType(const String& type)
+static bool isValidMIMEType(const String& type)
{
size_t slashPosition = type.find('/');
if (slashPosition == notFound || !slashPosition || slashPosition == type.length() - 1)
@@ -1146,26 +1147,41 @@ static inline bool isValidMIMEType(const String& type)
return true;
}
-Vector<String> HTMLInputElement::acceptMIMETypes()
+static bool isValidFileExtension(const String& type)
{
- Vector<String> mimeTypes;
+ if (type.length() < 2)
+ return false;
+ return type[0] == '.';
+}
- String acceptString = accept();
+static Vector<String> parseAcceptAttribute(const String& acceptString, bool (*predicate)(const String&))
+{
+ Vector<String> types;
if (acceptString.isEmpty())
- return mimeTypes;
+ return types;
Vector<String> splitTypes;
acceptString.split(',', false, splitTypes);
for (size_t i = 0; i < splitTypes.size(); ++i) {
- String trimmedMimeType = stripLeadingAndTrailingHTMLSpaces(splitTypes[i]);
- if (trimmedMimeType.isEmpty())
+ String trimmedType = stripLeadingAndTrailingHTMLSpaces(splitTypes[i]);
+ if (trimmedType.isEmpty())
continue;
- if (!isValidMIMEType(trimmedMimeType))
+ if (!predicate(trimmedType))
continue;
- mimeTypes.append(trimmedMimeType.lower());
+ types.append(trimmedType.lower());
}
- return mimeTypes;
+ return types;
+}
+
+Vector<String> HTMLInputElement::acceptMIMETypes()
+{
+ return parseAcceptAttribute(fastGetAttribute(acceptAttr), isValidMIMEType);
+}
+
+Vector<String> HTMLInputElement::acceptFileExtensions()
+{
+ return parseAcceptAttribute(fastGetAttribute(acceptAttr), isValidFileExtension);
}
String HTMLInputElement::accept() const
@@ -1225,11 +1241,18 @@ void HTMLInputElement::setFiles(PassRefPtr<FileList> files)
m_inputType->setFiles(files);
}
-void HTMLInputElement::receiveDroppedFiles(const Vector<String>& filenames)
+bool HTMLInputElement::receiveDroppedFiles(const DragData* dragData)
{
- m_inputType->receiveDroppedFiles(filenames);
+ return m_inputType->receiveDroppedFiles(dragData);
}
+#if ENABLE(FILE_SYSTEM)
+String HTMLInputElement::droppedFileSystemId()
+{
+ return m_inputType->droppedFileSystemId();
+}
+#endif
+
Icon* HTMLInputElement::icon() const
{
return m_inputType->icon();
@@ -1317,9 +1340,7 @@ bool HTMLInputElement::isRequiredFormControl() const
void HTMLInputElement::addSearchResult()
{
- ASSERT(isSearchField());
- if (renderer())
- toRenderTextControlSingleLine(renderer())->addSearchResult();
+ m_inputType->addSearchResult();
}
void HTMLInputElement::onSearch()
@@ -1351,16 +1372,14 @@ void HTMLInputElement::didChangeForm()
Node::InsertionNotificationRequest HTMLInputElement::insertedInto(ContainerNode* insertionPoint)
{
HTMLTextFormControlElement::insertedInto(insertionPoint);
- if (!insertionPoint->inDocument())
- return InsertionDone;
- ASSERT(inDocument());
- addToRadioButtonGroup();
+ if (insertionPoint->inDocument() && !form())
+ addToRadioButtonGroup();
return InsertionDone;
}
void HTMLInputElement::removedFrom(ContainerNode* insertionPoint)
{
- if (insertionPoint->inDocument())
+ if (insertionPoint->inDocument() && !form())
removeFromRadioButtonGroup();
HTMLTextFormControlElement::removedFrom(insertionPoint);
}
@@ -1374,7 +1393,7 @@ void HTMLInputElement::didMoveToNewDocument(Document* oldDocument)
if (needsSuspensionCallback)
oldDocument->unregisterForPageCacheSuspensionCallbacks(this);
if (isRadioButton())
- oldDocument->checkedRadioButtons().removeButton(this);
+ oldDocument->formController()->checkedRadioButtons().removeButton(this);
}
if (needsSuspensionCallback)
@@ -1672,7 +1691,7 @@ CheckedRadioButtons* HTMLInputElement::checkedRadioButtons() const
if (HTMLFormElement* formElement = form())
return &formElement->checkedRadioButtons();
if (inDocument())
- return &document()->checkedRadioButtons();
+ return &document()->formController()->checkedRadioButtons();
return 0;
}
diff --git a/Source/WebCore/html/HTMLInputElement.h b/Source/WebCore/html/HTMLInputElement.h
index 9756e4fc4..3af2b3525 100644
--- a/Source/WebCore/html/HTMLInputElement.h
+++ b/Source/WebCore/html/HTMLInputElement.h
@@ -30,6 +30,8 @@
namespace WebCore {
+class CheckedRadioButtons;
+class DragData;
class FileList;
class HTMLDataListElement;
class HTMLOptionElement;
@@ -65,7 +67,7 @@ public:
double maximum() const;
// Sets the "allowed value step" defined in the HTML spec to the specified double pointer.
// Returns false if there is no "allowed value step."
- bool getAllowedValueStep(double*) const;
+ bool getAllowedValueStep(Decimal*) const;
StepRange createStepRange(AnyStepHandling) const;
// Implementations of HTMLInputElement::stepUp() and stepDown().
@@ -195,6 +197,7 @@ public:
void setDefaultValue(const String&);
Vector<String> acceptMIMETypes();
+ Vector<String> acceptFileExtensions();
String accept() const;
String alt() const;
@@ -212,7 +215,14 @@ public:
FileList* files();
void setFiles(PassRefPtr<FileList>);
- void receiveDroppedFiles(const Vector<String>&);
+
+ // Returns true if the given DragData has more than one dropped files.
+ bool receiveDroppedFiles(const DragData*);
+
+#if ENABLE(FILE_SYSTEM)
+ String droppedFileSystemId();
+#endif
+
Icon* icon() const;
// These functions are used for rendering the input active during a
// drag-and-drop operation.
@@ -221,7 +231,6 @@ public:
void addSearchResult();
void onSearch();
- bool searchEventsShouldBeDispatched() const;
#if ENABLE(DATALIST)
HTMLElement* list() const;
@@ -232,6 +241,10 @@ public:
void setValueInternal(const String&, TextFieldEventBehavior);
+ bool isTextFormControlFocusable() const;
+ bool isTextFormControlKeyboardFocusable(KeyboardEvent*) const;
+ bool isTextFormControlMouseFocusable() const;
+
void cacheSelectionInResponseToSetValue(int caretOffset) { cacheSelection(caretOffset, caretOffset, SelectionHasNoDirection); }
#if ENABLE(INPUT_TYPE_COLOR)
@@ -253,6 +266,8 @@ public:
void setHeight(unsigned);
void setWidth(unsigned);
+ virtual const AtomicString& name() const OVERRIDE;
+
protected:
HTMLInputElement(const QualifiedName&, Document*, HTMLFormElement*, bool createdByParser);
void createShadowSubtree();
@@ -275,16 +290,14 @@ private:
virtual void aboutToUnload();
virtual bool shouldUseInputMethod();
- virtual const AtomicString& formControlName() const;
-
virtual bool isTextFormControl() const { return isTextField(); }
virtual bool canTriggerImplicitSubmission() const { return isTextField(); }
virtual const AtomicString& formControlType() const;
- virtual bool saveFormControlState(String& value) const;
- virtual void restoreFormControlState(const String&);
+ virtual FormControlState saveFormControlState() const OVERRIDE;
+ virtual void restoreFormControlState(const FormControlState&) OVERRIDE;
virtual bool canStartSelection() const;
diff --git a/Source/WebCore/html/HTMLKeygenElement.idl b/Source/WebCore/html/HTMLKeygenElement.idl
index 914fb99b0..fc6f25c81 100644
--- a/Source/WebCore/html/HTMLKeygenElement.idl
+++ b/Source/WebCore/html/HTMLKeygenElement.idl
@@ -36,7 +36,7 @@ module html {
attribute [Reflect] boolean disabled;
readonly attribute HTMLFormElement form;
attribute [Reflect] DOMString keytype;
- attribute DOMString name;
+ attribute [Reflect] DOMString name;
readonly attribute DOMString type;
diff --git a/Source/WebCore/html/HTMLMediaElement.cpp b/Source/WebCore/html/HTMLMediaElement.cpp
index 0af609ff8..c4accadb2 100644
--- a/Source/WebCore/html/HTMLMediaElement.cpp
+++ b/Source/WebCore/html/HTMLMediaElement.cpp
@@ -86,7 +86,6 @@
#include <wtf/text/CString.h>
#if USE(ACCELERATED_COMPOSITING)
-#include "RenderView.h"
#include "RenderLayerCompositor.h"
#endif
@@ -143,8 +142,6 @@ static const char* boolString(bool val)
#define LOG_CACHED_TIME_WARNINGS 0
#endif
-static const float invalidMediaTime = -1;
-
#if ENABLE(MEDIA_SOURCE)
// URL protocol used to signal that the media source API is being used.
static const char* mediaSourceURLProtocol = "x-media-source";
@@ -224,11 +221,11 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* docum
#if ENABLE(MEDIA_SOURCE)
, m_sourceState(SOURCE_CLOSED)
#endif
- , m_cachedTime(invalidMediaTime)
+ , m_cachedTime(MediaPlayer::invalidTime())
, m_cachedTimeWallClockUpdateTime(0)
, m_minimumWallClockTimeToCacheMediaTime(0)
- , m_fragmentStartTime(invalidMediaTime)
- , m_fragmentEndTime(invalidMediaTime)
+ , m_fragmentStartTime(MediaPlayer::invalidTime())
+ , m_fragmentEndTime(MediaPlayer::invalidTime())
, m_pendingLoadFlags(0)
, m_playing(false)
, m_isWaitingUntilMediaCanStart(false)
@@ -1101,7 +1098,9 @@ void HTMLMediaElement::updateActiveTextTrackCues(float movieTime)
if (!currentCues.contains(previousCues[i]) && previousCues[i].data()->isActive())
activeSetChanged = true;
- for (size_t i = 0; !activeSetChanged && i < currentCuesSize; ++i) {
+ for (size_t i = 0; i < currentCuesSize; ++i) {
+ currentCues[i].data()->updateDisplayTree(movieTime);
+
if (!currentCues[i].data()->isActive())
activeSetChanged = true;
}
@@ -1693,7 +1692,7 @@ void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
if (isPotentiallyPlaying && oldState <= HAVE_CURRENT_DATA)
scheduleEvent(eventNames().playingEvent);
- if (m_autoplaying && m_paused && autoplay() && !document()->isSandboxed(SandboxAutomaticFeatures)) {
+ if (m_autoplaying && m_paused && autoplay() && !document()->isSandboxed(SandboxAutomaticFeatures) && !userGestureRequiredForRateChange()) {
m_paused = false;
invalidateCachedTime();
scheduleEvent(eventNames().playEvent);
@@ -2046,7 +2045,7 @@ void HTMLMediaElement::invalidateCachedTime()
static const double minimumTimePlayingBeforeCacheSnapshot = 0.5;
m_minimumWallClockTimeToCacheMediaTime = WTF::currentTime() + minimumTimePlayingBeforeCacheSnapshot;
- m_cachedTime = invalidMediaTime;
+ m_cachedTime = MediaPlayer::invalidTime();
}
// playback state
@@ -2064,7 +2063,7 @@ float HTMLMediaElement::currentTime() const
return m_lastSeekTime;
}
- if (m_cachedTime != invalidMediaTime && m_paused) {
+ if (m_cachedTime != MediaPlayer::invalidTime() && m_paused) {
#if LOG_CACHED_TIME_WARNINGS
float delta = m_cachedTime - m_player->currentTime();
if (delta > minCachedDeltaForWarning)
@@ -2077,7 +2076,7 @@ float HTMLMediaElement::currentTime() const
double now = WTF::currentTime();
double maximumDurationToCacheMediaTime = m_player->maximumDurationToCacheMediaTime();
- if (maximumDurationToCacheMediaTime && m_cachedTime != invalidMediaTime && !m_paused && now > m_minimumWallClockTimeToCacheMediaTime) {
+ if (maximumDurationToCacheMediaTime && m_cachedTime != MediaPlayer::invalidTime() && !m_paused && now > m_minimumWallClockTimeToCacheMediaTime) {
double wallClockDelta = now - m_cachedTimeWallClockUpdateTime;
// Not too soon, use the cached time only if it hasn't expired.
@@ -2094,7 +2093,7 @@ float HTMLMediaElement::currentTime() const
}
#if LOG_CACHED_TIME_WARNINGS
- if (maximumDurationToCacheMediaTime && now > m_minimumWallClockTimeToCacheMediaTime && m_cachedTime != invalidMediaTime) {
+ if (maximumDurationToCacheMediaTime && now > m_minimumWallClockTimeToCacheMediaTime && m_cachedTime != MediaPlayer::invalidTime()) {
double wallClockDelta = now - m_cachedTimeWallClockUpdateTime;
float delta = m_cachedTime + (m_playbackRate * wallClockDelta) - m_player->currentTime();
LOG(Media, "HTMLMediaElement::currentTime - cached time was %f seconds off of media time when it expired", delta);
@@ -2124,7 +2123,7 @@ float HTMLMediaElement::startTime() const
double HTMLMediaElement::initialTime() const
{
- if (m_fragmentStartTime != invalidMediaTime)
+ if (m_fragmentStartTime != MediaPlayer::invalidTime())
return m_fragmentStartTime;
if (!m_player)
@@ -2724,8 +2723,8 @@ void HTMLMediaElement::playbackProgressTimerFired(Timer<HTMLMediaElement>*)
{
ASSERT(m_player);
- if (m_fragmentEndTime != invalidMediaTime && currentTime() >= m_fragmentEndTime && m_playbackRate > 0) {
- m_fragmentEndTime = invalidMediaTime;
+ if (m_fragmentEndTime != MediaPlayer::invalidTime() && currentTime() >= m_fragmentEndTime && m_playbackRate > 0) {
+ m_fragmentEndTime = MediaPlayer::invalidTime();
if (!m_mediaController && !m_paused) {
// changes paused to true and fires a simple event named pause at the media element.
pauseInternal();
@@ -2798,7 +2797,7 @@ PassRefPtr<TextTrack> HTMLMediaElement::addTextTrack(const String& kind, const S
// 4.8.10.12.4 Text track API
// The addTextTrack(kind, label, language) method of media elements, when invoked, must run the following steps:
-
+
// 1. If kind is not one of the following strings, then throw a SyntaxError exception and abort these steps
if (!TextTrack::isValidKindKeyword(kind)) {
ec = SYNTAX_ERR;
@@ -2808,15 +2807,23 @@ PassRefPtr<TextTrack> HTMLMediaElement::addTextTrack(const String& kind, const S
// 2. If the label argument was omitted, let label be the empty string.
// 3. If the language argument was omitted, let language be the empty string.
// 4. Create a new TextTrack object.
- RefPtr<TextTrack> textTrack = TextTrack::create(ActiveDOMObject::scriptExecutionContext(), this, kind, label, language);
// 5. Create a new text track corresponding to the new object, and set its text track kind to kind, its text
- // track label to label, its text track language to language, its text track readiness state to the text track
- // loaded state, its text track mode to the text track hidden mode, and its text track list of cues to an empty list.
-
+ // track label to label, its text track language to language...
+ RefPtr<TextTrack> textTrack = TextTrack::create(ActiveDOMObject::scriptExecutionContext(), this, kind, label, language);
+
+ // Note, due to side effects when changing track parameters, we have to
+ // first append the track to the text track list.
+
// 6. Add the new text track to the media element's list of text tracks.
textTracks()->append(textTrack);
+ // ... its text track readiness state to the text track loaded state ...
+ textTrack->setReadinessState(TextTrack::Loaded);
+
+ // ... its text track mode to the text track hidden mode, and its text track list of cues to an empty list ...
+ textTrack->setMode(TextTrack::HIDDEN, ec);
+
return textTrack.release();
}
@@ -3723,6 +3730,7 @@ void HTMLMediaElement::userCancelledLoad()
stopPeriodicTimers();
m_loadTimer.stop();
m_loadState = WaitingForSource;
+ m_pendingLoadFlags = 0;
// 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);
@@ -4398,7 +4406,7 @@ void HTMLMediaElement::prepareMediaFragmentURI()
if (m_fragmentStartTime > dur)
m_fragmentStartTime = dur;
} else
- m_fragmentStartTime = invalidMediaTime;
+ m_fragmentStartTime = MediaPlayer::invalidTime();
double end = fragmentParser.endTime();
if (end != MediaFragmentURIParser::invalidTimeValue() && end > 0 && end > m_fragmentStartTime) {
@@ -4406,15 +4414,15 @@ void HTMLMediaElement::prepareMediaFragmentURI()
if (m_fragmentEndTime > dur)
m_fragmentEndTime = dur;
} else
- m_fragmentEndTime = invalidMediaTime;
+ m_fragmentEndTime = MediaPlayer::invalidTime();
- if (m_fragmentStartTime != invalidMediaTime && m_readyState < HAVE_FUTURE_DATA)
+ if (m_fragmentStartTime != MediaPlayer::invalidTime() && m_readyState < HAVE_FUTURE_DATA)
prepareToPlay();
}
void HTMLMediaElement::applyMediaFragmentURI()
{
- if (m_fragmentStartTime != invalidMediaTime) {
+ if (m_fragmentStartTime != MediaPlayer::invalidTime()) {
ExceptionCode ignoredException;
m_sentEndEvent = false;
seek(m_fragmentStartTime, ignoredException);
@@ -4455,6 +4463,15 @@ String HTMLMediaElement::mediaPlayerUserAgent() const
}
+MediaPlayerClient::CORSMode HTMLMediaElement::mediaPlayerCORSMode() const
+{
+ if (!fastHasAttribute(HTMLNames::crossoriginAttr))
+ return Unspecified;
+ if (equalIgnoringCase(fastGetAttribute(HTMLNames::crossoriginAttr), "use-credentials"))
+ return UseCredentials;
+ return Anonymous;
+}
+
bool HTMLMediaElement::mediaPlayerNeedsSiteSpecificHacks() const
{
Settings* settings = document()->settings();
diff --git a/Source/WebCore/html/HTMLMediaElement.h b/Source/WebCore/html/HTMLMediaElement.h
index 5363ae255..1673e1535 100644
--- a/Source/WebCore/html/HTMLMediaElement.h
+++ b/Source/WebCore/html/HTMLMediaElement.h
@@ -427,6 +427,7 @@ private:
virtual String mediaPlayerReferrer() const OVERRIDE;
virtual String mediaPlayerUserAgent() const OVERRIDE;
+ virtual CORSMode mediaPlayerCORSMode() const OVERRIDE;
virtual bool mediaPlayerNeedsSiteSpecificHacks() const OVERRIDE;
virtual String mediaPlayerDocumentHost() const OVERRIDE;
diff --git a/Source/WebCore/html/HTMLMetaElement.cpp b/Source/WebCore/html/HTMLMetaElement.cpp
index cf114f67a..0e0d27b7a 100644
--- a/Source/WebCore/html/HTMLMetaElement.cpp
+++ b/Source/WebCore/html/HTMLMetaElement.cpp
@@ -75,7 +75,7 @@ void HTMLMetaElement::process()
document()->processViewport(contentValue, ViewportArguments::ViewportMeta);
else if (equalIgnoringCase(name(), "referrer"))
document()->processReferrerPolicy(contentValue);
-#if USE(LEGACY_VIEWPORT_ADAPTION)
+#if ENABLE(LEGACY_VIEWPORT_ADAPTION)
else if (equalIgnoringCase(name(), "handheldfriendly") && equalIgnoringCase(contentValue, "true"))
document()->processViewport("width=device-width", ViewportArguments::HandheldFriendlyMeta);
else if (equalIgnoringCase(name(), "mobileoptimized"))
diff --git a/Source/WebCore/html/HTMLObjectElement.cpp b/Source/WebCore/html/HTMLObjectElement.cpp
index 024e825bc..8c5b817a2 100644
--- a/Source/WebCore/html/HTMLObjectElement.cpp
+++ b/Source/WebCore/html/HTMLObjectElement.cpp
@@ -501,12 +501,6 @@ bool HTMLObjectElement::appendFormData(FormDataList& encoding, bool)
return true;
}
-const AtomicString& HTMLObjectElement::formControlName() const
-{
- const AtomicString& name = getNameAttribute();
- return name.isNull() ? emptyAtom : name;
-}
-
HTMLFormElement* HTMLObjectElement::virtualForm() const
{
return FormAssociatedElement::form();
diff --git a/Source/WebCore/html/HTMLObjectElement.h b/Source/WebCore/html/HTMLObjectElement.h
index c44da021d..932e5bccd 100644
--- a/Source/WebCore/html/HTMLObjectElement.h
+++ b/Source/WebCore/html/HTMLObjectElement.h
@@ -58,8 +58,8 @@ public:
bool checkValidity() { return true; }
virtual void setCustomValidity(const String&) OVERRIDE { }
- using TreeShared<ContainerNode>::ref;
- using TreeShared<ContainerNode>::deref;
+ using Node::ref;
+ using Node::deref;
virtual bool canContainRangeEndPoint() const { return useFallbackContent(); }
@@ -101,8 +101,6 @@ private:
virtual void derefFormAssociatedElement() { deref(); }
virtual HTMLFormElement* virtualForm() const;
- virtual const AtomicString& formControlName() const;
-
#if ENABLE(MICRODATA)
virtual String itemValueText() const OVERRIDE;
virtual void setItemValueText(const String&, ExceptionCode&) OVERRIDE;
diff --git a/Source/WebCore/html/HTMLPropertiesCollection.cpp b/Source/WebCore/html/HTMLPropertiesCollection.cpp
index f0a141214..b3f3f1c7b 100644
--- a/Source/WebCore/html/HTMLPropertiesCollection.cpp
+++ b/Source/WebCore/html/HTMLPropertiesCollection.cpp
@@ -128,7 +128,7 @@ Element* HTMLPropertiesCollection::itemAfter(Element* base, Element* previous) c
if (!current->isHTMLElement())
continue;
HTMLElement* element = toHTMLElement(current);
- if (element->fastHasAttribute(itempropAttr)) {
+ if (element->fastHasAttribute(itempropAttr) && element->itemProp()->length()) {
return element;
}
}
diff --git a/Source/WebCore/html/HTMLSelectElement.cpp b/Source/WebCore/html/HTMLSelectElement.cpp
index d066c9fb0..a5d8ad2bc 100644
--- a/Source/WebCore/html/HTMLSelectElement.cpp
+++ b/Source/WebCore/html/HTMLSelectElement.cpp
@@ -33,6 +33,7 @@
#include "Chrome.h"
#include "ChromeClient.h"
#include "EventNames.h"
+#include "FormController.h"
#include "FormDataList.h"
#include "Frame.h"
#include "HTMLFormElement.h"
@@ -349,13 +350,6 @@ bool HTMLSelectElement::childShouldCreateRenderer(const NodeRenderingContext& ch
return childContext.isOnUpperEncapsulationBoundary() && HTMLFormControlElementWithState::childShouldCreateRenderer(childContext);
}
-HTMLCollection* HTMLSelectElement::selectedOptions()
-{
- if (!m_selectedOptionsCollection)
- m_selectedOptionsCollection = HTMLCollection::create(this, SelectedOptions);
- return m_selectedOptionsCollection.get();
-}
-
HTMLOptionsCollection* HTMLSelectElement::options()
{
if (!m_optionsCollection)
@@ -921,7 +915,7 @@ void HTMLSelectElement::deselectItemsWithoutValidation(HTMLElement* excludeEleme
}
}
-bool HTMLSelectElement::saveFormControlState(String& value) const
+FormControlState HTMLSelectElement::saveFormControlState() const
{
const Vector<HTMLElement*>& items = listItems();
size_t length = items.size();
@@ -932,21 +926,21 @@ bool HTMLSelectElement::saveFormControlState(String& value) const
bool selected = element->hasTagName(optionTag) && toHTMLOptionElement(element)->selected();
builder.append(selected ? 'X' : '.');
}
- value = builder.toString();
- return true;
+ return FormControlState(builder.toString());
}
-void HTMLSelectElement::restoreFormControlState(const String& state)
+void HTMLSelectElement::restoreFormControlState(const FormControlState& state)
{
recalcListItems();
const Vector<HTMLElement*>& items = listItems();
size_t length = items.size();
+ String mask = state.value();
for (size_t i = 0; i < length; ++i) {
HTMLElement* element = items[i];
if (element->hasTagName(optionTag))
- toHTMLOptionElement(element)->setSelectedState(state[i] == 'X');
+ toHTMLOptionElement(element)->setSelectedState(mask[i] == 'X');
}
setOptionsChangedOnRenderer();
@@ -964,7 +958,7 @@ void HTMLSelectElement::parseMultipleAttribute(const Attribute& attribute)
bool HTMLSelectElement::appendFormData(FormDataList& list, bool)
{
- const AtomicString& name = formControlName();
+ const AtomicString& name = this->name();
if (name.isEmpty())
return false;
diff --git a/Source/WebCore/html/HTMLSelectElement.h b/Source/WebCore/html/HTMLSelectElement.h
index 3055977ac..e82b117f2 100644
--- a/Source/WebCore/html/HTMLSelectElement.h
+++ b/Source/WebCore/html/HTMLSelectElement.h
@@ -64,7 +64,6 @@ public:
void setValue(const String&);
HTMLOptionsCollection* options();
- HTMLCollection* selectedOptions();
void optionElementChildrenChanged();
@@ -121,8 +120,8 @@ private:
virtual bool isEnumeratable() const { return true; }
virtual bool supportLabels() const OVERRIDE { return true; }
- virtual bool saveFormControlState(String& value) const;
- virtual void restoreFormControlState(const String&);
+ virtual FormControlState saveFormControlState() const OVERRIDE;
+ virtual void restoreFormControlState(const FormControlState&) OVERRIDE;
virtual void parseAttribute(const Attribute&) OVERRIDE;
virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE;
@@ -180,7 +179,6 @@ private:
virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
OwnPtr<HTMLOptionsCollection> m_optionsCollection;
- OwnPtr<HTMLCollection> m_selectedOptionsCollection;
// m_listItems contains HTMLOptionElement, HTMLOptGroupElement, and HTMLHRElement objects.
mutable Vector<HTMLElement*> m_listItems;
diff --git a/Source/WebCore/html/HTMLSelectElement.idl b/Source/WebCore/html/HTMLSelectElement.idl
index b86363694..de8d2d6d0 100644
--- a/Source/WebCore/html/HTMLSelectElement.idl
+++ b/Source/WebCore/html/HTMLSelectElement.idl
@@ -28,7 +28,7 @@ module html {
attribute [Reflect] boolean disabled;
readonly attribute HTMLFormElement form;
attribute boolean multiple;
- attribute [TreatNullAs=NullString] DOMString name;
+ attribute [Reflect] DOMString name;
attribute [Reflect] boolean required;
attribute long size;
@@ -53,7 +53,6 @@ module html {
#else
void remove(in long index);
#endif
- readonly attribute HTMLCollection selectedOptions;
attribute long selectedIndex;
attribute [TreatNullAs=NullString] DOMString value;
diff --git a/Source/WebCore/html/HTMLStyleElement.cpp b/Source/WebCore/html/HTMLStyleElement.cpp
index 67ddceb4f..e2189e96b 100644
--- a/Source/WebCore/html/HTMLStyleElement.cpp
+++ b/Source/WebCore/html/HTMLStyleElement.cpp
@@ -25,13 +25,14 @@
#include "HTMLStyleElement.h"
#include "Attribute.h"
-#include "ContextEnabledFeatures.h"
+#include "ContextFeatures.h"
#include "Document.h"
#include "Event.h"
#include "EventSender.h"
#include "HTMLNames.h"
#include "ScriptEventListener.h"
#include "ScriptableDocumentParser.h"
+#include "ShadowRoot.h"
#include "StyleSheetContents.h"
namespace WebCore {
@@ -50,7 +51,7 @@ inline HTMLStyleElement::HTMLStyleElement(const QualifiedName& tagName, Document
, m_firedLoad(false)
, m_loadedSheet(false)
#if ENABLE(STYLE_SCOPED)
- , m_isRegisteredWithScopingNode(false)
+ , m_scopedStyleRegistrationState(NotRegistered)
#endif
{
ASSERT(hasTagName(styleTag));
@@ -58,8 +59,8 @@ inline HTMLStyleElement::HTMLStyleElement(const QualifiedName& tagName, Document
HTMLStyleElement::~HTMLStyleElement()
{
- // During tear-down, willRemove isn't called, so m_isRegisteredWithScopingNode may still be set here.
- // Therefore we can't ASSERT(!m_isRegisteredWithScopingNode).
+ // During tear-down, willRemove isn't called, so m_scopedStyleRegistrationState may still be RegisteredAsScoped or RegisteredInShadowRoot here.
+ // Therefore we can't ASSERT(m_scopedStyleRegistrationState == NotRegistered).
StyleElement::clearDocumentData(document(), this);
styleLoadEventSender().cancelEvent(this);
@@ -79,17 +80,42 @@ void HTMLStyleElement::parseAttribute(const Attribute& attribute)
else if (attribute.name() == onerrorAttr)
setAttributeEventListener(eventNames().errorEvent, createAttributeEventListener(this, attribute));
#if ENABLE(STYLE_SCOPED)
- else if (attribute.name() == scopedAttr) {
- if (!attribute.isNull() && !m_isRegisteredWithScopingNode && inDocument())
- registerWithScopingNode();
- else if (attribute.isNull() && m_isRegisteredWithScopingNode)
- unregisterWithScopingNode();
- }
+ else if (attribute.name() == scopedAttr)
+ scopedAttributeChanged(!attribute.isNull());
#endif
else
HTMLElement::parseAttribute(attribute);
}
+#if ENABLE(STYLE_SCOPED)
+void HTMLStyleElement::scopedAttributeChanged(bool scoped)
+{
+ if (!inDocument())
+ return;
+
+ if (scoped) {
+ // As any <style> in a shadow tree is treated as "scoped",
+ // need to remove the <style> from its shadow root.
+ if (m_scopedStyleRegistrationState == RegisteredInShadowRoot)
+ unregisterWithScopingNode(shadowRoot());
+
+ if (m_scopedStyleRegistrationState != RegisteredAsScoped)
+ registerWithScopingNode(true);
+ return;
+ }
+
+ // If the <style> was scoped, need to remove the <style> from the scoping
+ // element, i.e. the parent node.
+ if (m_scopedStyleRegistrationState == RegisteredAsScoped)
+ unregisterWithScopingNode(parentNode());
+
+ // As any <style> in a shadow tree is treated as "scoped",
+ // need to add the <style> to its shadow root.
+ if (isInShadowTree() && m_scopedStyleRegistrationState != RegisteredInShadowRoot)
+ registerWithScopingNode(false);
+}
+#endif
+
void HTMLStyleElement::finishParsingChildren()
{
StyleElement::finishParsingChildren(this);
@@ -97,18 +123,18 @@ void HTMLStyleElement::finishParsingChildren()
}
#if ENABLE(STYLE_SCOPED)
-void HTMLStyleElement::registerWithScopingNode()
+void HTMLStyleElement::registerWithScopingNode(bool scoped)
{
// Note: We cannot rely on the 'scoped' element already being present when this method is invoked.
// Therefore we cannot rely on scoped()!
- ASSERT(!m_isRegisteredWithScopingNode);
+ ASSERT(m_scopedStyleRegistrationState == NotRegistered);
ASSERT(inDocument());
- if (m_isRegisteredWithScopingNode)
+ if (m_scopedStyleRegistrationState != NotRegistered)
return;
- if (!ContextEnabledFeatures::styleScopedEnabled(document()))
+ if (!ContextFeatures::styleScopedEnabled(document()))
return;
- ContainerNode* scope = parentNode();
+ ContainerNode* scope = scoped ? parentNode() : shadowRoot();
if (!scope)
return;
if (!scope->isElementNode() && !scope->isShadowRoot()) {
@@ -123,17 +149,17 @@ void HTMLStyleElement::registerWithScopingNode()
if (inDocument() && !document()->parsing() && document()->renderer())
document()->styleResolverChanged(DeferRecalcStyle);
- m_isRegisteredWithScopingNode = true;
+ m_scopedStyleRegistrationState = scoped ? RegisteredAsScoped : RegisteredInShadowRoot;
}
void HTMLStyleElement::unregisterWithScopingNode(ContainerNode* scope)
{
// Note: We cannot rely on the 'scoped' element still being present when this method is invoked.
// Therefore we cannot rely on scoped()!
- ASSERT(m_isRegisteredWithScopingNode || !ContextEnabledFeatures::styleScopedEnabled(document()));
- if (!m_isRegisteredWithScopingNode)
+ ASSERT(m_scopedStyleRegistrationState != NotRegistered || !ContextFeatures::styleScopedEnabled(document()));
+ if (m_scopedStyleRegistrationState == NotRegistered)
return;
- if (!ContextEnabledFeatures::styleScopedEnabled(document()))
+ if (!ContextFeatures::styleScopedEnabled(document()))
return;
ASSERT(scope);
@@ -145,7 +171,7 @@ void HTMLStyleElement::unregisterWithScopingNode(ContainerNode* scope)
if (inDocument() && !document()->parsing() && document()->renderer())
document()->styleResolverChanged(DeferRecalcStyle);
- m_isRegisteredWithScopingNode = false;
+ m_scopedStyleRegistrationState = NotRegistered;
}
#endif
@@ -155,8 +181,8 @@ Node::InsertionNotificationRequest HTMLStyleElement::insertedInto(ContainerNode*
if (insertionPoint->inDocument()) {
StyleElement::insertedIntoDocument(document(), this);
#if ENABLE(STYLE_SCOPED)
- if (scoped() && !m_isRegisteredWithScopingNode)
- registerWithScopingNode();
+ if (m_scopedStyleRegistrationState == NotRegistered && (scoped() || isInShadowTree()))
+ registerWithScopingNode(scoped());
#endif
}
@@ -172,8 +198,12 @@ void HTMLStyleElement::removedFrom(ContainerNode* insertionPoint)
// That is, because willRemove() is also called if an ancestor is removed from the document.
// Now, if we want to register <style scoped> even if it's not inDocument,
// we'd need to find a way to discern whether that is the case, or whether <style scoped> itself is about to be removed.
- if (m_isRegisteredWithScopingNode)
- unregisterWithScopingNode(parentNode() ? parentNode() : insertionPoint);
+ if (m_scopedStyleRegistrationState != NotRegistered) {
+ ContainerNode* scope = parentNode()? parentNode() : insertionPoint;
+ if (m_scopedStyleRegistrationState == RegisteredInShadowRoot)
+ scope = scope->shadowRoot();
+ unregisterWithScopingNode(scope);
+ }
#endif
if (insertionPoint->inDocument())
diff --git a/Source/WebCore/html/HTMLStyleElement.h b/Source/WebCore/html/HTMLStyleElement.h
index 7e3125454..63a82c4ee 100644
--- a/Source/WebCore/html/HTMLStyleElement.h
+++ b/Source/WebCore/html/HTMLStyleElement.h
@@ -76,15 +76,22 @@ private:
virtual const AtomicString& media() const;
virtual const AtomicString& type() const;
- void registerWithScopingNode();
- void unregisterWithScopingNode() { unregisterWithScopingNode(parentNode()); }
- void unregisterWithScopingNode(ContainerNode* scope);
+#if ENABLE(STYLE_SCOPED)
+ void scopedAttributeChanged(bool);
+ void registerWithScopingNode(bool);
+ void unregisterWithScopingNode(ContainerNode*);
+#endif
bool m_firedLoad;
bool m_loadedSheet;
#if ENABLE(STYLE_SCOPED)
- bool m_isRegisteredWithScopingNode;
+ enum ScopedStyleRegistrationState {
+ NotRegistered,
+ RegisteredAsScoped,
+ RegisteredInShadowRoot
+ };
+ ScopedStyleRegistrationState m_scopedStyleRegistrationState;
#endif
};
diff --git a/Source/WebCore/html/HTMLTextAreaElement.cpp b/Source/WebCore/html/HTMLTextAreaElement.cpp
index 643725708..bf5125f8b 100644
--- a/Source/WebCore/html/HTMLTextAreaElement.cpp
+++ b/Source/WebCore/html/HTMLTextAreaElement.cpp
@@ -34,6 +34,7 @@
#include "Event.h"
#include "EventNames.h"
#include "ExceptionCode.h"
+#include "FormController.h"
#include "FormDataList.h"
#include "Frame.h"
#include "HTMLNames.h"
@@ -98,18 +99,17 @@ const AtomicString& HTMLTextAreaElement::formControlType() const
return textarea;
}
-bool HTMLTextAreaElement::saveFormControlState(String& result) const
+FormControlState HTMLTextAreaElement::saveFormControlState() const
{
String currentValue = value();
if (currentValue == defaultValue())
- return false;
- result = currentValue;
- return true;
+ return FormControlState();
+ return FormControlState(currentValue);
}
-void HTMLTextAreaElement::restoreFormControlState(const String& state)
+void HTMLTextAreaElement::restoreFormControlState(const FormControlState& state)
{
- setValue(state);
+ setValue(state.value());
}
void HTMLTextAreaElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
diff --git a/Source/WebCore/html/HTMLTextAreaElement.h b/Source/WebCore/html/HTMLTextAreaElement.h
index 63ce9ea77..18ebead28 100644
--- a/Source/WebCore/html/HTMLTextAreaElement.h
+++ b/Source/WebCore/html/HTMLTextAreaElement.h
@@ -90,8 +90,8 @@ private:
virtual const AtomicString& formControlType() const;
- virtual bool saveFormControlState(String& value) const;
- virtual void restoreFormControlState(const String&);
+ virtual FormControlState saveFormControlState() const OVERRIDE;
+ virtual void restoreFormControlState(const FormControlState&) OVERRIDE;
virtual bool isTextFormControl() const { return true; }
diff --git a/Source/WebCore/html/HTMLTextAreaElement.idl b/Source/WebCore/html/HTMLTextAreaElement.idl
index f9d80b5ad..729e6dae6 100644
--- a/Source/WebCore/html/HTMLTextAreaElement.idl
+++ b/Source/WebCore/html/HTMLTextAreaElement.idl
@@ -28,7 +28,7 @@ module html {
attribute [Reflect] boolean disabled;
readonly attribute HTMLFormElement form;
attribute long maxLength setter raises(DOMException);
- attribute [TreatNullAs=NullString] DOMString name;
+ attribute [Reflect] DOMString name;
attribute [Reflect] DOMString placeholder;
attribute [Reflect] boolean readOnly;
attribute [Reflect] boolean required;
diff --git a/Source/WebCore/html/HiddenInputType.cpp b/Source/WebCore/html/HiddenInputType.cpp
index 4efb8d60f..96d4ce001 100644
--- a/Source/WebCore/html/HiddenInputType.cpp
+++ b/Source/WebCore/html/HiddenInputType.cpp
@@ -32,6 +32,7 @@
#include "config.h"
#include "HiddenInputType.h"
+#include "FormController.h"
#include "FormDataList.h"
#include "HTMLInputElement.h"
#include "HTMLNames.h"
@@ -51,15 +52,15 @@ const AtomicString& HiddenInputType::formControlType() const
return InputTypeNames::hidden();
}
-bool HiddenInputType::saveFormControlState(String& result) const
+FormControlState HiddenInputType::saveFormControlState() const
{
- result = element()->value();
- return true;
+ // FIXME: We should not always save the value. http://webkit.org/b/88685
+ return FormControlState(element()->value());
}
-void HiddenInputType::restoreFormControlState(const String& string)
+void HiddenInputType::restoreFormControlState(const FormControlState& state)
{
- element()->setAttribute(valueAttr, string);
+ element()->setAttribute(valueAttr, state.value());
}
bool HiddenInputType::supportsValidation() const
diff --git a/Source/WebCore/html/HiddenInputType.h b/Source/WebCore/html/HiddenInputType.h
index b6be4e995..dbf227883 100644
--- a/Source/WebCore/html/HiddenInputType.h
+++ b/Source/WebCore/html/HiddenInputType.h
@@ -42,8 +42,8 @@ public:
private:
HiddenInputType(HTMLInputElement* element) : InputType(element) { }
virtual const AtomicString& formControlType() const OVERRIDE;
- virtual bool saveFormControlState(String&) const OVERRIDE;
- virtual void restoreFormControlState(const String&) OVERRIDE;
+ virtual FormControlState saveFormControlState() const OVERRIDE;
+ virtual void restoreFormControlState(const FormControlState&) OVERRIDE;
virtual bool supportsValidation() const OVERRIDE;
virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) const OVERRIDE;
virtual void accessKeyAction(bool sendMouseEvents) OVERRIDE;
diff --git a/Source/WebCore/html/InputType.cpp b/Source/WebCore/html/InputType.cpp
index e91960d40..514119fea 100644
--- a/Source/WebCore/html/InputType.cpp
+++ b/Source/WebCore/html/InputType.cpp
@@ -42,6 +42,7 @@
#include "ExceptionCode.h"
#include "FileInputType.h"
#include "FileList.h"
+#include "FormController.h"
#include "FormDataList.h"
#include "HTMLFormElement.h"
#include "HTMLInputElement.h"
@@ -168,18 +169,17 @@ bool InputType::isRangeControl() const
return false;
}
-bool InputType::saveFormControlState(String& result) const
+FormControlState InputType::saveFormControlState() const
{
String currentValue = element()->value();
if (currentValue == element()->defaultValue())
- return false;
- result = currentValue;
- return true;
+ return FormControlState();
+ return FormControlState(currentValue);
}
-void InputType::restoreFormControlState(const String& state)
+void InputType::restoreFormControlState(const FormControlState& state)
{
- element()->setValue(state);
+ element()->setValue(state.value());
}
bool InputType::isFormDataAppendable() const
@@ -205,12 +205,17 @@ void InputType::setValueAsDate(double, ExceptionCode& ec) const
ec = INVALID_STATE_ERR;
}
-double InputType::valueAsNumber() const
+double InputType::valueAsDouble() const
{
return numeric_limits<double>::quiet_NaN();
}
-void InputType::setValueAsNumber(double, TextFieldEventBehavior, ExceptionCode& ec) const
+void InputType::setValueAsDouble(double doubleValue, TextFieldEventBehavior eventBehavior, ExceptionCode& ec) const
+{
+ setValueAsDecimal(Decimal::fromDouble(doubleValue), eventBehavior, ec);
+}
+
+void InputType::setValueAsDecimal(const Decimal&, TextFieldEventBehavior, ExceptionCode& ec) const
{
ec = INVALID_STATE_ERR;
}
@@ -251,11 +256,11 @@ bool InputType::rangeUnderflow(const String& value) const
if (!isSteppable())
return false;
- double doubleValue = parseToDouble(value, numeric_limits<double>::quiet_NaN());
- if (isnan(doubleValue))
+ const Decimal numericValue = parseToNumberOrNaN(value);
+ if (!numericValue.isFinite())
return false;
- return doubleValue < createStepRange(RejectAny).minimum();
+ return numericValue < createStepRange(RejectAny).minimum();
}
bool InputType::rangeOverflow(const String& value) const
@@ -263,26 +268,26 @@ bool InputType::rangeOverflow(const String& value) const
if (!isSteppable())
return false;
- double doubleValue = parseToDouble(value, numeric_limits<double>::quiet_NaN());
- if (isnan(doubleValue))
+ const Decimal numericValue = parseToNumberOrNaN(value);
+ if (!numericValue.isFinite())
return false;
- return doubleValue > createStepRange(RejectAny).maximum();
+ return numericValue > createStepRange(RejectAny).maximum();
}
-double InputType::defaultValueForStepUp() const
+Decimal InputType::defaultValueForStepUp() const
{
return 0;
}
double InputType::minimum() const
{
- return createStepRange(RejectAny).minimum();
+ return createStepRange(RejectAny).minimum().toDouble();
}
double InputType::maximum() const
{
- return createStepRange(RejectAny).maximum();
+ return createStepRange(RejectAny).maximum().toDouble();
}
bool InputType::sizeShouldIncludeDecoration(int, int& preferredSize) const
@@ -296,12 +301,12 @@ bool InputType::isInRange(const String& value) const
if (!isSteppable())
return false;
- double doubleValue = parseToDouble(value, numeric_limits<double>::quiet_NaN());
- if (isnan(doubleValue))
+ const Decimal numericValue = parseToNumberOrNaN(value);
+ if (!numericValue.isFinite())
return true;
StepRange stepRange(createStepRange(RejectAny));
- return doubleValue >= stepRange.minimum() && doubleValue <= stepRange.maximum();
+ return numericValue >= stepRange.minimum() && numericValue <= stepRange.maximum();
}
bool InputType::isOutOfRange(const String& value) const
@@ -309,12 +314,12 @@ bool InputType::isOutOfRange(const String& value) const
if (!isSteppable())
return false;
- double doubleValue = parseToDouble(value, numeric_limits<double>::quiet_NaN());
- if (isnan(doubleValue))
+ const Decimal numericValue = parseToNumberOrNaN(value);
+ if (!numericValue.isFinite())
return true;
StepRange stepRange(createStepRange(RejectAny));
- return doubleValue < stepRange.minimum() || doubleValue > stepRange.maximum();
+ return numericValue < stepRange.minimum() || numericValue > stepRange.maximum();
}
bool InputType::stepMismatch(const String& value) const
@@ -322,11 +327,11 @@ bool InputType::stepMismatch(const String& value) const
if (!isSteppable())
return false;
- double doubleValue = parseToDouble(value, numeric_limits<double>::quiet_NaN());
- if (isnan(doubleValue))
+ const Decimal numericValue = parseToNumberOrNaN(value);
+ if (!numericValue.isFinite())
return false;
- return createStepRange(RejectAny).stepMismatch(doubleValue);
+ return createStepRange(RejectAny).stepMismatch(numericValue);
}
String InputType::typeMismatchText() const
@@ -360,19 +365,19 @@ String InputType::validationMessage() const
if (!isSteppable())
return emptyString();
- double doubleValue = parseToDouble(value, numeric_limits<double>::quiet_NaN());
- if (isnan(doubleValue))
+ const Decimal numericValue = parseToNumberOrNaN(value);
+ if (!numericValue.isFinite())
return emptyString();
StepRange stepRange(createStepRange(RejectAny));
- if (doubleValue < stepRange.minimum())
+ if (numericValue < stepRange.minimum())
return validationMessageRangeUnderflowText(serialize(stepRange.minimum()));
- if (doubleValue < stepRange.maximum())
+ if (numericValue < stepRange.maximum())
return validationMessageRangeOverflowText(serialize(stepRange.maximum()));
- if (stepRange.stepMismatch(doubleValue)) {
+ if (stepRange.stepMismatch(numericValue)) {
const String stepString = stepRange.hasStep() ? serializeForNumberType(stepRange.step() / stepRange.stepScaleFactor()) : emptyString();
return validationMessageStepMismatchText(serialize(stepRange.stepBase()), stepString);
}
@@ -453,17 +458,15 @@ void InputType::destroyShadowSubtree()
}
}
-double InputType::parseToDouble(const String&, double defaultValue) const
+Decimal InputType::parseToNumber(const String&, const Decimal& defaultValue) const
{
ASSERT_NOT_REACHED();
return defaultValue;
}
-double InputType::parseToDoubleWithDecimalPlaces(const String& src, double defaultValue, unsigned *decimalPlaces) const
+Decimal InputType::parseToNumberOrNaN(const String& string) const
{
- if (decimalPlaces)
- *decimalPlaces = 0;
- return parseToDouble(src, defaultValue);
+ return parseToNumber(string, Decimal::nan());
}
bool InputType::parseToDateComponents(const String&, DateComponents*) const
@@ -472,7 +475,7 @@ bool InputType::parseToDateComponents(const String&, DateComponents*) const
return false;
}
-String InputType::serialize(double) const
+String InputType::serialize(const Decimal&) const
{
ASSERT_NOT_REACHED();
return String();
@@ -497,9 +500,14 @@ bool InputType::canSetStringValue() const
return true;
}
-bool InputType::isKeyboardFocusable() const
+bool InputType::isKeyboardFocusable(KeyboardEvent* event) const
{
- return true;
+ return element()->isTextFormControlKeyboardFocusable(event);
+}
+
+bool InputType::isMouseFocusable() const
+{
+ return element()->isTextFormControlMouseFocusable();
}
bool InputType::shouldUseInputMethod() const
@@ -520,6 +528,10 @@ void InputType::accessKeyAction(bool)
element()->focus(false);
}
+void InputType::addSearchResult()
+{
+}
+
void InputType::attach()
{
}
@@ -664,10 +676,19 @@ bool InputType::hasUnacceptableValue()
return false;
}
-void InputType::receiveDroppedFiles(const Vector<String>&)
+bool InputType::receiveDroppedFiles(const DragData*)
{
ASSERT_NOT_REACHED();
+ return false;
+}
+
+#if ENABLE(FILE_SYSTEM)
+String InputType::droppedFileSystemId()
+{
+ ASSERT_NOT_REACHED();
+ return String();
}
+#endif
Icon* InputType::icon() const
{
@@ -848,6 +869,10 @@ void InputType::readonlyAttributeChanged()
{
}
+void InputType::subtreeHasChanged()
+{
+}
+
String InputType::defaultToolTip() const
{
return String();
@@ -868,7 +893,7 @@ unsigned InputType::width() const
return 0;
}
-void InputType::applyStep(double count, AnyStepHandling anyStepHandling, TextFieldEventBehavior eventBehavior, ExceptionCode& ec)
+void InputType::applyStep(int count, AnyStepHandling anyStepHandling, TextFieldEventBehavior eventBehavior, ExceptionCode& ec)
{
StepRange stepRange(createStepRange(anyStepHandling));
if (!stepRange.hasStep()) {
@@ -876,20 +901,18 @@ void InputType::applyStep(double count, AnyStepHandling anyStepHandling, TextFie
return;
}
- const double nan = numeric_limits<double>::quiet_NaN();
- unsigned currentDecimalPlaces;
- double current = parseToDoubleWithDecimalPlaces(element()->value(), nan, &currentDecimalPlaces);
- if (!isfinite(current)) {
+ const Decimal current = parseToNumberOrNaN(element()->value());
+ if (!current.isFinite()) {
ec = INVALID_STATE_ERR;
return;
}
- double newValue = current + stepRange.step() * count;
- if (isinf(newValue)) {
+ Decimal newValue = current + stepRange.step() * count;
+ if (!newValue.isFinite()) {
ec = INVALID_STATE_ERR;
return;
}
- double acceptableErrorValue = stepRange.acceptableError();
+ const Decimal acceptableErrorValue = stepRange.acceptableError();
if (newValue - stepRange.minimum() < -acceptableErrorValue) {
ec = INVALID_STATE_ERR;
return;
@@ -899,7 +922,7 @@ void InputType::applyStep(double count, AnyStepHandling anyStepHandling, TextFie
const AtomicString& stepString = element()->fastGetAttribute(stepAttr);
if (!equalIgnoringCase(stepString, "any"))
- newValue = stepRange.alignValueForStep(current, currentDecimalPlaces, newValue);
+ newValue = stepRange.alignValueForStep(current, newValue);
if (newValue - stepRange.maximum() > acceptableErrorValue) {
ec = INVALID_STATE_ERR;
@@ -908,13 +931,13 @@ void InputType::applyStep(double count, AnyStepHandling anyStepHandling, TextFie
if (newValue > stepRange.maximum())
newValue = stepRange.maximum();
- element()->setValueAsNumber(newValue, ec, eventBehavior);
+ setValueAsDecimal(newValue, eventBehavior, ec);
if (AXObjectCache::accessibilityEnabled())
element()->document()->axObjectCache()->postNotification(element()->renderer(), AXObjectCache::AXValueChanged, true);
}
-bool InputType::getAllowedValueStep(double* step) const
+bool InputType::getAllowedValueStep(Decimal* step) const
{
StepRange stepRange(createStepRange(RejectAny));
*step = stepRange.step();
@@ -987,7 +1010,7 @@ void InputType::stepUpFromRenderer(int n)
if (!stepRange.hasStep())
return;
- double step = stepRange.step();
+ const Decimal step = stepRange.step();
int sign;
if (step > 0)
@@ -997,33 +1020,31 @@ void InputType::stepUpFromRenderer(int n)
else
sign = 0;
- const double nan = numeric_limits<double>::quiet_NaN();
String currentStringValue = element()->value();
- double current = parseToDouble(currentStringValue, nan);
- if (!isfinite(current)) {
+ Decimal current = parseToNumberOrNaN(currentStringValue);
+ if (!current.isFinite()) {
ExceptionCode ec;
current = defaultValueForStepUp();
- double nextDiff = step * n;
+ const Decimal nextDiff = step * n;
if (current < stepRange.minimum() - nextDiff)
current = stepRange.minimum() - nextDiff;
if (current > stepRange.maximum() - nextDiff)
current = stepRange.maximum() - nextDiff;
- element()->setValueAsNumber(current, ec, DispatchInputAndChangeEvent);
+ setValueAsDecimal(current, DispatchInputAndChangeEvent, ec);
}
- if ((sign > 0 && current < stepRange.minimum()) || (sign < 0 && current > stepRange.maximum()))
- element()->setValue(serialize(sign > 0 ? stepRange.minimum() : stepRange.maximum()), DispatchInputAndChangeEvent);
- else {
+ if ((sign > 0 && current < stepRange.minimum()) || (sign < 0 && current > stepRange.maximum())) {
+ ExceptionCode ec;
+ setValueAsDecimal(sign > 0 ? stepRange.minimum() : stepRange.maximum(), DispatchInputAndChangeEvent, ec);
+ } else {
ExceptionCode ec;
if (stepMismatch(element()->value())) {
- ASSERT(step);
- double newValue;
- double scale = pow(10.0, static_cast<double>(max(stepRange.stepDecimalPlaces(), stepRange.stepBaseDecimalPlaces())));
- double base = stepRange.stepBase();
-
+ ASSERT(!step.isZero());
+ const Decimal base = stepRange.stepBase();
+ Decimal newValue;
if (sign < 0)
- newValue = round((base + floor((current - base) / step) * step) * scale) / scale;
+ newValue = base + ((current - base) / step).floor() * step;
else if (sign > 0)
- newValue = round((base + ceil((current - base) / step) * step) * scale) / scale;
+ newValue = base + ((current - base) / step).ceiling() * step;
else
newValue = current;
@@ -1032,8 +1053,7 @@ void InputType::stepUpFromRenderer(int n)
if (newValue > stepRange.maximum())
newValue = stepRange.maximum();
- element()->setValueAsNumber(newValue, ec, n == 1 || n == -1 ? DispatchInputAndChangeEvent : DispatchNoEvent);
- current = newValue;
+ setValueAsDecimal(newValue, n == 1 || n == -1 ? DispatchInputAndChangeEvent : DispatchNoEvent, ec);
if (n > 1)
applyStep(n - 1, AnyIsDefaultStep, DispatchInputAndChangeEvent, ec);
else if (n < -1)
diff --git a/Source/WebCore/html/InputType.h b/Source/WebCore/html/InputType.h
index 83efbdebe..451303d13 100644
--- a/Source/WebCore/html/InputType.h
+++ b/Source/WebCore/html/InputType.h
@@ -47,6 +47,7 @@ class BeforeTextInsertedEvent;
class Chrome;
class Color;
class DateComponents;
+class DragData;
class Event;
class FileList;
class FormDataList;
@@ -125,8 +126,8 @@ public:
// Form value functions
- virtual bool saveFormControlState(String&) const;
- virtual void restoreFormControlState(const String&);
+ virtual FormControlState saveFormControlState() const;
+ virtual void restoreFormControlState(const FormControlState&);
virtual bool isFormDataAppendable() const;
virtual bool appendFormData(FormDataList&, bool multipart) const;
@@ -137,8 +138,9 @@ public:
virtual String defaultValue() const; // Checked after even fallbackValue, only when the valueWithDefault function is called.
virtual double valueAsDate() const;
virtual void setValueAsDate(double, ExceptionCode&) const;
- virtual double valueAsNumber() const;
- virtual void setValueAsNumber(double, TextFieldEventBehavior, ExceptionCode&) const;
+ virtual double valueAsDouble() const;
+ virtual void setValueAsDouble(double, TextFieldEventBehavior, ExceptionCode&) const;
+ virtual void setValueAsDecimal(const Decimal&, TextFieldEventBehavior, ExceptionCode&) const;
// Validation functions
virtual String validationMessage() const;
@@ -155,12 +157,12 @@ public:
bool rangeOverflow(const String&) const;
bool isInRange(const String&) const;
bool isOutOfRange(const String&) const;
- virtual double defaultValueForStepUp() const;
+ virtual Decimal defaultValueForStepUp() const;
double minimum() const;
double maximum() const;
virtual bool sizeShouldIncludeDecoration(int defaultSize, int& preferredSize) const;
bool stepMismatch(const String&) const;
- virtual bool getAllowedValueStep(double*) const;
+ virtual bool getAllowedValueStep(Decimal*) const;
virtual StepRange createStepRange(AnyStepHandling) const;
virtual void stepUp(int, ExceptionCode&);
virtual void stepUpFromRenderer(int);
@@ -192,13 +194,14 @@ public:
// Helpers for event handlers.
virtual bool shouldSubmitImplicitly(Event*);
virtual PassRefPtr<HTMLFormElement> formForSubmission() const;
- virtual bool isKeyboardFocusable() const;
+ virtual bool isKeyboardFocusable(KeyboardEvent*) const;
+ virtual bool isMouseFocusable() const;
virtual bool shouldUseInputMethod() const;
virtual void handleFocusEvent();
virtual void handleBlurEvent();
virtual void accessKeyAction(bool sendMouseEvents);
virtual bool canBeSuccessfulSubmitButton();
-
+ virtual void subtreeHasChanged();
// Shadow tree handling
@@ -220,6 +223,7 @@ public:
virtual bool rendererIsNeeded();
virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) const;
+ virtual void addSearchResult();
virtual void attach();
virtual void detach();
virtual void minOrMaxAttributeChanged();
@@ -230,7 +234,11 @@ public:
virtual bool shouldRespectAlignAttribute();
virtual FileList* files();
virtual void setFiles(PassRefPtr<FileList>);
- virtual void receiveDroppedFiles(const Vector<String>&);
+ // Should return true if the given DragData has more than one dropped files.
+ virtual bool receiveDroppedFiles(const DragData*);
+#if ENABLE(FILE_SYSTEM)
+ virtual String droppedFileSystemId();
+#endif
virtual Icon* icon() const;
// Should return true if the corresponding renderer for a type can display a suggested value.
virtual bool canSetSuggestedValue();
@@ -260,15 +268,10 @@ public:
virtual String defaultToolTip() const;
// Parses the specified string for the type, and return
- // the double value for the parsing result if the parsing
+ // the Decimal 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 the type as parseToDouble() does.
- // In addition, it stores the number of digits after the decimal point
- // into *decimalPlaces.
- virtual double parseToDoubleWithDecimalPlaces(const String&, double defaultValue, unsigned* decimalPlaces) const;
+ virtual Decimal parseToNumber(const String&, const Decimal& defaultValue) const;
// Parses the specified string for this InputType, and returns true if it
// is successfully parsed. An instance pointed by the DateComponents*
@@ -276,10 +279,10 @@ public:
// 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
+ // Create a string representation of the specified Decimal 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;
+ virtual String serialize(const Decimal&) const;
virtual bool supportsIndeterminateAppearance() const;
@@ -293,10 +296,11 @@ protected:
HTMLInputElement* element() const { return m_element; }
void dispatchSimulatedClickIfActive(KeyboardEvent*) const;
Chrome* chrome() const;
+ Decimal parseToNumberOrNaN(const String&) const;
private:
// Helper for stepUp()/stepDown(). Adds step value * count to the current value.
- void applyStep(double count, AnyStepHandling, TextFieldEventBehavior, ExceptionCode&);
+ void applyStep(int count, AnyStepHandling, TextFieldEventBehavior, ExceptionCode&);
// Raw pointer because the HTMLInputElement object owns this InputType object.
HTMLInputElement* m_element;
diff --git a/Source/WebCore/html/LabelsNodeList.cpp b/Source/WebCore/html/LabelsNodeList.cpp
index 5554c1232..fb3442be6 100644
--- a/Source/WebCore/html/LabelsNodeList.cpp
+++ b/Source/WebCore/html/LabelsNodeList.cpp
@@ -32,8 +32,9 @@ namespace WebCore {
using namespace HTMLNames;
-LabelsNodeList::LabelsNodeList(Node* forNode )
- : DynamicSubtreeNodeList(forNode->document()) , m_forNode(forNode)
+LabelsNodeList::LabelsNodeList(Node* forNode)
+ : DynamicSubtreeNodeList(forNode, RootedAtDocument)
+ , m_forNode(forNode)
{
m_forNode->document()->registerDynamicSubtreeNodeList(this);
}
diff --git a/Source/WebCore/html/MediaController.cpp b/Source/WebCore/html/MediaController.cpp
index 806af55b9..bba6f0310 100644
--- a/Source/WebCore/html/MediaController.cpp
+++ b/Source/WebCore/html/MediaController.cpp
@@ -142,8 +142,9 @@ float MediaController::currentTime() const
{
if (m_mediaElements.isEmpty())
return 0;
-
- return m_clock->currentTime();
+
+ // Some clocks may return times outside the range of [0..duration].
+ return max(0.0f, min(duration(), m_clock->currentTime()));
}
void MediaController::setCurrentTime(float time, ExceptionCode& code)
diff --git a/Source/WebCore/html/MediaDocument.cpp b/Source/WebCore/html/MediaDocument.cpp
index 58ff49633..e5194542a 100644
--- a/Source/WebCore/html/MediaDocument.cpp
+++ b/Source/WebCore/html/MediaDocument.cpp
@@ -166,6 +166,7 @@ void MediaDocument::defaultEventHandler(Event* event)
if (!targetNode)
return;
+#if !PLATFORM(CHROMIUM)
if (HTMLVideoElement* video = ancestorVideoElement(targetNode)) {
if (event->type() == eventNames().clickEvent) {
if (!video->canPlay()) {
@@ -179,7 +180,8 @@ void MediaDocument::defaultEventHandler(Event* event)
}
}
}
-
+#endif
+
if (event->type() == eventNames().keydownEvent && event->isKeyboardEvent()) {
HTMLVideoElement* video = descendentVideoElement(targetNode);
if (!video)
diff --git a/Source/WebCore/html/MediaFragmentURIParser.cpp b/Source/WebCore/html/MediaFragmentURIParser.cpp
index 9842f60f7..de786ffd4 100644
--- a/Source/WebCore/html/MediaFragmentURIParser.cpp
+++ b/Source/WebCore/html/MediaFragmentURIParser.cpp
@@ -30,6 +30,7 @@
#include "MediaFragmentURIParser.h"
#include "HTMLElement.h"
+#include "MediaPlayer.h"
#include "ProcessingInstruction.h"
#include "SegmentedString.h"
#include "Text.h"
@@ -41,7 +42,6 @@ namespace WebCore {
const int secondsPerHour = 3600;
const int secondsPerMinute = 60;
-const double invalidMediaTime = -1;
const unsigned nptIdentiferLength = 4; // "npt:"
static String collectDigits(const LChar* input, unsigned length, unsigned& position)
@@ -72,21 +72,21 @@ static String collectFraction(const LChar* input, unsigned length, unsigned& pos
double MediaFragmentURIParser::invalidTimeValue()
{
- return invalidMediaTime;
+ return MediaPlayer::invalidTime();
}
MediaFragmentURIParser::MediaFragmentURIParser(const KURL& url)
: m_url(url)
, m_timeFormat(None)
- , m_startTime(invalidMediaTime)
- , m_endTime(invalidMediaTime)
+ , m_startTime(MediaPlayer::invalidTime())
+ , m_endTime(MediaPlayer::invalidTime())
{
}
double MediaFragmentURIParser::startTime()
{
if (!m_url.isValid())
- return invalidMediaTime;
+ return MediaPlayer::invalidTime();
if (m_timeFormat == None)
parseTimeFragment();
return m_startTime;
@@ -95,7 +95,7 @@ double MediaFragmentURIParser::startTime()
double MediaFragmentURIParser::endTime()
{
if (!m_url.isValid())
- return invalidMediaTime;
+ return MediaPlayer::invalidTime();
if (m_timeFormat == None)
parseTimeFragment();
return m_endTime;
@@ -184,8 +184,8 @@ void MediaFragmentURIParser::parseTimeFragment()
// in the same format. The format is specified by name, followed by a colon (:), with npt: being
// the default.
- double start = invalidMediaTime;
- double end = invalidMediaTime;
+ double start = MediaPlayer::invalidTime();
+ double end = MediaPlayer::invalidTime();
if (parseNPTFragment(fragment.second.characters8(), fragment.second.length(), start, end)) {
m_startTime = start;
m_endTime = end;
diff --git a/Source/WebCore/html/MonthInputType.cpp b/Source/WebCore/html/MonthInputType.cpp
index ebde3b205..c9bebb135 100644
--- a/Source/WebCore/html/MonthInputType.cpp
+++ b/Source/WebCore/html/MonthInputType.cpp
@@ -45,9 +45,9 @@ namespace WebCore {
using namespace HTMLNames;
-static const double monthDefaultStep = 1.0;
-static const double monthDefaultStepBase = 0.0;
-static const double monthStepScaleFactor = 1.0;
+static const int monthDefaultStep = 1;
+static const int monthDefaultStepBase = 0;
+static const int monthStepScaleFactor = 1;
PassOwnPtr<InputType> MonthInputType::create(HTMLInputElement* element)
{
@@ -82,7 +82,7 @@ String MonthInputType::serializeWithMilliseconds(double value) const
return serializeWithComponents(date);
}
-double MonthInputType::defaultValueForStepUp() const
+Decimal MonthInputType::defaultValueForStepUp() const
{
double current = currentTimeMS();
double utcOffset = calculateUTCOffset();
@@ -94,28 +94,28 @@ double MonthInputType::defaultValueForStepUp() const
date.setMillisecondsSinceEpochForMonth(current);
double months = date.monthsSinceEpoch();
ASSERT(isfinite(months));
- return months;
+ return Decimal::fromDouble(months);
}
StepRange MonthInputType::createStepRange(AnyStepHandling anyStepHandling) const
{
DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (monthDefaultStep, monthDefaultStepBase, monthStepScaleFactor, StepRange::ParsedStepValueShouldBeInteger));
- double stepBase = parseToDouble(element()->fastGetAttribute(minAttr), DateComponents::minimumMonth());
- double minimum = parseToDouble(element()->fastGetAttribute(minAttr), DateComponents::minimumMonth());
- double maximum = parseToDouble(element()->fastGetAttribute(maxAttr), DateComponents::maximumMonth());
- StepRange::DoubleWithDecimalPlacesOrMissing step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
+ const Decimal stepBase = parseToNumber(element()->fastGetAttribute(minAttr), Decimal::fromDouble(DateComponents::minimumMonth()));
+ const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), Decimal::fromDouble(DateComponents::minimumMonth()));
+ const Decimal maximum = parseToNumber(element()->fastGetAttribute(maxAttr), Decimal::fromDouble(DateComponents::maximumMonth()));
+ const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
return StepRange(stepBase, minimum, maximum, step, stepDescription);
}
-double MonthInputType::parseToDouble(const String& src, double defaultValue) const
+Decimal MonthInputType::parseToNumber(const String& src, const Decimal& defaultValue) const
{
DateComponents date;
if (!parseToDateComponents(src, &date))
return defaultValue;
double months = date.monthsSinceEpoch();
ASSERT(isfinite(months));
- return months;
+ return Decimal::fromDouble(months);
}
bool MonthInputType::parseToDateComponentsInternal(const UChar* characters, unsigned length, DateComponents* out) const
diff --git a/Source/WebCore/html/MonthInputType.h b/Source/WebCore/html/MonthInputType.h
index d07b01bcb..8f24fa785 100644
--- a/Source/WebCore/html/MonthInputType.h
+++ b/Source/WebCore/html/MonthInputType.h
@@ -47,8 +47,8 @@ private:
virtual DateComponents::Type dateType() const OVERRIDE;
virtual double valueAsDate() const OVERRIDE;
virtual String serializeWithMilliseconds(double) const OVERRIDE;
- virtual double parseToDouble(const String&, double) const OVERRIDE;
- virtual double defaultValueForStepUp() const OVERRIDE;
+ virtual Decimal parseToNumber(const String&, const Decimal&) const OVERRIDE;
+ virtual Decimal defaultValueForStepUp() const OVERRIDE;
virtual StepRange createStepRange(AnyStepHandling) const OVERRIDE;
virtual bool parseToDateComponentsInternal(const UChar*, unsigned length, DateComponents*) const OVERRIDE;
virtual bool setMillisecondToDateComponents(double, DateComponents*) const OVERRIDE;
diff --git a/Source/WebCore/html/NumberInputType.cpp b/Source/WebCore/html/NumberInputType.cpp
index cfdc7d497..eb157f10c 100644
--- a/Source/WebCore/html/NumberInputType.cpp
+++ b/Source/WebCore/html/NumberInputType.cpp
@@ -50,23 +50,48 @@ namespace WebCore {
using namespace HTMLNames;
using namespace std;
-static const double numberDefaultStep = 1.0;
-static const double numberDefaultStepBase = 0.0;
-static const double numberStepScaleFactor = 1.0;
+static const int numberDefaultStep = 1;
+static const int numberDefaultStepBase = 0;
+static const int numberStepScaleFactor = 1;
-static unsigned lengthBeforeDecimalPoint(double value)
+struct RealNumberRenderSize
{
- // If value is negative, '-' should be counted.
+ unsigned sizeBeforeDecimalPoint;
+ unsigned sizeAfteDecimalPoint;
- double absoluteValue = fabs(value);
- if (absoluteValue < 1)
- return value < 0 ? 2 : 1;
+ RealNumberRenderSize(unsigned before, unsigned after)
+ : sizeBeforeDecimalPoint(before)
+ , sizeAfteDecimalPoint(after)
+ {
+ }
+
+ RealNumberRenderSize max(const RealNumberRenderSize& other) const
+ {
+ return RealNumberRenderSize(
+ std::max(sizeBeforeDecimalPoint, other.sizeBeforeDecimalPoint),
+ std::max(sizeAfteDecimalPoint, other.sizeAfteDecimalPoint));
+ }
+};
- unsigned length = static_cast<unsigned>(log10(floor(absoluteValue))) + 1;
- if (value < 0)
- length += 1;
+static RealNumberRenderSize calculateRenderSize(const Decimal& value)
+{
+ ASSERT(value.isFinite());
+ const unsigned sizeOfDigits = String::number(value.value().coefficient()).length();
+ const unsigned sizeOfSign = value.isNegative() ? 1 : 0;
+ const int exponent = value.exponent();
+ if (exponent >= 0)
+ return RealNumberRenderSize(sizeOfSign + sizeOfDigits, 0);
+
+ const int sizeBeforeDecimalPoint = exponent + sizeOfDigits;
+ if (sizeBeforeDecimalPoint > 0) {
+ // In case of "123.456"
+ return RealNumberRenderSize(sizeOfSign + sizeBeforeDecimalPoint, sizeOfDigits - sizeBeforeDecimalPoint);
+ }
- return length;
+ // In case of "0.00012345"
+ const unsigned sizeOfZero = 1;
+ const unsigned numberOfZeroAfterDecimalPoint = -sizeBeforeDecimalPoint;
+ return RealNumberRenderSize(sizeOfSign + sizeOfZero , numberOfZeroAfterDecimalPoint + sizeOfDigits);
}
PassOwnPtr<InputType> NumberInputType::create(HTMLInputElement* element)
@@ -79,22 +104,39 @@ const AtomicString& NumberInputType::formControlType() const
return InputTypeNames::number();
}
-double NumberInputType::valueAsNumber() const
+double NumberInputType::valueAsDouble() const
{
- return parseToDouble(element()->value(), numeric_limits<double>::quiet_NaN());
+ return parseToDoubleForNumberType(element()->value());
+}
+
+void NumberInputType::setValueAsDouble(double newValue, TextFieldEventBehavior eventBehavior, ExceptionCode& ec) const
+{
+ // FIXME: We should use numeric_limits<double>::max for number input type.
+ const double floatMax = numeric_limits<float>::max();
+ if (newValue < -floatMax) {
+ ec = INVALID_STATE_ERR;
+ return;
+ }
+ if (newValue > floatMax) {
+ ec = INVALID_STATE_ERR;
+ return;
+ }
+ element()->setValue(serializeForNumberType(newValue), eventBehavior);
}
-void NumberInputType::setValueAsNumber(double newValue, TextFieldEventBehavior eventBehavior, ExceptionCode& ec) const
+void NumberInputType::setValueAsDecimal(const Decimal& newValue, TextFieldEventBehavior eventBehavior, ExceptionCode& ec) const
{
- if (newValue < -numeric_limits<float>::max()) {
+ // FIXME: We should use numeric_limits<double>::max for number input type.
+ const Decimal floatMax = Decimal::fromDouble(numeric_limits<float>::max());
+ if (newValue < -floatMax) {
ec = INVALID_STATE_ERR;
return;
}
- if (newValue > numeric_limits<float>::max()) {
+ if (newValue > floatMax) {
ec = INVALID_STATE_ERR;
return;
}
- element()->setValue(serialize(newValue), eventBehavior);
+ element()->setValue(serializeForNumberType(newValue), eventBehavior);
}
bool NumberInputType::typeMismatchFor(const String& value) const
@@ -111,14 +153,12 @@ bool NumberInputType::typeMismatch() const
StepRange NumberInputType::createStepRange(AnyStepHandling anyStepHandling) const
{
DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (numberDefaultStep, numberDefaultStepBase, numberStepScaleFactor));
-
- unsigned stepBaseDecimalPlaces;
- double stepBaseValue = parseToDoubleWithDecimalPlaces(element()->fastGetAttribute(minAttr), numberDefaultStepBase, &stepBaseDecimalPlaces);
- StepRange::DoubleWithDecimalPlaces stepBase(stepBaseValue, min(stepBaseDecimalPlaces, 16u));
- double minimum = parseToDouble(element()->fastGetAttribute(minAttr), -numeric_limits<float>::max());
- double maximum = parseToDouble(element()->fastGetAttribute(maxAttr), numeric_limits<float>::max());
-
- StepRange::DoubleWithDecimalPlacesOrMissing step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
+ const Decimal stepBase = parseToDecimalForNumberType(element()->fastGetAttribute(minAttr), numberDefaultStepBase);
+ // FIXME: We should use numeric_limits<double>::max for number input type.
+ const Decimal floatMax = Decimal::fromDouble(numeric_limits<float>::max());
+ const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), -floatMax);
+ const Decimal maximum = parseToNumber(element()->fastGetAttribute(maxAttr), floatMax);
+ const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
return StepRange(stepBase, minimum, maximum, step, stepDescription);
}
@@ -126,46 +166,25 @@ bool NumberInputType::sizeShouldIncludeDecoration(int defaultSize, int& preferre
{
preferredSize = defaultSize;
- unsigned minValueDecimalPlaces;
- String minValue = element()->fastGetAttribute(minAttr);
- double minValueDouble = parseToDoubleForNumberTypeWithDecimalPlaces(minValue, &minValueDecimalPlaces);
- if (!isfinite(minValueDouble))
+ const String stepString = element()->fastGetAttribute(stepAttr);
+ if (equalIgnoringCase(stepString, "any"))
return false;
- unsigned maxValueDecimalPlaces;
- String maxValue = element()->fastGetAttribute(maxAttr);
- double maxValueDouble = parseToDoubleForNumberTypeWithDecimalPlaces(maxValue, &maxValueDecimalPlaces);
- if (!isfinite(maxValueDouble))
+ const Decimal minimum = parseToDecimalForNumberType(element()->fastGetAttribute(minAttr));
+ if (!minimum.isFinite())
return false;
- if (maxValueDouble < minValueDouble) {
- maxValueDouble = minValueDouble;
- maxValueDecimalPlaces = minValueDecimalPlaces;
- }
-
- String stepValue = element()->fastGetAttribute(stepAttr);
- if (equalIgnoringCase(stepValue, "any"))
+ const Decimal maximum = parseToDecimalForNumberType(element()->fastGetAttribute(maxAttr));
+ if (!maximum.isFinite())
return false;
- unsigned stepValueDecimalPlaces;
- double stepValueDouble = parseToDoubleForNumberTypeWithDecimalPlaces(stepValue, &stepValueDecimalPlaces);
- if (!isfinite(stepValueDouble)) {
- stepValueDouble = 1;
- stepValueDecimalPlaces = 0;
- }
- unsigned length = lengthBeforeDecimalPoint(minValueDouble);
- length = max(length, lengthBeforeDecimalPoint(maxValueDouble));
- length = max(length, lengthBeforeDecimalPoint(stepValueDouble));
+ const Decimal step = parseToDecimalForNumberType(stepString, 1);
+ ASSERT(step.isFinite());
- unsigned lengthAfterDecimalPoint = minValueDecimalPlaces;
- lengthAfterDecimalPoint = max(lengthAfterDecimalPoint, maxValueDecimalPlaces);
- lengthAfterDecimalPoint = max(lengthAfterDecimalPoint, stepValueDecimalPlaces);
+ RealNumberRenderSize size = calculateRenderSize(minimum).max(calculateRenderSize(maximum).max(calculateRenderSize(step)));
- // '.' should be counted if the value has decimal places.
- if (lengthAfterDecimalPoint > 0)
- length += lengthAfterDecimalPoint + 1;
+ preferredSize = size.sizeBeforeDecimalPoint + size.sizeAfteDecimalPoint + (size.sizeAfteDecimalPoint ? 1 : 0);
- preferredSize = length;
return true;
}
@@ -186,19 +205,14 @@ void NumberInputType::handleWheelEvent(WheelEvent* event)
handleWheelEventForSpinButton(event);
}
-double NumberInputType::parseToDouble(const String& src, double defaultValue) const
-{
- return parseToDoubleForNumberType(src, defaultValue);
-}
-
-double NumberInputType::parseToDoubleWithDecimalPlaces(const String& src, double defaultValue, unsigned *decimalPlaces) const
+Decimal NumberInputType::parseToNumber(const String& src, const Decimal& defaultValue) const
{
- return parseToDoubleForNumberTypeWithDecimalPlaces(src, decimalPlaces, defaultValue);
+ return parseToDecimalForNumberType(src, defaultValue);
}
-String NumberInputType::serialize(double value) const
+String NumberInputType::serialize(const Decimal& value) const
{
- if (!isfinite(value))
+ if (!value.isFinite())
return String();
return serializeForNumberType(value);
}
@@ -252,7 +266,7 @@ String NumberInputType::convertFromVisibleValue(const String& visibleValue) cons
bool NumberInputType::isAcceptableValue(const String& proposedValue)
{
String standardValue = convertFromVisibleValue(proposedValue);
- return standardValue.isEmpty() || parseToDoubleForNumberType(standardValue, 0);
+ return standardValue.isEmpty() || isfinite(parseToDoubleForNumberType(standardValue));
}
String NumberInputType::sanitizeValue(const String& proposedValue) const
diff --git a/Source/WebCore/html/NumberInputType.h b/Source/WebCore/html/NumberInputType.h
index ce4177bfc..fe16e5fa0 100644
--- a/Source/WebCore/html/NumberInputType.h
+++ b/Source/WebCore/html/NumberInputType.h
@@ -42,8 +42,9 @@ public:
private:
NumberInputType(HTMLInputElement* element) : TextFieldInputType(element) { }
virtual const AtomicString& formControlType() const OVERRIDE;
- virtual double valueAsNumber() const OVERRIDE;
- virtual void setValueAsNumber(double, TextFieldEventBehavior, ExceptionCode&) const OVERRIDE;
+ virtual double valueAsDouble() const OVERRIDE;
+ virtual void setValueAsDouble(double, TextFieldEventBehavior, ExceptionCode&) const OVERRIDE;
+ virtual void setValueAsDecimal(const Decimal&, TextFieldEventBehavior, ExceptionCode&) const OVERRIDE;
virtual bool typeMismatchFor(const String&) const OVERRIDE;
virtual bool typeMismatch() const OVERRIDE;
virtual bool sizeShouldIncludeDecoration(int defaultSize, int& preferredSize) const OVERRIDE;
@@ -51,9 +52,8 @@ private:
virtual StepRange createStepRange(AnyStepHandling) const OVERRIDE;
virtual void handleKeydownEvent(KeyboardEvent*) OVERRIDE;
virtual void handleWheelEvent(WheelEvent*) OVERRIDE;
- virtual double parseToDouble(const String&, double) const OVERRIDE;
- virtual double parseToDoubleWithDecimalPlaces(const String&, double, unsigned*) const OVERRIDE;
- virtual String serialize(double) const OVERRIDE;
+ virtual Decimal parseToNumber(const String&, const Decimal&) const OVERRIDE;
+ virtual String serialize(const Decimal&) const OVERRIDE;
virtual void handleBlurEvent() OVERRIDE;
virtual String localizeValue(const String&) const OVERRIDE;
virtual String visibleValue() const OVERRIDE;
diff --git a/Source/WebCore/html/PasswordInputType.cpp b/Source/WebCore/html/PasswordInputType.cpp
index 88bb842b6..10c2d9f9e 100644
--- a/Source/WebCore/html/PasswordInputType.cpp
+++ b/Source/WebCore/html/PasswordInputType.cpp
@@ -32,6 +32,7 @@
#include "config.h"
#include "PasswordInputType.h"
+#include "FormController.h"
#include "HTMLInputElement.h"
#include <wtf/Assertions.h>
#include <wtf/PassOwnPtr.h>
@@ -48,13 +49,13 @@ const AtomicString& PasswordInputType::formControlType() const
return InputTypeNames::password();
}
-bool PasswordInputType::saveFormControlState(String&) const
+FormControlState PasswordInputType::saveFormControlState() const
{
// Should never save/restore password fields.
- return false;
+ return FormControlState();
}
-void PasswordInputType::restoreFormControlState(const String&)
+void PasswordInputType::restoreFormControlState(const FormControlState&)
{
// Should never save/restore password fields.
ASSERT_NOT_REACHED();
diff --git a/Source/WebCore/html/PasswordInputType.h b/Source/WebCore/html/PasswordInputType.h
index 5267dde63..83012cf9c 100644
--- a/Source/WebCore/html/PasswordInputType.h
+++ b/Source/WebCore/html/PasswordInputType.h
@@ -42,8 +42,8 @@ public:
private:
PasswordInputType(HTMLInputElement* element) : BaseTextInputType(element) { }
virtual const AtomicString& formControlType() const OVERRIDE;
- virtual bool saveFormControlState(String&) const OVERRIDE;
- virtual void restoreFormControlState(const String&) OVERRIDE;
+ virtual FormControlState saveFormControlState() const OVERRIDE;
+ virtual void restoreFormControlState(const FormControlState&) OVERRIDE;
virtual bool shouldUseInputMethod() const OVERRIDE;
virtual bool shouldResetOnDocumentActivation() OVERRIDE;
virtual bool shouldRespectListAttribute() OVERRIDE;
diff --git a/Source/WebCore/html/RadioInputType.cpp b/Source/WebCore/html/RadioInputType.cpp
index 155be891d..2c16b1a16 100644
--- a/Source/WebCore/html/RadioInputType.cpp
+++ b/Source/WebCore/html/RadioInputType.cpp
@@ -114,8 +114,11 @@ void RadioInputType::handleKeyupEvent(KeyboardEvent* event)
dispatchSimulatedClickIfActive(event);
}
-bool RadioInputType::isKeyboardFocusable() const
+bool RadioInputType::isKeyboardFocusable(KeyboardEvent* event) const
{
+ if (!InputType::isKeyboardFocusable(event))
+ return false;
+
// When using Spatial Navigation, every radio button should be focusable.
if (isSpatialNavigationEnabled(element()->document()->frame()))
return true;
diff --git a/Source/WebCore/html/RadioInputType.h b/Source/WebCore/html/RadioInputType.h
index 7790b504c..24e27bc57 100644
--- a/Source/WebCore/html/RadioInputType.h
+++ b/Source/WebCore/html/RadioInputType.h
@@ -47,7 +47,7 @@ private:
virtual void handleClickEvent(MouseEvent*) OVERRIDE;
virtual void handleKeydownEvent(KeyboardEvent*) OVERRIDE;
virtual void handleKeyupEvent(KeyboardEvent*) OVERRIDE;
- virtual bool isKeyboardFocusable() const OVERRIDE;
+ virtual bool isKeyboardFocusable(KeyboardEvent*) const OVERRIDE;
virtual bool shouldSendChangeEventAfterCheckedChanged() OVERRIDE;
virtual PassOwnPtr<ClickHandlingState> willDispatchClick() OVERRIDE;
virtual void didDispatchClick(Event*, const ClickHandlingState&) OVERRIDE;
diff --git a/Source/WebCore/html/RadioNodeList.cpp b/Source/WebCore/html/RadioNodeList.cpp
index 40929bca3..3c3a618ab 100644
--- a/Source/WebCore/html/RadioNodeList.cpp
+++ b/Source/WebCore/html/RadioNodeList.cpp
@@ -36,8 +36,8 @@ namespace WebCore {
using namespace HTMLNames;
-RadioNodeList::RadioNodeList(const AtomicString& name, Element* baseElement)
- : DynamicSubtreeNodeList(baseElement->hasTagName(formTag) ? static_cast<Node*>(baseElement->document()) : baseElement)
+RadioNodeList::RadioNodeList(Element* baseElement, const AtomicString& name)
+ : DynamicSubtreeNodeList(baseElement, baseElement->hasTagName(formTag) ? RootedAtDocument : RootedAtNode)
, m_name(name)
, m_baseElement(baseElement)
{
diff --git a/Source/WebCore/html/RadioNodeList.h b/Source/WebCore/html/RadioNodeList.h
index 7782e4802..46065b383 100644
--- a/Source/WebCore/html/RadioNodeList.h
+++ b/Source/WebCore/html/RadioNodeList.h
@@ -36,9 +36,9 @@ namespace WebCore {
class RadioNodeList : public DynamicSubtreeNodeList {
public:
- static PassRefPtr<RadioNodeList> create(const AtomicString& name, Element* baseElement)
+ static PassRefPtr<RadioNodeList> create(Element* baseElement, const AtomicString& name)
{
- return adoptRef(new RadioNodeList(name, baseElement));
+ return adoptRef(new RadioNodeList(baseElement, name));
}
~RadioNodeList();
@@ -50,7 +50,7 @@ protected:
virtual bool nodeMatches(Element*) const;
private:
- RadioNodeList(const AtomicString& name, Element*);
+ RadioNodeList(Element*, const AtomicString& name);
bool checkElementMatchesRadioNodeListFilter(Element*) const;
AtomicString m_name;
diff --git a/Source/WebCore/html/RangeInputType.cpp b/Source/WebCore/html/RangeInputType.cpp
index b417dc320..fd11cbaa7 100644
--- a/Source/WebCore/html/RangeInputType.cpp
+++ b/Source/WebCore/html/RangeInputType.cpp
@@ -54,11 +54,16 @@ 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 rangeDefaultStepBase = 0.0;
-static const double rangeStepScaleFactor = 1.0;
+static const int rangeDefaultMinimum = 0;
+static const int rangeDefaultMaximum = 100;
+static const int rangeDefaultStep = 1;
+static const int rangeDefaultStepBase = 0;
+static const int rangeStepScaleFactor = 1;
+
+static Decimal ensureMaximum(const Decimal& proposedValue, const Decimal& minimum, const Decimal& fallbackValue)
+{
+ return proposedValue >= minimum ? proposedValue : std::max(minimum, fallbackValue);
+}
PassOwnPtr<InputType> RangeInputType::create(HTMLInputElement* element)
{
@@ -75,12 +80,12 @@ const AtomicString& RangeInputType::formControlType() const
return InputTypeNames::range();
}
-double RangeInputType::valueAsNumber() const
+double RangeInputType::valueAsDouble() const
{
- return parseToDouble(element()->value(), numeric_limits<double>::quiet_NaN());
+ return parseToDoubleForNumberType(element()->value());
}
-void RangeInputType::setValueAsNumber(double newValue, TextFieldEventBehavior eventBehavior, ExceptionCode&) const
+void RangeInputType::setValueAsDecimal(const Decimal& newValue, TextFieldEventBehavior eventBehavior, ExceptionCode&) const
{
element()->setValue(serialize(newValue), eventBehavior);
}
@@ -94,18 +99,16 @@ StepRange RangeInputType::createStepRange(AnyStepHandling anyStepHandling) const
{
DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (rangeDefaultStep, rangeDefaultStepBase, rangeStepScaleFactor));
- double minimum = parseToDouble(element()->fastGetAttribute(minAttr), rangeDefaultMinimum);
- double maximum = parseToDouble(element()->fastGetAttribute(maxAttr), rangeDefaultMaximum);
- if (maximum < minimum)
- maximum = max(minimum, rangeDefaultMaximum);
+ const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), rangeDefaultMinimum);
+ const Decimal maximum = ensureMaximum(parseToNumber(element()->fastGetAttribute(maxAttr), rangeDefaultMaximum), minimum, rangeDefaultMaximum);
const AtomicString& precisionValue = element()->fastGetAttribute(precisionAttr);
if (!precisionValue.isNull()) {
- StepRange::DoubleWithDecimalPlacesOrMissing step(1, !equalIgnoringCase(precisionValue, "float"));
+ const Decimal step = equalIgnoringCase(precisionValue, "float") ? Decimal::nan() : 1;
return StepRange(minimum, minimum, maximum, step, stepDescription);
}
- StepRange::DoubleWithDecimalPlacesOrMissing step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
+ const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
return StepRange(minimum, minimum, maximum, step, stepDescription);
}
@@ -138,25 +141,16 @@ void RangeInputType::handleKeydownEvent(KeyboardEvent* event)
const String& key = event->keyIdentifier();
- double current = parseToDouble(element()->value(), numeric_limits<double>::quiet_NaN());
- ASSERT(isfinite(current));
+ const Decimal current = parseToNumberOrNaN(element()->value());
+ ASSERT(current.isFinite());
StepRange stepRange(createStepRange(RejectAny));
- double step, bigStep;
- if (equalIgnoringCase(element()->fastGetAttribute(stepAttr), "any")) {
- // FIXME: We can't use stepUp() for the step value "any". So, we increase
- // or decrease the value by 1/100 of the value range. Is it reasonable?
- step = (stepRange.maximum() - stepRange.minimum()) / 100;
- bigStep = step * 10;
- } else {
- if (!element()->getAllowedValueStep(&step))
- ASSERT_NOT_REACHED();
-
- bigStep = (stepRange.maximum() - stepRange.minimum()) / 10;
- if (bigStep < step)
- bigStep = step;
- }
+
+ // FIXME: We can't use stepUp() for the step value "any". So, we increase
+ // or decrease the value by 1/100 of the value range. Is it reasonable?
+ const Decimal step = equalIgnoringCase(element()->fastGetAttribute(stepAttr), "any") ? (stepRange.maximum() - stepRange.minimum()) / 100 : stepRange.step();
+ const Decimal bigStep = max((stepRange.maximum() - stepRange.minimum()) / 10, step);
bool isVertical = false;
if (element()->renderer()) {
@@ -164,7 +158,7 @@ void RangeInputType::handleKeydownEvent(KeyboardEvent* event)
isVertical = part == SliderVerticalPart || part == MediaVolumeSliderPart;
}
- double newValue;
+ Decimal newValue;
if (key == "Up")
newValue = current + step;
else if (key == "Down")
@@ -189,7 +183,7 @@ void RangeInputType::handleKeydownEvent(KeyboardEvent* event)
if (newValue != current) {
ExceptionCode ec;
TextFieldEventBehavior eventBehavior = DispatchChangeEvent;
- setValueAsNumber(newValue, eventBehavior, ec);
+ setValueAsDecimal(newValue, eventBehavior, ec);
if (AXObjectCache::accessibilityEnabled())
element()->document()->axObjectCache()->postNotification(element()->renderer(), AXObjectCache::AXValueChanged, true);
@@ -219,14 +213,14 @@ RenderObject* RangeInputType::createRenderer(RenderArena* arena, RenderStyle*) c
return new (arena) RenderSlider(element());
}
-double RangeInputType::parseToDouble(const String& src, double defaultValue) const
+Decimal RangeInputType::parseToNumber(const String& src, const Decimal& defaultValue) const
{
- return parseToDoubleForNumberType(src, defaultValue);
+ return parseToDecimalForNumberType(src, defaultValue);
}
-String RangeInputType::serialize(double value) const
+String RangeInputType::serialize(const Decimal& value) const
{
- if (!isfinite(value))
+ if (!value.isFinite())
return String();
return serializeForNumberType(value);
}
@@ -269,8 +263,8 @@ String RangeInputType::fallbackValue() const
String RangeInputType::sanitizeValue(const String& proposedValue) const
{
StepRange stepRange(createStepRange(RejectAny));
- double proposedDoubleValue = parseToDouble(proposedValue, stepRange.defaultValue());
- return serializeForNumberType(stepRange.clampValue(proposedDoubleValue));
+ const Decimal proposedNumericValue = parseToNumber(proposedValue, stepRange.defaultValue());
+ return serializeForNumberType(stepRange.clampValue(proposedNumericValue));
}
bool RangeInputType::shouldRespectListAttribute()
diff --git a/Source/WebCore/html/RangeInputType.h b/Source/WebCore/html/RangeInputType.h
index 45fb4afa3..ff8f4028f 100644
--- a/Source/WebCore/html/RangeInputType.h
+++ b/Source/WebCore/html/RangeInputType.h
@@ -45,8 +45,8 @@ private:
RangeInputType(HTMLInputElement* element) : InputType(element) { }
virtual bool isRangeControl() const OVERRIDE;
virtual const AtomicString& formControlType() const OVERRIDE;
- virtual double valueAsNumber() const OVERRIDE;
- virtual void setValueAsNumber(double, TextFieldEventBehavior, ExceptionCode&) const OVERRIDE;
+ virtual double valueAsDouble() const OVERRIDE;
+ virtual void setValueAsDecimal(const Decimal&, TextFieldEventBehavior, ExceptionCode&) const OVERRIDE;
virtual bool supportsRequired() const OVERRIDE;
virtual StepRange createStepRange(AnyStepHandling) const OVERRIDE;
virtual bool isSteppable() const OVERRIDE;
@@ -54,8 +54,8 @@ private:
virtual void handleKeydownEvent(KeyboardEvent*) OVERRIDE;
virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) const OVERRIDE;
virtual void createShadowSubtree() OVERRIDE;
- virtual double parseToDouble(const String&, double) const OVERRIDE;
- virtual String serialize(double) const OVERRIDE;
+ virtual Decimal parseToNumber(const String&, const Decimal&) const OVERRIDE;
+ virtual String serialize(const Decimal&) const OVERRIDE;
virtual void accessKeyAction(bool sendMouseEvents) OVERRIDE;
virtual void minOrMaxAttributeChanged() OVERRIDE;
virtual void setValue(const String&, bool valueChanged, TextFieldEventBehavior) OVERRIDE;
diff --git a/Source/WebCore/html/SearchInputType.cpp b/Source/WebCore/html/SearchInputType.cpp
index 6f500daf3..958878ced 100644
--- a/Source/WebCore/html/SearchInputType.cpp
+++ b/Source/WebCore/html/SearchInputType.cpp
@@ -32,14 +32,17 @@
#include "SearchInputType.h"
#include "HTMLInputElement.h"
+#include "HTMLNames.h"
#include "KeyboardEvent.h"
-#include "RenderTextControlSingleLine.h"
+#include "RenderSearchField.h"
#include "ShadowRoot.h"
#include "TextControlInnerElements.h"
#include <wtf/PassOwnPtr.h>
namespace WebCore {
+using namespace HTMLNames;
+
inline SearchInputType::SearchInputType(HTMLInputElement* element)
: BaseTextInputType(element)
, m_searchEventTimer(this, &SearchInputType::searchEventTimerFired)
@@ -51,6 +54,17 @@ PassOwnPtr<InputType> SearchInputType::create(HTMLInputElement* element)
return adoptPtr(new SearchInputType(element));
}
+void SearchInputType::addSearchResult()
+{
+ if (RenderObject* renderer = element()->renderer())
+ toRenderSearchField(renderer)->addSearchResult();
+}
+
+RenderObject* SearchInputType::createRenderer(RenderArena* arena, RenderStyle*) const
+{
+ return new (arena) RenderSearchField(element());
+}
+
const AtomicString& SearchInputType::formControlType() const
{
return InputTypeNames::search();
@@ -151,5 +165,19 @@ void SearchInputType::searchEventTimerFired(Timer<SearchInputType>*)
element()->onSearch();
}
+bool SearchInputType::searchEventsShouldBeDispatched() const
+{
+ return element()->hasAttribute(incrementalAttr);
+}
+
+void SearchInputType::subtreeHasChanged()
+{
+ if (m_cancelButton.get())
+ toRenderSearchField(element()->renderer())->updateCancelButtonVisibility();
+
+ // If the incremental attribute is set, then dispatch the search event
+ if (searchEventsShouldBeDispatched())
+ startSearchEventTimer();
+}
} // namespace WebCore
diff --git a/Source/WebCore/html/SearchInputType.h b/Source/WebCore/html/SearchInputType.h
index ab19103af..ece35a259 100644
--- a/Source/WebCore/html/SearchInputType.h
+++ b/Source/WebCore/html/SearchInputType.h
@@ -43,11 +43,12 @@ class SearchInputType : public BaseTextInputType {
public:
static PassOwnPtr<InputType> create(HTMLInputElement*);
- void startSearchEventTimer();
void stopSearchEventTimer();
private:
SearchInputType(HTMLInputElement*);
+ virtual void addSearchResult() OVERRIDE;
+ virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) const OVERRIDE;
virtual const AtomicString& formControlType() const OVERRIDE;
virtual bool shouldRespectSpeechAttribute() OVERRIDE;
virtual bool isSearchField() const OVERRIDE;
@@ -57,8 +58,11 @@ private:
virtual HTMLElement* resultsButtonElement() const OVERRIDE;
virtual HTMLElement* cancelButtonElement() const OVERRIDE;
virtual void handleKeydownEvent(KeyboardEvent*) OVERRIDE;
+ virtual void subtreeHasChanged();
void searchEventTimerFired(Timer<SearchInputType>*);
+ bool searchEventsShouldBeDispatched() const;
+ void startSearchEventTimer();
RefPtr<HTMLElement> m_resultsButton;
RefPtr<HTMLElement> m_cancelButton;
diff --git a/Source/WebCore/html/StepRange.cpp b/Source/WebCore/html/StepRange.cpp
index 9b9b7dcc9..c7c88fcf9 100644
--- a/Source/WebCore/html/StepRange.cpp
+++ b/Source/WebCore/html/StepRange.cpp
@@ -37,8 +37,6 @@ StepRange::StepRange()
, m_minimum(0)
, m_step(1)
, m_stepBase(0)
- , m_stepBaseDecimalPlaces(0)
- , m_stepDecimalPlaces(0)
, m_hasStep(false)
{
}
@@ -49,126 +47,122 @@ StepRange::StepRange(const StepRange& stepRange)
, m_step(stepRange.m_step)
, m_stepBase(stepRange.m_stepBase)
, m_stepDescription(stepRange.m_stepDescription)
- , m_stepBaseDecimalPlaces(stepRange.m_stepBaseDecimalPlaces)
- , m_stepDecimalPlaces(stepRange.m_stepDecimalPlaces)
, m_hasStep(stepRange.m_hasStep)
{
}
-StepRange::StepRange(const DoubleWithDecimalPlaces& stepBase, double minimum, double maximum, const DoubleWithDecimalPlacesOrMissing& step, const StepDescription& stepDescription)
+StepRange::StepRange(const Decimal& stepBase, const Decimal& minimum, const Decimal& maximum, const Decimal& step, const StepDescription& stepDescription)
: m_maximum(maximum)
, m_minimum(minimum)
- , m_step(step.value.value)
- , m_stepBase(stepBase.value)
+ , m_step(step.isFinite() ? step : 1)
+ , m_stepBase(stepBase.isFinite() ? stepBase : 1)
, m_stepDescription(stepDescription)
- , m_stepBaseDecimalPlaces(stepBase.decimalPlaces)
- , m_stepDecimalPlaces(step.value.decimalPlaces)
- , m_hasStep(step.hasValue)
+ , m_hasStep(step.isFinite())
{
- ASSERT(isfinite(m_maximum));
- ASSERT(isfinite(m_minimum));
- ASSERT(isfinite(m_step));
- ASSERT(isfinite(m_stepBase));
+ ASSERT(m_maximum.isFinite());
+ ASSERT(m_minimum.isFinite());
+ ASSERT(m_step.isFinite());
+ ASSERT(m_stepBase.isFinite());
}
-double StepRange::acceptableError() const
+Decimal StepRange::acceptableError() const
{
- return m_step / pow(2.0, FLT_MANT_DIG);
+ // FIXME: We should use DBL_MANT_DIG instead of FLT_MANT_DIG regarding to HTML5 specification.
+ DEFINE_STATIC_LOCAL(const Decimal, twoPowerOfFloatMantissaBits, (Decimal::Positive, 0, UINT64_C(1) << FLT_MANT_DIG));
+ return m_step / twoPowerOfFloatMantissaBits;
}
-double StepRange::alignValueForStep(double currentValue, unsigned currentDecimalPlaces, double newValue) const
+Decimal StepRange::alignValueForStep(const Decimal& currentValue, const Decimal& newValue) const
{
- if (newValue >= pow(10.0, 21.0))
+ DEFINE_STATIC_LOCAL(const Decimal, tenPowerOf21, (Decimal::Positive, 21, 1));
+ if (newValue >= tenPowerOf21)
return newValue;
- if (stepMismatch(currentValue)) {
- double scale = pow(10.0, static_cast<double>(max(m_stepDecimalPlaces, currentDecimalPlaces)));
- newValue = round(newValue * scale) / scale;
- } else {
- double scale = pow(10.0, static_cast<double>(max(m_stepDecimalPlaces, m_stepBaseDecimalPlaces)));
- newValue = round((m_stepBase + round((newValue - m_stepBase) / m_step) * m_step) * scale) / scale;
- }
-
- return newValue;
+ return stepMismatch(currentValue) ? newValue : roundByStep(newValue, m_stepBase);
}
-double StepRange::clampValue(double value) const
+
+Decimal StepRange::clampValue(const Decimal& value) const
{
- double clampedValue = max(m_minimum, min(value, m_maximum));
+ const Decimal inRangeValue = max(m_minimum, min(value, m_maximum));
if (!m_hasStep)
- return clampedValue;
- // Rounds clampedValue to minimum + N * step.
- clampedValue = m_minimum + round((clampedValue - m_minimum) / m_step) * m_step;
- if (clampedValue > m_maximum)
- clampedValue -= m_step;
+ return inRangeValue;
+ // Rounds inRangeValue to minimum + N * step.
+ const Decimal roundedValue = roundByStep(inRangeValue, m_minimum);
+ const Decimal clampedValue = roundedValue > m_maximum ? roundedValue - m_step : roundedValue;
ASSERT(clampedValue >= m_minimum);
ASSERT(clampedValue <= m_maximum);
return clampedValue;
}
-StepRange::DoubleWithDecimalPlacesOrMissing StepRange::parseStep(AnyStepHandling anyStepHandling, const StepDescription& stepDescription, const String& stepString)
+Decimal StepRange::parseStep(AnyStepHandling anyStepHandling, const StepDescription& stepDescription, const String& stepString)
{
if (stepString.isEmpty())
- return DoubleWithDecimalPlacesOrMissing(stepDescription.defaultValue());
+ return stepDescription.defaultValue();
if (equalIgnoringCase(stepString, "any")) {
switch (anyStepHandling) {
case RejectAny:
- return DoubleWithDecimalPlacesOrMissing(DoubleWithDecimalPlaces(1), false);
+ return Decimal::nan();
case AnyIsDefaultStep:
- return DoubleWithDecimalPlacesOrMissing(stepDescription.defaultValue());
+ return stepDescription.defaultValue();
default:
ASSERT_NOT_REACHED();
}
}
- DoubleWithDecimalPlacesOrMissing step(0);
- step.value.value = parseToDoubleForNumberTypeWithDecimalPlaces(stepString, &step.value.decimalPlaces);
- if (!isfinite(step.value.value) || step.value.value <= 0.0)
- return DoubleWithDecimalPlacesOrMissing(stepDescription.defaultValue());
+ Decimal step = parseToDecimalForNumberType(stepString);
+ if (!step.isFinite() || step <= 0)
+ return stepDescription.defaultValue();
switch (stepDescription.stepValueShouldBe) {
case StepValueShouldBeReal:
- step.value.value *= stepDescription.stepScaleFactor;
+ step *= stepDescription.stepScaleFactor;
break;
case ParsedStepValueShouldBeInteger:
// For date, month, and week, the parsed value should be an integer for some types.
- step.value.value = max(round(step.value.value), 1.0);
- step.value.value *= stepDescription.stepScaleFactor;
+ step = max(step.round(), Decimal(1));
+ step *= stepDescription.stepScaleFactor;
break;
case ScaledStepValueShouldBeInteger:
// For datetime, datetime-local, time, the result should be an integer.
- step.value.value *= stepDescription.stepScaleFactor;
- step.value.value = max(round(step.value.value), 1.0);
+ step *= stepDescription.stepScaleFactor;
+ step = max(step.round(), Decimal(1));
break;
default:
ASSERT_NOT_REACHED();
}
- ASSERT(step.value.value > 0);
+ ASSERT(step > 0);
return step;
}
-bool StepRange::stepMismatch(double doubleValue) const
+Decimal StepRange::roundByStep(const Decimal& value, const Decimal& base) const
+{
+ return base + ((value - base) / m_step).round() * m_step;
+}
+
+bool StepRange::stepMismatch(const Decimal& valueForCheck) const
{
if (!m_hasStep)
return false;
- if (!isfinite(doubleValue))
+ if (!valueForCheck.isFinite())
return false;
- doubleValue = fabs(doubleValue - m_stepBase);
- if (isinf(doubleValue))
+ const Decimal value = (valueForCheck - m_stepBase).abs();
+ if (!value.isFinite())
return false;
- // double's fractional part size is DBL_MAN_DIG-bit. If the current value
+ // Decimal's fractional part size is DBL_MAN_DIG-bit. If the current value
// is greater than step*2^DBL_MANT_DIG, the following computation for
// remainder makes no sense.
- if (doubleValue / pow(2.0, DBL_MANT_DIG) > m_step)
+ DEFINE_STATIC_LOCAL(const Decimal, twoPowerOfDoubleMantissaBits, (Decimal::Positive, 0, UINT64_C(1) << DBL_MANT_DIG));
+ if (value / twoPowerOfDoubleMantissaBits > m_step)
return false;
// The computation follows HTML5 4.10.7.2.10 `The step attribute' :
// ... that number subtracted from the step base is not an integral multiple
// of the allowed value step, the element is suffering from a step mismatch.
- double remainder = fabs(doubleValue - m_step * round(doubleValue / m_step));
+ const Decimal remainder = (value - m_step * (value / m_step).round()).abs();
// Accepts erros in lower fractional part which IEEE 754 single-precision
// can't represent.
- double computedAcceptableError = acceptableError();
+ const Decimal computedAcceptableError = acceptableError();
return computedAcceptableError < remainder && remainder < (m_step - computedAcceptableError);
}
diff --git a/Source/WebCore/html/StepRange.h b/Source/WebCore/html/StepRange.h
index 0adbfd857..63ab7561a 100644
--- a/Source/WebCore/html/StepRange.h
+++ b/Source/WebCore/html/StepRange.h
@@ -21,6 +21,7 @@
#ifndef StepRange_h
#define StepRange_h
+#include "Decimal.h"
#include <wtf/Forward.h>
#include <wtf/Noncopyable.h>
@@ -32,28 +33,6 @@ enum AnyStepHandling { RejectAny, AnyIsDefaultStep };
class StepRange {
public:
- struct DoubleWithDecimalPlaces {
- unsigned decimalPlaces;
- double value;
-
- DoubleWithDecimalPlaces(double value = 0, unsigned decimalPlaces = 0)
- : decimalPlaces(decimalPlaces)
- , value(value)
- {
- }
- };
-
- struct DoubleWithDecimalPlacesOrMissing {
- bool hasValue;
- DoubleWithDecimalPlaces value;
-
- DoubleWithDecimalPlacesOrMissing(DoubleWithDecimalPlaces value, bool hasValue = true)
- : hasValue(hasValue)
- , value(value)
- {
- }
- };
-
enum StepValueShouldBe {
StepValueShouldBeReal,
ParsedStepValueShouldBeInteger,
@@ -82,7 +61,7 @@ public:
{
}
- double defaultValue() const
+ Decimal defaultValue() const
{
return defaultStep * stepScaleFactor;
}
@@ -90,29 +69,27 @@ public:
StepRange();
StepRange(const StepRange&);
- StepRange(const DoubleWithDecimalPlaces& stepBase, double minimum, double maximum, const DoubleWithDecimalPlacesOrMissing& step, const StepDescription&);
- double acceptableError() const;
- double alignValueForStep(double currentValue, unsigned currentDecimalPlaces, double newValue) const;
- double clampValue(double value) const;
+ StepRange(const Decimal& stepBase, const Decimal& minimum, const Decimal& maximum, const Decimal& step, const StepDescription&);
+ Decimal acceptableError() const;
+ Decimal alignValueForStep(const Decimal& currentValue, const Decimal& newValue) const;
+ Decimal clampValue(const Decimal& value) const;
bool hasStep() const { return m_hasStep; }
- double maximum() const { return m_maximum; }
- double minimum() const { return m_minimum; }
- static DoubleWithDecimalPlacesOrMissing parseStep(AnyStepHandling, const StepDescription&, const String&);
- double step() const { return m_step; }
- double stepBase() const { return m_stepBase; }
- unsigned stepBaseDecimalPlaces() const { return m_stepBaseDecimalPlaces; }
- unsigned stepDecimalPlaces() const { return m_stepDecimalPlaces; }
+ Decimal maximum() const { return m_maximum; }
+ Decimal minimum() const { return m_minimum; }
+ static Decimal parseStep(AnyStepHandling, const StepDescription&, const String&);
+ Decimal step() const { return m_step; }
+ Decimal stepBase() const { return m_stepBase; }
int stepScaleFactor() const { return m_stepDescription.stepScaleFactor; }
- bool stepMismatch(double) const;
+ bool stepMismatch(const Decimal&) const;
// Clamp the middle value according to the step
- double defaultValue() const
+ Decimal defaultValue() const
{
return clampValue((m_minimum + m_maximum) / 2);
}
// Map value into 0-1 range
- double proportionFromValue(double value) const
+ Decimal proportionFromValue(const Decimal& value) const
{
if (m_minimum == m_maximum)
return 0;
@@ -121,21 +98,20 @@ public:
}
// Map from 0-1 range to value
- double valueFromProportion(double proportion) const
+ Decimal valueFromProportion(const Decimal& proportion) const
{
return m_minimum + proportion * (m_maximum - m_minimum);
}
private:
StepRange& operator =(const StepRange&);
+ Decimal roundByStep(const Decimal& value, const Decimal& base) const;
- const double m_maximum; // maximum must be >= minimum.
- const double m_minimum;
- const double m_step;
- const double m_stepBase;
+ const Decimal m_maximum; // maximum must be >= minimum.
+ const Decimal m_minimum;
+ const Decimal m_step;
+ const Decimal m_stepBase;
const StepDescription m_stepDescription;
- const unsigned m_stepBaseDecimalPlaces;
- const unsigned m_stepDecimalPlaces;
const bool m_hasStep;
};
diff --git a/Source/WebCore/html/TextFieldInputType.cpp b/Source/WebCore/html/TextFieldInputType.cpp
index 8189144a9..af53255bb 100644
--- a/Source/WebCore/html/TextFieldInputType.cpp
+++ b/Source/WebCore/html/TextFieldInputType.cpp
@@ -65,6 +65,16 @@ TextFieldInputType::~TextFieldInputType()
{
}
+bool TextFieldInputType::isKeyboardFocusable(KeyboardEvent*) const
+{
+ return element()->isTextFormControlFocusable();
+}
+
+bool TextFieldInputType::isMouseFocusable() const
+{
+ return element()->isTextFormControlFocusable();
+}
+
bool TextFieldInputType::isTextField() const
{
return true;
diff --git a/Source/WebCore/html/TextFieldInputType.h b/Source/WebCore/html/TextFieldInputType.h
index 559be25e7..b3629d0d3 100644
--- a/Source/WebCore/html/TextFieldInputType.h
+++ b/Source/WebCore/html/TextFieldInputType.h
@@ -67,6 +67,8 @@ protected:
virtual void handleBlurEvent() OVERRIDE;
private:
+ virtual bool isKeyboardFocusable(KeyboardEvent*) const OVERRIDE;
+ virtual bool isMouseFocusable() const OVERRIDE;
virtual bool isTextField() const OVERRIDE;
virtual bool valueMissing(const String&) const OVERRIDE;
virtual void handleBeforeTextInsertedEvent(BeforeTextInsertedEvent*) OVERRIDE;
diff --git a/Source/WebCore/html/TimeInputType.cpp b/Source/WebCore/html/TimeInputType.cpp
index ec527024c..052b88756 100644
--- a/Source/WebCore/html/TimeInputType.cpp
+++ b/Source/WebCore/html/TimeInputType.cpp
@@ -45,9 +45,9 @@ namespace WebCore {
using namespace HTMLNames;
-static const double timeDefaultStep = 60.0;
-static const double timeDefaultStepBase = 0.0;
-static const double timeStepScaleFactor = 1000.0;
+static const int timeDefaultStep = 60;
+static const int timeDefaultStepBase = 0;
+static const int timeStepScaleFactor = 1000;
PassOwnPtr<InputType> TimeInputType::create(HTMLInputElement* element)
{
@@ -64,7 +64,7 @@ DateComponents::Type TimeInputType::dateType() const
return DateComponents::Time;
}
-double TimeInputType::defaultValueForStepUp() const
+Decimal TimeInputType::defaultValueForStepUp() const
{
double current = currentTimeMS();
double utcOffset = calculateUTCOffset();
@@ -76,17 +76,17 @@ double TimeInputType::defaultValueForStepUp() const
date.setMillisecondsSinceMidnight(current);
double milliseconds = date.millisecondsSinceEpoch();
ASSERT(isfinite(milliseconds));
- return milliseconds;
+ return Decimal::fromDouble(milliseconds);
}
StepRange TimeInputType::createStepRange(AnyStepHandling anyStepHandling) const
{
DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (timeDefaultStep, timeDefaultStepBase, timeStepScaleFactor, StepRange::ScaledStepValueShouldBeInteger));
- double stepBase = parseToDouble(element()->fastGetAttribute(minAttr), 0);
- double minimum = parseToDouble(element()->fastGetAttribute(minAttr), DateComponents::minimumTime());
- double maximum = parseToDouble(element()->fastGetAttribute(maxAttr), DateComponents::maximumTime());
- StepRange::DoubleWithDecimalPlacesOrMissing step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
+ const Decimal stepBase = parseToNumber(element()->fastGetAttribute(minAttr), 0);
+ const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), Decimal::fromDouble(DateComponents::minimumTime()));
+ const Decimal maximum = parseToNumber(element()->fastGetAttribute(maxAttr), Decimal::fromDouble(DateComponents::maximumTime()));
+ const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
return StepRange(stepBase, minimum, maximum, step, stepDescription);
}
diff --git a/Source/WebCore/html/TimeInputType.h b/Source/WebCore/html/TimeInputType.h
index 1c2c286ec..c9d5b0cdd 100644
--- a/Source/WebCore/html/TimeInputType.h
+++ b/Source/WebCore/html/TimeInputType.h
@@ -45,7 +45,7 @@ private:
TimeInputType(HTMLInputElement* element) : BaseDateAndTimeInputType(element) { }
virtual const AtomicString& formControlType() const OVERRIDE;
virtual DateComponents::Type dateType() const OVERRIDE;
- virtual double defaultValueForStepUp() const OVERRIDE;
+ virtual Decimal defaultValueForStepUp() const OVERRIDE;
virtual StepRange createStepRange(AnyStepHandling) const OVERRIDE;
virtual bool parseToDateComponentsInternal(const UChar*, unsigned length, DateComponents*) const OVERRIDE;
virtual bool setMillisecondToDateComponents(double, DateComponents*) const OVERRIDE;
diff --git a/Source/WebCore/html/WeekInputType.cpp b/Source/WebCore/html/WeekInputType.cpp
index 3a6228911..c881ae8c1 100644
--- a/Source/WebCore/html/WeekInputType.cpp
+++ b/Source/WebCore/html/WeekInputType.cpp
@@ -42,9 +42,9 @@ 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;
+static const int weekDefaultStepBase = -259200000; // The first day of 1970-W01.
+static const int weekDefaultStep = 1;
+static const int weekStepScaleFactor = 604800000;
PassOwnPtr<InputType> WeekInputType::create(HTMLInputElement* element)
{
@@ -65,10 +65,10 @@ StepRange WeekInputType::createStepRange(AnyStepHandling anyStepHandling) const
{
DEFINE_STATIC_LOCAL(const StepRange::StepDescription, stepDescription, (weekDefaultStep, weekDefaultStepBase, weekStepScaleFactor, StepRange::ParsedStepValueShouldBeInteger));
- double stepBase = parseToDouble(element()->fastGetAttribute(minAttr), weekDefaultStepBase);
- double minimum = parseToDouble(element()->fastGetAttribute(minAttr), DateComponents::minimumWeek());
- double maximum = parseToDouble(element()->fastGetAttribute(maxAttr), DateComponents::maximumWeek());
- StepRange::DoubleWithDecimalPlacesOrMissing step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
+ const Decimal stepBase = parseToNumber(element()->fastGetAttribute(minAttr), weekDefaultStepBase);
+ const Decimal minimum = parseToNumber(element()->fastGetAttribute(minAttr), Decimal::fromDouble(DateComponents::minimumWeek()));
+ const Decimal maximum = parseToNumber(element()->fastGetAttribute(maxAttr), Decimal::fromDouble(DateComponents::maximumWeek()));
+ const Decimal step = StepRange::parseStep(anyStepHandling, stepDescription, element()->fastGetAttribute(stepAttr));
return StepRange(stepBase, minimum, maximum, step, stepDescription);
}
diff --git a/Source/WebCore/html/canvas/CanvasRenderingContext.cpp b/Source/WebCore/html/canvas/CanvasRenderingContext.cpp
index c73fc99e4..8813d990d 100644
--- a/Source/WebCore/html/canvas/CanvasRenderingContext.cpp
+++ b/Source/WebCore/html/canvas/CanvasRenderingContext.cpp
@@ -77,11 +77,12 @@ bool CanvasRenderingContext::wouldTaintOrigin(const HTMLVideoElement* video)
if (!video || !canvas()->originClean())
return false;
- if (wouldTaintOrigin(video->currentSrc()))
+ if (!video->hasSingleSecurityOrigin())
return true;
- if (!video->hasSingleSecurityOrigin())
+ if (!(video->player() && video->player()->didPassCORSAccessCheck()) && wouldTaintOrigin(video->currentSrc()))
return true;
+
#else
UNUSED_PARAM(video);
#endif
diff --git a/Source/WebCore/html/canvas/WebGLDepthTexture.cpp b/Source/WebCore/html/canvas/WebGLDepthTexture.cpp
new file mode 100644
index 000000000..3acf46a1b
--- /dev/null
+++ b/Source/WebCore/html/canvas/WebGLDepthTexture.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEBGL)
+
+#include "WebGLDepthTexture.h"
+
+#include "Extensions3D.h"
+
+namespace WebCore {
+
+WebGLDepthTexture::WebGLDepthTexture(WebGLRenderingContext* context)
+ : WebGLExtension(context)
+{
+}
+
+WebGLDepthTexture::~WebGLDepthTexture()
+{
+}
+
+WebGLExtension::ExtensionName WebGLDepthTexture::getName() const
+{
+ return WebKitWebGLDepthTextureName;
+}
+
+PassOwnPtr<WebGLDepthTexture> WebGLDepthTexture::create(WebGLRenderingContext* context)
+{
+ return adoptPtr(new WebGLDepthTexture(context));
+}
+
+bool WebGLDepthTexture::supported(GraphicsContext3D* context)
+{
+ Extensions3D* extensions = context->getExtensions();
+ return extensions->supports("GL_CHROMIUM_depth_texture")
+ || extensions->supports("GL_OES_depth_texture")
+ || extensions->supports("GL_ARB_depth_texture");
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEBGL)
diff --git a/Source/WebCore/html/canvas/WebGLDepthTexture.h b/Source/WebCore/html/canvas/WebGLDepthTexture.h
new file mode 100644
index 000000000..bac6aabff
--- /dev/null
+++ b/Source/WebCore/html/canvas/WebGLDepthTexture.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WebGLDepthTexture_h
+#define WebGLDepthTexture_h
+
+#include "WebGLExtension.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class WebGLDepthTexture : public WebGLExtension {
+public:
+ static PassOwnPtr<WebGLDepthTexture> create(WebGLRenderingContext*);
+
+ static bool supported(GraphicsContext3D*);
+
+ virtual ~WebGLDepthTexture();
+ virtual ExtensionName getName() const;
+
+private:
+ WebGLDepthTexture(WebGLRenderingContext*);
+};
+
+} // namespace WebCore
+
+#endif // WebGLDepthTexture_h
diff --git a/Source/WebCore/html/canvas/WebGLDepthTexture.idl b/Source/WebCore/html/canvas/WebGLDepthTexture.idl
new file mode 100644
index 000000000..507450d18
--- /dev/null
+++ b/Source/WebCore/html/canvas/WebGLDepthTexture.idl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module html {
+ interface [
+ Conditional=WEBGL,
+ JSGenerateIsReachable=ImplContext,
+ OmitConstructor
+ ] WebGLDepthTexture {
+ };
+}
diff --git a/Source/WebCore/html/canvas/WebGLExtension.h b/Source/WebCore/html/canvas/WebGLExtension.h
index a4d397029..c66a60861 100644
--- a/Source/WebCore/html/canvas/WebGLExtension.h
+++ b/Source/WebCore/html/canvas/WebGLExtension.h
@@ -42,6 +42,7 @@ public:
WebGLDebugRendererInfoName,
WebGLDebugShadersName,
WebKitWebGLCompressedTextureS3TCName, // WEBKIT_ prefix until extension is official
+ WebKitWebGLDepthTextureName, // WEBKIT_ prefix until extension is official
};
void ref() { m_context->ref(); }
diff --git a/Source/WebCore/html/canvas/WebGLFramebuffer.cpp b/Source/WebCore/html/canvas/WebGLFramebuffer.cpp
index eb07cf06a..e515423e6 100644
--- a/Source/WebCore/html/canvas/WebGLFramebuffer.cpp
+++ b/Source/WebCore/html/canvas/WebGLFramebuffer.cpp
@@ -36,81 +36,233 @@ namespace WebCore {
namespace {
- bool isAttachmentComplete(WebGLSharedObject* attachedObject, GC3Denum attachment, const char** reason)
+ Platform3DObject objectOrZero(WebGLObject* object)
{
- ASSERT(attachedObject && attachedObject->object());
- ASSERT(attachedObject->isRenderbuffer());
- ASSERT(reason);
- WebGLRenderbuffer* buffer = reinterpret_cast<WebGLRenderbuffer*>(attachedObject);
- switch (attachment) {
- case GraphicsContext3D::DEPTH_ATTACHMENT:
- if (buffer->getInternalFormat() != GraphicsContext3D::DEPTH_COMPONENT16) {
- *reason = "DEPTH_ATTACHMENT is not a depth format";
- return false;
- }
- break;
- case GraphicsContext3D::STENCIL_ATTACHMENT:
- if (buffer->getInternalFormat() != GraphicsContext3D::STENCIL_INDEX8) {
- *reason = "STENCIL_ATTACHMENT is not a stencil format";
- return false;
- }
- break;
- case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
- if (buffer->getInternalFormat() != GraphicsContext3D::DEPTH_STENCIL) {
- *reason = "DEPTH_STENCIL_ATTACHMENT is not a depth-stencil format";
- return false;
- }
- break;
- default:
- ASSERT_NOT_REACHED();
- return false;
- }
- if (!buffer->getWidth() || !buffer->getHeight()) {
- *reason = "attachment has a 0 dimension";
- return false;
- }
+ return object ? object->object() : 0;
+ }
+
+ class WebGLRenderbufferAttachment : public WebGLFramebuffer::WebGLAttachment {
+ public:
+ static PassRefPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLRenderbuffer*);
+
+ private:
+ WebGLRenderbufferAttachment(WebGLRenderbuffer*);
+ virtual GC3Dsizei getWidth() const;
+ virtual GC3Dsizei getHeight() const;
+ virtual GC3Denum getFormat() const;
+ virtual WebGLSharedObject* getObject() const;
+ virtual bool isSharedObject(WebGLSharedObject*) const;
+ virtual bool isValid() const;
+ virtual bool isInitialized() const;
+ virtual void setInitialized();
+ virtual void onDetached(GraphicsContext3D*);
+ virtual void attach(GraphicsContext3D*, GC3Denum attachment);
+ virtual void unattach(GraphicsContext3D*, GC3Denum attachment);
+
+ WebGLRenderbufferAttachment() { };
+
+ RefPtr<WebGLRenderbuffer> m_renderbuffer;
+ };
+
+ PassRefPtr<WebGLFramebuffer::WebGLAttachment> WebGLRenderbufferAttachment::create(WebGLRenderbuffer* renderbuffer)
+ {
+ return adoptRef(new WebGLRenderbufferAttachment(renderbuffer));
+ }
+
+ WebGLRenderbufferAttachment::WebGLRenderbufferAttachment(WebGLRenderbuffer* renderbuffer)
+ : m_renderbuffer(renderbuffer)
+ {
+ }
+
+ GC3Dsizei WebGLRenderbufferAttachment::getWidth() const
+ {
+ return m_renderbuffer->getWidth();
+ }
+
+ GC3Dsizei WebGLRenderbufferAttachment::getHeight() const
+ {
+ return m_renderbuffer->getHeight();
+ }
+
+ GC3Denum WebGLRenderbufferAttachment::getFormat() const
+ {
+ return m_renderbuffer->getInternalFormat();
+ }
+
+ WebGLSharedObject* WebGLRenderbufferAttachment::getObject() const
+ {
+ return m_renderbuffer->object() ? m_renderbuffer.get() : 0;
+ }
+
+ bool WebGLRenderbufferAttachment::isSharedObject(WebGLSharedObject* object) const
+ {
+ return object == m_renderbuffer;
+ }
+
+ bool WebGLRenderbufferAttachment::isValid() const
+ {
+ return m_renderbuffer->object();
+ }
+
+ bool WebGLRenderbufferAttachment::isInitialized() const
+ {
+ return m_renderbuffer->object() && m_renderbuffer->isInitialized();
+ }
+
+ void WebGLRenderbufferAttachment::setInitialized()
+ {
+ if (m_renderbuffer->object())
+ m_renderbuffer->setInitialized();
+ }
+
+ void WebGLRenderbufferAttachment::onDetached(GraphicsContext3D* context)
+ {
+ m_renderbuffer->onDetached(context);
+ }
+
+ void WebGLRenderbufferAttachment::attach(GraphicsContext3D* context, GC3Denum attachment)
+ {
+ Platform3DObject object = objectOrZero(m_renderbuffer.get());
+ context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, attachment, GraphicsContext3D::RENDERBUFFER, object);
+ }
+
+ void WebGLRenderbufferAttachment::unattach(GraphicsContext3D* context, GC3Denum attachment)
+ {
+ if (attachment == GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT) {
+ context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, 0);
+ context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, 0);
+ } else
+ context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, attachment, GraphicsContext3D::RENDERBUFFER, 0);
+ }
+
+ class WebGLTextureAttachment : public WebGLFramebuffer::WebGLAttachment {
+ public:
+ static PassRefPtr<WebGLFramebuffer::WebGLAttachment> create(WebGLTexture*, GC3Denum target, GC3Dint level);
+
+ private:
+ WebGLTextureAttachment(WebGLTexture*, GC3Denum target, GC3Dint level);
+ virtual GC3Dsizei getWidth() const;
+ virtual GC3Dsizei getHeight() const;
+ virtual GC3Denum getFormat() const;
+ virtual WebGLSharedObject* getObject() const;
+ virtual bool isSharedObject(WebGLSharedObject*) const;
+ virtual bool isValid() const;
+ virtual bool isInitialized() const;
+ virtual void setInitialized();
+ virtual void onDetached(GraphicsContext3D*);
+ virtual void attach(GraphicsContext3D*, GC3Denum attachment);
+ virtual void unattach(GraphicsContext3D*, GC3Denum attachment);
+
+ WebGLTextureAttachment() { };
+
+ RefPtr<WebGLTexture> m_texture;
+ GC3Denum m_target;
+ GC3Dint m_level;
+ };
+
+ PassRefPtr<WebGLFramebuffer::WebGLAttachment> WebGLTextureAttachment::create(WebGLTexture* texture, GC3Denum target, GC3Dint level)
+ {
+ return adoptRef(new WebGLTextureAttachment(texture, target, level));
+ }
+
+ WebGLTextureAttachment::WebGLTextureAttachment(WebGLTexture* texture, GC3Denum target, GC3Dint level)
+ : m_texture(texture)
+ , m_target(target)
+ , m_level(level)
+ {
+ }
+
+ GC3Dsizei WebGLTextureAttachment::getWidth() const
+ {
+ return m_texture->getWidth(m_target, m_level);
+ }
+
+ GC3Dsizei WebGLTextureAttachment::getHeight() const
+ {
+ return m_texture->getHeight(m_target, m_level);
+ }
+
+ GC3Denum WebGLTextureAttachment::getFormat() const
+ {
+ return m_texture->getInternalFormat(m_target, m_level);
+ }
+
+ WebGLSharedObject* WebGLTextureAttachment::getObject() const
+ {
+ return m_texture->object() ? m_texture.get() : 0;
+ }
+
+ bool WebGLTextureAttachment::isSharedObject(WebGLSharedObject* object) const
+ {
+ return object == m_texture;
+ }
+
+ bool WebGLTextureAttachment::isValid() const
+ {
+ return m_texture->object();
+ }
+
+ bool WebGLTextureAttachment::isInitialized() const
+ {
+ // Textures are assumed to be initialized.
return true;
}
- GC3Dsizei getImageWidth(WebGLSharedObject* attachedObject)
+ void WebGLTextureAttachment::setInitialized()
{
- ASSERT(attachedObject && attachedObject->object());
- ASSERT(attachedObject->isRenderbuffer());
- WebGLRenderbuffer* buffer = reinterpret_cast<WebGLRenderbuffer*>(attachedObject);
- return buffer->getWidth();
+ // Textures are assumed to be initialized.
}
- GC3Dsizei getImageHeight(WebGLSharedObject* attachedObject)
+ void WebGLTextureAttachment::onDetached(GraphicsContext3D* context)
{
- ASSERT(attachedObject && attachedObject->object());
- ASSERT(attachedObject->isRenderbuffer());
- WebGLRenderbuffer* buffer = reinterpret_cast<WebGLRenderbuffer*>(attachedObject);
- return buffer->getHeight();
+ m_texture->onDetached(context);
}
- bool isUninitialized(WebGLSharedObject* attachedObject)
+ void WebGLTextureAttachment::attach(GraphicsContext3D* context, GC3Denum attachment)
{
- if (attachedObject && attachedObject->object() && attachedObject->isRenderbuffer()
- && !(reinterpret_cast<WebGLRenderbuffer*>(attachedObject))->isInitialized())
- return true;
- return false;
+ Platform3DObject object = objectOrZero(m_texture.get());
+ context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, attachment, m_target, object, m_level);
}
- void setInitialized(WebGLSharedObject* attachedObject)
+ void WebGLTextureAttachment::unattach(GraphicsContext3D* context, GC3Denum attachment)
{
- if (attachedObject && attachedObject->object() && attachedObject->isRenderbuffer())
- (reinterpret_cast<WebGLRenderbuffer*>(attachedObject))->setInitialized();
+ context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, attachment, m_target, 0, m_level);
}
- bool isValidRenderbuffer(WebGLSharedObject* attachedObject)
+ bool isAttachmentComplete(WebGLFramebuffer::WebGLAttachment* attachedObject, GC3Denum attachment, const char** reason)
{
- if (!attachedObject || !attachedObject->object() || !attachedObject->isRenderbuffer())
+ ASSERT(attachedObject && attachedObject->isValid());
+ ASSERT(reason);
+ GC3Denum format = attachedObject->getFormat();
+ unsigned need = GraphicsContext3D::getClearBitsByAttachmentType(attachment);
+ unsigned have = GraphicsContext3D::getClearBitsByFormat(format);
+
+ if ((need & have) != need) {
+ *reason = "attachment type is not correct for attachment";
+ return false;
+ }
+ if (!attachedObject->getWidth() || !attachedObject->getHeight()) {
+ *reason = "attachment has a 0 dimension";
return false;
- return static_cast<WebGLRenderbuffer*>(attachedObject)->isValid();
+ }
+ if ((attachment == GraphicsContext3D::DEPTH_ATTACHMENT || attachment == GraphicsContext3D::STENCIL_ATTACHMENT)
+ && format == GraphicsContext3D::DEPTH_STENCIL) {
+ *reason = "attachment DEPTH_STENCIL not allowed on DEPTH or STENCIL attachment";
+ return false;
+ }
+ return true;
}
} // anonymous namespace
+WebGLFramebuffer::WebGLAttachment::WebGLAttachment()
+{
+}
+
+WebGLFramebuffer::WebGLAttachment::~WebGLAttachment()
+{
+}
+
PassRefPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContext* ctx)
{
return adoptRef(new WebGLFramebuffer(ctx));
@@ -119,8 +271,6 @@ PassRefPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContext* ctx
WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContext* ctx)
: WebGLContextObject(ctx)
, m_hasEverBeenBound(false)
- , m_texTarget(0)
- , m_texLevel(-1)
{
setObject(ctx->graphicsContext3D()->createFramebuffer());
}
@@ -133,82 +283,47 @@ WebGLFramebuffer::~WebGLFramebuffer()
void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GC3Denum attachment, GC3Denum texTarget, WebGLTexture* texture, GC3Dint level)
{
ASSERT(isBound());
+ removeAttachmentFromBoundFramebuffer(attachment);
if (!object())
return;
- removeAttachmentFromBoundFramebuffer(attachment);
- if (texture && !texture->object())
- texture = 0;
- switch (attachment) {
- case GraphicsContext3D::COLOR_ATTACHMENT0:
- m_colorAttachment = texture;
- if (texture) {
- m_texTarget = texTarget;
- m_texLevel = level;
- }
- break;
- case GraphicsContext3D::DEPTH_ATTACHMENT:
- m_depthAttachment = texture;
- break;
- case GraphicsContext3D::STENCIL_ATTACHMENT:
- m_stencilAttachment = texture;
- break;
- case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
- m_depthStencilAttachment = texture;
- break;
- default:
- ASSERT_NOT_REACHED();
- break;
- }
- if (texture)
+ if (texture && texture->object()) {
+ m_attachments.add(attachment, WebGLTextureAttachment::create(texture, texTarget, level));
texture->onAttached();
+ }
}
void WebGLFramebuffer::setAttachmentForBoundFramebuffer(GC3Denum attachment, WebGLRenderbuffer* renderbuffer)
{
ASSERT(isBound());
+ removeAttachmentFromBoundFramebuffer(attachment);
if (!object())
return;
- removeAttachmentFromBoundFramebuffer(attachment);
- if (renderbuffer && !renderbuffer->object())
- renderbuffer = 0;
- switch (attachment) {
- case GraphicsContext3D::COLOR_ATTACHMENT0:
- m_colorAttachment = renderbuffer;
- break;
- case GraphicsContext3D::DEPTH_ATTACHMENT:
- m_depthAttachment = renderbuffer;
- break;
- case GraphicsContext3D::STENCIL_ATTACHMENT:
- m_stencilAttachment = renderbuffer;
- break;
- case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
- m_depthStencilAttachment = renderbuffer;
- break;
- default:
- ASSERT_NOT_REACHED();
- break;
- }
- if (renderbuffer)
+ if (renderbuffer && renderbuffer->object()) {
+ m_attachments.add(attachment, WebGLRenderbufferAttachment::create(renderbuffer));
renderbuffer->onAttached();
+ }
}
-WebGLSharedObject* WebGLFramebuffer::getAttachment(GC3Denum attachment) const
+void WebGLFramebuffer::attach(GC3Denum attachment, GC3Denum attachmentPoint)
+{
+ ASSERT(isBound());
+ WebGLAttachment* attachmentObject = getAttachment(attachment);
+ if (attachmentObject)
+ attachmentObject->attach(context()->graphicsContext3D(), attachmentPoint);
+}
+
+WebGLSharedObject* WebGLFramebuffer::getAttachmentObject(GC3Denum attachment) const
{
if (!object())
return 0;
- switch (attachment) {
- case GraphicsContext3D::COLOR_ATTACHMENT0:
- return m_colorAttachment.get();
- case GraphicsContext3D::DEPTH_ATTACHMENT:
- return m_depthAttachment.get();
- case GraphicsContext3D::STENCIL_ATTACHMENT:
- return m_stencilAttachment.get();
- case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
- return m_depthStencilAttachment.get();
- default:
- ASSERT_NOT_REACHED();
- return 0;
- }
+ WebGLAttachment* attachmentObject = getAttachment(attachment);
+ return attachmentObject ? attachmentObject->getObject() : 0;
+}
+
+WebGLFramebuffer::WebGLAttachment* WebGLFramebuffer::getAttachment(GC3Denum attachment) const
+{
+ const AttachmentMap::const_iterator it = m_attachments.find(attachment);
+ return (it != m_attachments.end()) ? it->second.get() : 0;
}
void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GC3Denum attachment)
@@ -217,37 +332,22 @@ void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GC3Denum attachment)
if (!object())
return;
- GraphicsContext3D* context3d = context()->graphicsContext3D();
- switch (attachment) {
- case GraphicsContext3D::COLOR_ATTACHMENT0:
- if (m_colorAttachment) {
- m_colorAttachment->onDetached(context3d);
- m_colorAttachment = 0;
- m_texTarget = 0;
- m_texLevel = -1;
- }
- break;
- case GraphicsContext3D::DEPTH_ATTACHMENT:
- if (m_depthAttachment) {
- m_depthAttachment->onDetached(context3d);
- m_depthAttachment = 0;
- }
- break;
- case GraphicsContext3D::STENCIL_ATTACHMENT:
- if (m_stencilAttachment) {
- m_stencilAttachment->onDetached(context3d);
- m_stencilAttachment = 0;
- }
- break;
- case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
- if (m_depthStencilAttachment) {
- m_depthStencilAttachment->onDetached(context3d);
- m_depthStencilAttachment = 0;
+ WebGLAttachment* attachmentObject = getAttachment(attachment);
+ if (attachmentObject) {
+ attachmentObject->onDetached(context()->graphicsContext3D());
+ m_attachments.remove(attachment);
+ switch (attachment) {
+ case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
+ attach(GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::DEPTH_ATTACHMENT);
+ attach(GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::STENCIL_ATTACHMENT);
+ break;
+ case GraphicsContext3D::DEPTH_ATTACHMENT:
+ attach(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT, GraphicsContext3D::DEPTH_ATTACHMENT);
+ break;
+ case GraphicsContext3D::STENCIL_ATTACHMENT:
+ attach(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT, GraphicsContext3D::STENCIL_ATTACHMENT);
+ break;
}
- break;
- default:
- ASSERT_NOT_REACHED();
- break;
}
}
@@ -259,200 +359,148 @@ void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(WebGLSharedObject* a
if (!attachment)
return;
- GraphicsContext3D* gc3d = context()->graphicsContext3D();
-
- if (attachment == m_colorAttachment.get()) {
- if (attachment->isRenderbuffer())
- gc3d->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::RENDERBUFFER, 0);
- else
- gc3d->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, m_texTarget, 0, m_texLevel);
- removeAttachmentFromBoundFramebuffer(GraphicsContext3D::COLOR_ATTACHMENT0);
- }
- if (attachment == m_depthAttachment.get()) {
- gc3d->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, 0);
- removeAttachmentFromBoundFramebuffer(GraphicsContext3D::DEPTH_ATTACHMENT);
- }
- if (attachment == m_stencilAttachment.get()) {
- gc3d->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, 0);
- removeAttachmentFromBoundFramebuffer(GraphicsContext3D::STENCIL_ATTACHMENT);
- }
- if (attachment == m_depthStencilAttachment.get()) {
- gc3d->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, 0);
- gc3d->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, 0);
- removeAttachmentFromBoundFramebuffer(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT);
+ bool checkMore = true;
+ while (checkMore) {
+ checkMore = false;
+ for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
+ WebGLAttachment* attachmentObject = it->second.get();
+ if (attachmentObject->isSharedObject(attachment)) {
+ GC3Denum attachmentType = it->first;
+ attachmentObject->unattach(context()->graphicsContext3D(), attachmentType);
+ removeAttachmentFromBoundFramebuffer(attachmentType);
+ checkMore = true;
+ break;
+ }
+ }
}
}
GC3Dsizei WebGLFramebuffer::getColorBufferWidth() const
{
- if (!object() || !isColorAttached())
+ if (!object())
return 0;
- if (m_colorAttachment->isRenderbuffer())
- return (reinterpret_cast<WebGLRenderbuffer*>(m_colorAttachment.get()))->getWidth();
- if (m_colorAttachment->isTexture())
- return (reinterpret_cast<WebGLTexture*>(m_colorAttachment.get()))->getWidth(m_texTarget, m_texLevel);
- ASSERT_NOT_REACHED();
- return 0;
+ WebGLAttachment* attachment = getAttachment(GraphicsContext3D::COLOR_ATTACHMENT0);
+ if (!attachment)
+ return 0;
+
+ return attachment->getWidth();
}
GC3Dsizei WebGLFramebuffer::getColorBufferHeight() const
{
- if (!object() || !isColorAttached())
+ if (!object())
+ return 0;
+ WebGLAttachment* attachment = getAttachment(GraphicsContext3D::COLOR_ATTACHMENT0);
+ if (!attachment)
return 0;
- if (m_colorAttachment->isRenderbuffer())
- return (reinterpret_cast<WebGLRenderbuffer*>(m_colorAttachment.get()))->getHeight();
- if (m_colorAttachment->isTexture())
- return (reinterpret_cast<WebGLTexture*>(m_colorAttachment.get()))->getHeight(m_texTarget, m_texLevel);
- ASSERT_NOT_REACHED();
- return 0;
+
+ return attachment->getHeight();
}
GC3Denum WebGLFramebuffer::getColorBufferFormat() const
{
- if (!object() || !isColorAttached())
+ if (!object())
return 0;
- if (m_colorAttachment->isRenderbuffer()) {
- unsigned long format = (reinterpret_cast<WebGLRenderbuffer*>(m_colorAttachment.get()))->getInternalFormat();
- switch (format) {
- case GraphicsContext3D::RGBA4:
- case GraphicsContext3D::RGB5_A1:
- return GraphicsContext3D::RGBA;
- case GraphicsContext3D::RGB565:
- return GraphicsContext3D::RGB;
- }
+ WebGLAttachment* attachment = getAttachment(GraphicsContext3D::COLOR_ATTACHMENT0);
+ if (!attachment)
return 0;
- }
- if (m_colorAttachment->isTexture())
- return (reinterpret_cast<WebGLTexture*>(m_colorAttachment.get()))->getInternalFormat(m_texTarget, m_texLevel);
- ASSERT_NOT_REACHED();
- return 0;
+ return attachment->getFormat();
}
GC3Denum WebGLFramebuffer::checkStatus(const char** reason) const
{
unsigned int count = 0;
GC3Dsizei width = 0, height = 0;
- if (isDepthAttached()) {
- if (!isAttachmentComplete(m_depthAttachment.get(), GraphicsContext3D::DEPTH_ATTACHMENT, reason))
- return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
- width = getImageWidth(m_depthAttachment.get());
- height = getImageHeight(m_depthAttachment.get());
- count++;
- }
- if (isStencilAttached()) {
- if (!isAttachmentComplete(m_stencilAttachment.get(), GraphicsContext3D::STENCIL_ATTACHMENT, reason))
+ bool haveDepth = false;
+ bool haveStencil = false;
+ bool haveDepthStencil = false;
+ for (AttachmentMap::const_iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
+ WebGLAttachment* attachment = it->second.get();
+ if (!isAttachmentComplete(attachment, it->first, reason))
return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
- if (!count) {
- width = getImageWidth(m_stencilAttachment.get());
- height = getImageHeight(m_stencilAttachment.get());
- } else {
- if (width != getImageWidth(m_stencilAttachment.get()) || height != getImageHeight(m_stencilAttachment.get())) {
- *reason = "STENCIL_ATTACHMENT has different dimensions than DEPTH_ATTACHMENT";
- return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
- }
+ if (!attachment->isValid()) {
+ *reason = "attachment is not valid";
+ return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
}
- count++;
- }
- if (isDepthStencilAttached()) {
- if (!isAttachmentComplete(m_depthStencilAttachment.get(), GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT, reason))
+ if (!attachment->getFormat()) {
+ *reason = "attachment is an unsupported format";
return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
- if (!isValidRenderbuffer(m_depthStencilAttachment.get())) {
- *reason = "DEPTH_STENCIL_ATTACHMENT is not valid";
- return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
+ }
+ switch (it->first) {
+ case GraphicsContext3D::DEPTH_ATTACHMENT:
+ haveDepth = true;
+ break;
+ case GraphicsContext3D::STENCIL_ATTACHMENT:
+ haveDepth = true;
+ break;
+ case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
+ haveDepthStencil = true;
+ break;
}
if (!count) {
- width = getImageWidth(m_depthStencilAttachment.get());
- height = getImageHeight(m_depthStencilAttachment.get());
+ width = attachment->getWidth();
+ height = attachment->getHeight();
} else {
- if (width != getImageWidth(m_depthStencilAttachment.get()) || height != getImageHeight(m_depthStencilAttachment.get())) {
- *reason = "DEPTH_STENCIL_ATTACHMENT has different dimensions than other attachments";
+ if (width != attachment->getWidth() || height != attachment->getHeight()) {
+ *reason = "attachments do not have the same dimensions";
return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
}
}
- count++;
+ ++count;
+ }
+ if (!count) {
+ *reason = "no attachments";
+ return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
+ }
+ if (!width || !height) {
+ *reason = "framebuffer has a 0 dimension";
+ return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
}
// WebGL specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments.
- if (count > 1) {
+ if ((haveDepthStencil && (haveDepth || haveStencil)) || (haveDepth && haveStencil)) {
*reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments";
return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
}
- if (isColorAttached()) {
- // FIXME: if color buffer is texture, is ALPHA, LUMINANCE or LUMINANCE_ALPHA valid?
- if (!getColorBufferFormat()) {
- *reason = "COLOR_ATTACHMENT0 is an unsupported format";
- return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
- }
- if (!count) {
- if (!getColorBufferWidth() || !getColorBufferHeight()) {
- *reason = "COLOR_ATTACHMENT0 has a 0 dimension";
- return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
- }
- } else {
- if (width != getColorBufferWidth() || height != getColorBufferHeight()) {
- *reason = "COLOR_ATTACHMENT0 has different dimensions than other attachments";
- return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
- }
- }
-
- } else {
- if (!count) {
- *reason = "no attachments";
- return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
- }
- }
return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
}
-bool WebGLFramebuffer::onAccess(GraphicsContext3D* context3d, bool needToInitializeRenderbuffers, const char** reason)
+bool WebGLFramebuffer::onAccess(GraphicsContext3D* context3d, bool needToInitializeAttachments, const char** reason)
{
if (checkStatus(reason) != GraphicsContext3D::FRAMEBUFFER_COMPLETE)
return false;
- if (needToInitializeRenderbuffers)
- return initializeRenderbuffers(context3d, reason);
+ if (needToInitializeAttachments)
+ return initializeAttachments(context3d, reason);
return true;
}
bool WebGLFramebuffer::hasStencilBuffer() const
{
- return isValidRenderbuffer(m_depthStencilAttachment.get()) || isValidRenderbuffer(m_stencilAttachment.get());
+ WebGLAttachment* attachment = getAttachment(GraphicsContext3D::STENCIL_ATTACHMENT);
+ if (!attachment)
+ attachment = getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT);
+ return attachment && attachment->isValid();
}
void WebGLFramebuffer::deleteObjectImpl(GraphicsContext3D* context3d, Platform3DObject object)
{
- if (m_colorAttachment)
- m_colorAttachment->onDetached(context3d);
- if (m_depthAttachment)
- m_depthAttachment->onDetached(context3d);
- if (m_stencilAttachment)
- m_stencilAttachment->onDetached(context3d);
- if (m_depthStencilAttachment)
- m_depthStencilAttachment->onDetached(context3d);
+ for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it)
+ it->second->onDetached(context3d);
+
context3d->deleteFramebuffer(object);
}
-bool WebGLFramebuffer::initializeRenderbuffers(GraphicsContext3D* g3d, const char** reason)
+bool WebGLFramebuffer::initializeAttachments(GraphicsContext3D* g3d, const char** reason)
{
ASSERT(object());
- bool initColor = false, initDepth = false, initStencil = false;
GC3Dbitfield mask = 0;
- if (isUninitialized(m_colorAttachment.get())) {
- initColor = true;
- mask |= GraphicsContext3D::COLOR_BUFFER_BIT;
- }
- if (isUninitialized(m_depthAttachment.get())) {
- initDepth = true;
- mask |= GraphicsContext3D::DEPTH_BUFFER_BIT;
- }
- if (isUninitialized(m_stencilAttachment.get())) {
- initStencil = true;
- mask |= GraphicsContext3D::STENCIL_BUFFER_BIT;
- }
- if (isUninitialized(m_depthStencilAttachment.get())) {
- initDepth = true;
- initStencil = true;
- mask |= (GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT);
+
+ for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
+ GC3Denum attachmentType = it->first;
+ WebGLAttachment* attachment = it->second.get();
+ if (!attachment->isInitialized())
+ mask |= GraphicsContext3D::getClearBitsByAttachmentType(attachmentType);
}
- if (!initColor && !initDepth && !initStencil)
+ if (!mask)
return true;
// We only clear un-initialized renderbuffers when they are ready to be
@@ -462,6 +510,10 @@ bool WebGLFramebuffer::initializeRenderbuffers(GraphicsContext3D* g3d, const cha
return false;
}
+ bool initColor = mask & GraphicsContext3D::COLOR_BUFFER_BIT;
+ bool initDepth = mask & GraphicsContext3D::DEPTH_BUFFER_BIT;
+ bool initStencil = mask & GraphicsContext3D::STENCIL_BUFFER_BIT;
+
GC3Dfloat colorClearValue[] = {0, 0, 0, 0}, depthClearValue = 0;
GC3Dint stencilClearValue = 0;
GC3Dboolean colorMask[] = {0, 0, 0, 0}, depthMask = 0;
@@ -514,15 +566,12 @@ bool WebGLFramebuffer::initializeRenderbuffers(GraphicsContext3D* g3d, const cha
else
g3d->disable(GraphicsContext3D::DITHER);
- if (initColor)
- setInitialized(m_colorAttachment.get());
- if (initDepth && initStencil && m_depthStencilAttachment)
- setInitialized(m_depthStencilAttachment.get());
- else {
- if (initDepth)
- setInitialized(m_depthAttachment.get());
- if (initStencil)
- setInitialized(m_stencilAttachment.get());
+ for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
+ GC3Denum attachmentType = it->first;
+ WebGLAttachment* attachment = it->second.get();
+ GC3Dbitfield bits = GraphicsContext3D::getClearBitsByAttachmentType(attachmentType);
+ if (bits & mask)
+ attachment->setInitialized();
}
return true;
}
diff --git a/Source/WebCore/html/canvas/WebGLFramebuffer.h b/Source/WebCore/html/canvas/WebGLFramebuffer.h
index c69b0cc6a..9c4b519a6 100644
--- a/Source/WebCore/html/canvas/WebGLFramebuffer.h
+++ b/Source/WebCore/html/canvas/WebGLFramebuffer.h
@@ -39,6 +39,26 @@ class WebGLTexture;
class WebGLFramebuffer : public WebGLContextObject {
public:
+ class WebGLAttachment : public RefCounted<WebGLAttachment> {
+ public:
+ virtual ~WebGLAttachment();
+
+ virtual GC3Dsizei getWidth() const = 0;
+ virtual GC3Dsizei getHeight() const = 0;
+ virtual GC3Denum getFormat() const = 0;
+ virtual WebGLSharedObject* getObject() const = 0;
+ virtual bool isSharedObject(WebGLSharedObject*) const = 0;
+ virtual bool isValid() const = 0;
+ virtual bool isInitialized() const = 0;
+ virtual void setInitialized() = 0;
+ virtual void onDetached(GraphicsContext3D*) = 0;
+ virtual void attach(GraphicsContext3D*, GC3Denum attachment) = 0;
+ virtual void unattach(GraphicsContext3D*, GC3Denum attachment) = 0;
+
+ protected:
+ WebGLAttachment();
+ };
+
virtual ~WebGLFramebuffer();
static PassRefPtr<WebGLFramebuffer> create(WebGLRenderingContext*);
@@ -49,7 +69,7 @@ public:
void removeAttachmentFromBoundFramebuffer(WebGLSharedObject*);
// If a given attachment point for the currently bound framebuffer is not null, remove the attached object.
void removeAttachmentFromBoundFramebuffer(GC3Denum);
- WebGLSharedObject* getAttachment(GC3Denum) const;
+ WebGLSharedObject* getAttachmentObject(GC3Denum) const;
GC3Denum getColorBufferFormat() const;
GC3Dsizei getColorBufferWidth() const;
@@ -60,8 +80,8 @@ public:
// currently bound.
// Return false if the framebuffer is incomplete; otherwise initialize
// the buffers if they haven't been initialized and
- // needToInitializeRenderbuffers is true.
- bool onAccess(GraphicsContext3D*, bool needToInitializeRenderbuffers, const char** reason);
+ // needToInitializeAttachments is true.
+ bool onAccess(GraphicsContext3D*, bool needToInitializeAttachments, const char** reason);
// Software version of glCheckFramebufferStatus(), except that when
// FRAMEBUFFER_COMPLETE is returned, it is still possible for
@@ -83,26 +103,22 @@ protected:
private:
virtual bool isFramebuffer() const { return true; }
+ WebGLAttachment* getAttachment(GC3Denum) const;
+
// Return false if framebuffer is incomplete.
- bool initializeRenderbuffers(GraphicsContext3D*, const char** reason);
+ bool initializeAttachments(GraphicsContext3D*, const char** reason);
// Check if the framebuffer is currently bound.
bool isBound() const;
- bool isColorAttached() const { return (m_colorAttachment && m_colorAttachment->object()); }
- bool isDepthAttached() const { return (m_depthAttachment && m_depthAttachment->object()); }
- bool isStencilAttached() const { return (m_stencilAttachment && m_stencilAttachment->object()); }
- bool isDepthStencilAttached() const { return (m_depthStencilAttachment && m_depthStencilAttachment->object()); }
+ // attach 'attachment' at 'attachmentPoint'.
+ void attach(GC3Denum attachment, GC3Denum attachmentPoint);
- RefPtr<WebGLSharedObject> m_colorAttachment;
- RefPtr<WebGLSharedObject> m_depthAttachment;
- RefPtr<WebGLSharedObject> m_stencilAttachment;
- RefPtr<WebGLSharedObject> m_depthStencilAttachment;
+ typedef WTF::HashMap<GC3Denum, RefPtr<WebGLAttachment> > AttachmentMap;
- bool m_hasEverBeenBound;
+ AttachmentMap m_attachments;
- GC3Denum m_texTarget;
- GC3Dint m_texLevel;
+ bool m_hasEverBeenBound;
};
} // namespace WebCore
diff --git a/Source/WebCore/html/canvas/WebGLRenderingContext.cpp b/Source/WebCore/html/canvas/WebGLRenderingContext.cpp
index 038edc22c..5ce428503 100644
--- a/Source/WebCore/html/canvas/WebGLRenderingContext.cpp
+++ b/Source/WebCore/html/canvas/WebGLRenderingContext.cpp
@@ -59,6 +59,7 @@
#include "WebGLContextGroup.h"
#include "WebGLDebugRendererInfo.h"
#include "WebGLDebugShaders.h"
+#include "WebGLDepthTexture.h"
#include "WebGLFramebuffer.h"
#include "WebGLLoseContext.h"
#include "WebGLProgram.h"
@@ -81,7 +82,7 @@
namespace WebCore {
const double secondsBetweenRestoreAttempts = 1.0;
-const int maxGLErrorsAllowedToConsole = 10;
+const int maxGLErrorsAllowedToConsole = 256;
namespace {
@@ -1320,12 +1321,23 @@ void WebGLRenderingContext::compressedTexSubImage2D(GC3Denum target, GC3Dint lev
cleanupAfterGraphicsCall(false);
}
+bool WebGLRenderingContext::validateSettableTexFormat(const char* functionName, GC3Denum format)
+{
+ if (GraphicsContext3D::getClearBitsByFormat(format) & (GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) {
+ synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "format can not be set, only rendered to");
+ return false;
+ }
+ return true;
+}
+
void WebGLRenderingContext::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border)
{
if (isContextLost())
return;
if (!validateTexFuncParameters("copyTexImage2D", target, level, internalformat, width, height, border, internalformat, GraphicsContext3D::UNSIGNED_BYTE))
return;
+ if (!validateSettableTexFormat("copyTexImage2D", internalformat))
+ return;
WebGLTexture* tex = validateTextureBinding("copyTexImage2D", target, true);
if (!tex)
return;
@@ -1380,7 +1392,10 @@ void WebGLRenderingContext::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC
synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "rectangle out of range");
return;
}
- if (!isTexInternalFormatColorBufferCombinationValid(tex->getInternalFormat(target, level), getBoundFramebufferColorFormat())) {
+ GC3Denum internalformat = tex->getInternalFormat(target, level);
+ if (!validateSettableTexFormat("copyTexSubImage2D", internalformat))
+ return;
+ if (!isTexInternalFormatColorBufferCombinationValid(internalformat, getBoundFramebufferColorFormat())) {
synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "copyTexSubImage2D", "framebuffer is incompatible format");
return;
}
@@ -1865,8 +1880,10 @@ void WebGLRenderingContext::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei c
return;
}
- if (!count)
+ if (!count) {
+ cleanupAfterGraphicsCall(true);
return;
+ }
if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
// Ensure we have a valid rendering state
@@ -1929,8 +1946,10 @@ void WebGLRenderingContext::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denu
return;
}
- if (!count)
+ if (!count) {
+ cleanupAfterGraphicsCall(true);
return;
+ }
if (!m_boundVertexArrayObject->getElementArrayBuffer()) {
synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "no ELEMENT_ARRAY_BUFFER bound");
@@ -2055,53 +2074,21 @@ void WebGLRenderingContext::framebufferRenderbuffer(GC3Denum target, GC3Denum at
return;
}
Platform3DObject bufferObject = objectOrZero(buffer);
- bool reattachDepth = false;
- bool reattachStencil = false;
- bool reattachDepthStencilDepth = false;
- bool reattachDepthStencilStencil = false;
switch (attachment) {
case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, bufferObject);
- if (!bufferObject) {
- reattachDepth = true;
- reattachStencil = true;
- }
break;
case GraphicsContext3D::DEPTH_ATTACHMENT:
- m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
- if (!bufferObject)
- reattachDepthStencilDepth = true;
+ m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, bufferObject);
break;
case GraphicsContext3D::STENCIL_ATTACHMENT:
- m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
- if (!bufferObject)
- reattachDepthStencilStencil = true;
+ m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, bufferObject);
break;
default:
- m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
+ m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, bufferObject);
}
m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, buffer);
- if (reattachDepth) {
- Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_ATTACHMENT));
- if (object)
- m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object);
- }
- if (reattachStencil) {
- Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::STENCIL_ATTACHMENT));
- if (object)
- m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object);
- }
- if (reattachDepthStencilDepth) {
- Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT));
- if (object)
- m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object);
- }
- if (reattachDepthStencilStencil) {
- Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT));
- if (object)
- m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object);
- }
applyStencilTest();
cleanupAfterGraphicsCall(false);
}
@@ -2126,8 +2113,23 @@ void WebGLRenderingContext::framebufferTexture2D(GC3Denum target, GC3Denum attac
synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferTexture2D", "no framebuffer bound");
return;
}
- m_context->framebufferTexture2D(target, attachment, textarget, objectOrZero(texture), level);
+ Platform3DObject textureObject = objectOrZero(texture);
+ switch (attachment) {
+ case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
+ m_context->framebufferTexture2D(target, GraphicsContext3D::DEPTH_ATTACHMENT, textarget, textureObject, level);
+ m_context->framebufferTexture2D(target, GraphicsContext3D::STENCIL_ATTACHMENT, textarget, textureObject, level);
+ break;
+ case GraphicsContext3D::DEPTH_ATTACHMENT:
+ m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
+ break;
+ case GraphicsContext3D::STENCIL_ATTACHMENT:
+ m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
+ break;
+ default:
+ m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
+ }
m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, textarget, texture, level);
+ applyStencilTest();
cleanupAfterGraphicsCall(false);
}
@@ -2150,6 +2152,9 @@ void WebGLRenderingContext::generateMipmap(GC3Denum target)
synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "generateMipmap", "level 0 not power of 2 or not all the same size");
return;
}
+ if (!validateSettableTexFormat("generateMipmap", tex->getInternalFormat(target, 0)))
+ return;
+
// generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR
// on Mac. Remove the hack once this driver bug is fixed.
#if OS(DARWIN)
@@ -2325,7 +2330,14 @@ WebGLExtension* WebGLRenderingContext::getExtension(const String& name)
m_webglCompressedTextureS3TC = WebGLCompressedTextureS3TC::create(this);
return m_webglCompressedTextureS3TC.get();
}
-
+ if (equalIgnoringCase(name, "WEBKIT_WEBGL_depth_texture")
+ && WebGLDepthTexture::supported(graphicsContext3D())) {
+ if (!m_webglDepthTexture) {
+ m_context->getExtensions()->ensureEnabled("GL_CHROMIUM_depth_texture");
+ m_webglDepthTexture = WebGLDepthTexture::create(this);
+ }
+ return m_webglDepthTexture.get();
+ }
if (allowPrivilegedExtensions()) {
if (equalIgnoringCase(name, "WEBGL_debug_renderer_info")) {
if (!m_webglDebugRendererInfo)
@@ -2354,7 +2366,7 @@ WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(GC3Denum t
return WebGLGetInfo();
}
- WebGLSharedObject* object = m_framebufferBinding->getAttachment(attachment);
+ WebGLSharedObject* object = m_framebufferBinding->getAttachmentObject(attachment);
if (!object) {
if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
return WebGLGetInfo(GraphicsContext3D::NONE);
@@ -2445,7 +2457,7 @@ WebGLGetInfo WebGLRenderingContext::getParameter(GC3Denum pname, ExceptionCode&
case GraphicsContext3D::CURRENT_PROGRAM:
return WebGLGetInfo(PassRefPtr<WebGLProgram>(m_currentProgram));
case GraphicsContext3D::DEPTH_BITS:
- if (!m_attributes.depth)
+ if (!m_framebufferBinding && !m_attributes.depth)
return WebGLGetInfo(intZero);
return getIntParameter(pname);
case GraphicsContext3D::DEPTH_CLEAR_VALUE:
@@ -2540,7 +2552,7 @@ WebGLGetInfo WebGLRenderingContext::getParameter(GC3Denum pname, ExceptionCode&
case GraphicsContext3D::STENCIL_BACK_WRITEMASK:
return getUnsignedIntParameter(pname);
case GraphicsContext3D::STENCIL_BITS:
- if (!m_attributes.stencil)
+ if (!m_framebufferBinding && !m_attributes.stencil)
return WebGLGetInfo(intZero);
return getIntParameter(pname);
case GraphicsContext3D::STENCIL_CLEAR_VALUE:
@@ -2809,6 +2821,8 @@ Vector<String> WebGLRenderingContext::getSupportedExtensions()
result.append("WEBKIT_WEBGL_lose_context");
if (WebGLCompressedTextureS3TC::supported(this))
result.append("WEBKIT_WEBGL_compressed_texture_s3tc");
+ if (WebGLDepthTexture::supported(graphicsContext3D()))
+ result.append("WEBKIT_WEBGL_depth_texture");
if (allowPrivilegedExtensions()) {
if (m_context->getExtensions()->supports("GL_ANGLE_translated_shader_source"))
@@ -3501,11 +3515,21 @@ void WebGLRenderingContext::texImage2DBase(GC3Denum target, GC3Dint level, GC3De
}
}
if (!pixels) {
- bool succeed = m_context->texImage2DResourceSafe(target, level, internalformat, width, height,
- border, format, type, m_unpackAlignment);
- if (!succeed)
- return;
+ // Note: Chromium's OpenGL implementation clears textures and isResourceSafe() is therefore true.
+ // For other implementations, if they are using ANGLE_depth_texture, ANGLE depth textures
+ // can not be cleared with texImage2D and must be cleared by binding to an fbo and calling
+ // clear.
+ if (isResourceSafe())
+ m_context->texImage2D(target, level, internalformat, width, height, border, format, type, 0);
+ else {
+ bool succeed = m_context->texImage2DResourceSafe(target, level, internalformat, width, height,
+ border, format, type, m_unpackAlignment);
+ if (!succeed)
+ return;
+ }
} else {
+ if (!validateSettableTexFormat("texImage2D", internalformat))
+ return;
m_context->texImage2D(target, level, internalformat, width, height,
border, format, type, pixels);
}
@@ -3518,6 +3542,8 @@ void WebGLRenderingContext::texImage2DImpl(GC3Denum target, GC3Dint level, GC3De
bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
{
ec = 0;
+ if (!validateSettableTexFormat("texImage2D", internalformat))
+ return;
Vector<uint8_t> data;
if (!m_context->extractImageData(image, format, type, flipY, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE, data)) {
synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "bad image data");
@@ -3535,7 +3561,7 @@ void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum
GC3Dsizei width, GC3Dsizei height, GC3Dint border,
GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
{
- if (isContextLost() || !validateTexFuncData("texImage2D", width, height, format, type, pixels, NullAllowed))
+ if (isContextLost() || !validateTexFuncData("texImage2D", level, width, height, format, type, pixels, NullAllowed))
return;
void* data = pixels ? pixels->baseAddress() : 0;
Vector<uint8_t> tempData;
@@ -3713,6 +3739,8 @@ void WebGLRenderingContext::texSubImage2DBase(GC3Denum target, GC3Dint level, GC
return;
if (!validateSize("texSubImage2D", xoffset, yoffset))
return;
+ if (!validateSettableTexFormat("texSubImage2D", format))
+ return;
WebGLTexture* tex = validateTextureBinding("texSubImage2D", target, true);
if (!tex)
return;
@@ -3752,7 +3780,7 @@ void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Din
GC3Dsizei width, GC3Dsizei height,
GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
{
- if (isContextLost() || !validateTexFuncData("texSubImage2D", width, height, format, type, pixels, NullNotAllowed))
+ if (isContextLost() || !validateTexFuncData("texSubImage2D", level, width, height, format, type, pixels, NullNotAllowed))
return;
void* data = pixels->baseAddress();
Vector<uint8_t> tempData;
@@ -4583,20 +4611,9 @@ void WebGLRenderingContext::createFallbackBlackTextures1x1()
bool WebGLRenderingContext::isTexInternalFormatColorBufferCombinationValid(GC3Denum texInternalFormat,
GC3Denum colorBufferFormat)
{
- switch (colorBufferFormat) {
- case GraphicsContext3D::ALPHA:
- if (texInternalFormat == GraphicsContext3D::ALPHA)
- return true;
- break;
- case GraphicsContext3D::RGB:
- if (texInternalFormat == GraphicsContext3D::LUMINANCE
- || texInternalFormat == GraphicsContext3D::RGB)
- return true;
- break;
- case GraphicsContext3D::RGBA:
- return true;
- }
- return false;
+ unsigned need = GraphicsContext3D::getChannelBitsByFormat(texInternalFormat);
+ unsigned have = GraphicsContext3D::getChannelBitsByFormat(colorBufferFormat);
+ return (need & have) == need;
}
GC3Denum WebGLRenderingContext::getBoundFramebufferColorFormat()
@@ -4687,7 +4704,7 @@ bool WebGLRenderingContext::validateString(const char* functionName, const Strin
return true;
}
-bool WebGLRenderingContext::validateTexFuncFormatAndType(const char* functionName, GC3Denum format, GC3Denum type)
+bool WebGLRenderingContext::validateTexFuncFormatAndType(const char* functionName, GC3Denum format, GC3Denum type, GC3Dint level)
{
switch (format) {
case GraphicsContext3D::ALPHA:
@@ -4696,6 +4713,11 @@ bool WebGLRenderingContext::validateTexFuncFormatAndType(const char* functionNam
case GraphicsContext3D::RGB:
case GraphicsContext3D::RGBA:
break;
+ case GraphicsContext3D::DEPTH_COMPONENT:
+ if (m_webglDepthTexture)
+ break;
+ synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "DEPTH_COMPONENT texture format not enabled");
+ return false;
default:
synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture format");
return false;
@@ -4712,6 +4734,12 @@ bool WebGLRenderingContext::validateTexFuncFormatAndType(const char* functionNam
break;
synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture type");
return false;
+ case GraphicsContext3D::UNSIGNED_INT:
+ case GraphicsContext3D::UNSIGNED_SHORT:
+ if (m_webglDepthTexture)
+ break;
+ synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture type");
+ return false;
default:
synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid texture type");
return false;
@@ -4745,6 +4773,21 @@ bool WebGLRenderingContext::validateTexFuncFormatAndType(const char* functionNam
return false;
}
break;
+ case GraphicsContext3D::DEPTH_COMPONENT:
+ if (!m_webglDepthTexture) {
+ synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid format. DEPTH_COMPONENT not enabled");
+ return false;
+ }
+ if (type != GraphicsContext3D::UNSIGNED_SHORT
+ && type != GraphicsContext3D::UNSIGNED_INT) {
+ synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "invalid type for DEPTH_COMPONENT format");
+ return false;
+ }
+ if (level > 0) {
+ synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "level must be 0 for DEPTH_COMPONENT format");
+ return false;
+ }
+ break;
default:
ASSERT_NOT_REACHED();
}
@@ -4791,7 +4834,7 @@ bool WebGLRenderingContext::validateTexFuncParameters(const char* functionName,
// We absolutely have to validate the format and type combination.
// The texImage2D entry points taking HTMLImage, etc. will produce
// temporary data based on this combination, so it must be legal.
- if (!validateTexFuncFormatAndType(functionName, format, type) || !validateTexFuncLevel(functionName, target, level))
+ if (!validateTexFuncFormatAndType(functionName, format, type, level) || !validateTexFuncLevel(functionName, target, level))
return false;
if (width < 0 || height < 0) {
@@ -4835,7 +4878,7 @@ bool WebGLRenderingContext::validateTexFuncParameters(const char* functionName,
return true;
}
-bool WebGLRenderingContext::validateTexFuncData(const char* functionName,
+bool WebGLRenderingContext::validateTexFuncData(const char* functionName, GC3Dint level,
GC3Dsizei width, GC3Dsizei height,
GC3Denum format, GC3Denum type,
ArrayBufferView* pixels,
@@ -4848,7 +4891,9 @@ bool WebGLRenderingContext::validateTexFuncData(const char* functionName,
return false;
}
- if (!validateTexFuncFormatAndType(functionName, format, type))
+ if (!validateTexFuncFormatAndType(functionName, format, type, level))
+ return false;
+ if (!validateSettableTexFormat(functionName, format))
return false;
switch (type) {
diff --git a/Source/WebCore/html/canvas/WebGLRenderingContext.h b/Source/WebCore/html/canvas/WebGLRenderingContext.h
index 548a999b1..e4c3f74cd 100644
--- a/Source/WebCore/html/canvas/WebGLRenderingContext.h
+++ b/Source/WebCore/html/canvas/WebGLRenderingContext.h
@@ -57,6 +57,7 @@ class WebGLCompressedTextureS3TC;
class WebGLContextAttributes;
class WebGLDebugRendererInfo;
class WebGLDebugShaders;
+class WebGLDepthTexture;
class WebGLExtension;
class WebGLFramebuffer;
class WebGLLoseContext;
@@ -506,6 +507,7 @@ public:
OwnPtr<WebGLDebugRendererInfo> m_webglDebugRendererInfo;
OwnPtr<WebGLDebugShaders> m_webglDebugShaders;
OwnPtr<WebGLCompressedTextureS3TC> m_webglCompressedTextureS3TC;
+ OwnPtr<WebGLDepthTexture> m_webglDepthTexture;
// Helpers for getParameter and others
WebGLGetInfo getBooleanParameter(GC3Denum);
@@ -574,7 +576,7 @@ public:
// Helper function to check input format/type for functions {copy}Tex{Sub}Image.
// Generates GL error and returns false if parameters are invalid.
- bool validateTexFuncFormatAndType(const char* functionName, GC3Denum format, GC3Denum type);
+ bool validateTexFuncFormatAndType(const char* functionName, GC3Denum format, GC3Denum type, GC3Dint level);
// Helper function to check input level for functions {copy}Tex{Sub}Image.
// Generates GL error and returns false if level is invalid.
@@ -596,12 +598,18 @@ public:
// Helper function to validate that the given ArrayBufferView
// is of the correct type and contains enough data for the texImage call.
// Generates GL error and returns false if parameters are invalid.
- bool validateTexFuncData(const char* functionName,
+ bool validateTexFuncData(const char* functionName, GC3Dint level,
GC3Dsizei width, GC3Dsizei height,
GC3Denum format, GC3Denum type,
ArrayBufferView* pixels,
NullDisposition);
+ // Helper function to validate a given texture format is settable as in
+ // you can supply data to texImage2D, or call texImage2D, copyTexImage2D and
+ // copyTexSubImage2D.
+ // Generates GL error and returns false if the format is not settable.
+ bool validateSettableTexFormat(const char* functionName, GC3Denum format);
+
// Helper function to validate compressed texture data is correct size
// for the given format and dimensions.
bool validateCompressedTexFuncData(const char* functionName,
diff --git a/Source/WebCore/html/parser/HTMLConstructionSite.h b/Source/WebCore/html/parser/HTMLConstructionSite.h
index 27906643b..367c0fe26 100644
--- a/Source/WebCore/html/parser/HTMLConstructionSite.h
+++ b/Source/WebCore/html/parser/HTMLConstructionSite.h
@@ -75,6 +75,7 @@ enum WhitespaceMode {
class AtomicHTMLToken;
class Document;
class Element;
+class HTMLFormElement;
class HTMLConstructionSite {
WTF_MAKE_NONCOPYABLE(HTMLConstructionSite);
diff --git a/Source/WebCore/html/parser/HTMLParserIdioms.cpp b/Source/WebCore/html/parser/HTMLParserIdioms.cpp
index a99a21a08..c3becc360 100644
--- a/Source/WebCore/html/parser/HTMLParserIdioms.cpp
+++ b/Source/WebCore/html/parser/HTMLParserIdioms.cpp
@@ -25,6 +25,7 @@
#include "config.h"
#include "HTMLParserIdioms.h"
+#include "Decimal.h"
#include <limits>
#include <wtf/MathExtras.h>
#include <wtf/dtoa.h>
@@ -58,6 +59,15 @@ String stripLeadingAndTrailingHTMLSpaces(const String& string)
return string.substring(numLeadingSpaces, length - (numLeadingSpaces + numTrailingSpaces));
}
+String serializeForNumberType(const Decimal& number)
+{
+ if (number.isZero()) {
+ // Decimal::toString appends exponent, e.g. "0e-18"
+ return number.isNegative() ? "-0" : "0";
+ }
+ return number.toString();
+}
+
String serializeForNumberType(double number)
{
// According to HTML5, "the best representation of the number n as a floating
@@ -66,6 +76,35 @@ String serializeForNumberType(double number)
return String(numberToString(number, buffer));
}
+Decimal parseToDecimalForNumberType(const String& string, const Decimal& fallbackValue)
+{
+ // See HTML5 2.5.4.3 `Real numbers.' and parseToDoubleForNumberType
+
+ // String::toDouble() accepts leading + and whitespace characters, which are not valid here.
+ const UChar firstCharacter = string[0];
+ if (firstCharacter != '-' && firstCharacter != '.' && !isASCIIDigit(firstCharacter))
+ return fallbackValue;
+
+ const Decimal value = Decimal::fromString(string);
+ if (!value.isFinite())
+ return fallbackValue;
+
+ // Numbers are considered finite IEEE 754 single-precision floating point values.
+ // See HTML5 2.5.4.3 `Real numbers.'
+ // FIXME: We should use numeric_limits<double>::max for number input type.
+ const Decimal floatMax = Decimal::fromDouble(std::numeric_limits<float>::max());
+ if (value < -floatMax || value > floatMax)
+ return fallbackValue;
+
+ // We return +0 for -0 case.
+ return value.isZero() ? Decimal(0) : value;
+}
+
+Decimal parseToDecimalForNumberType(const String& string)
+{
+ return parseToDecimalForNumberType(string, Decimal::nan());
+}
+
double parseToDoubleForNumberType(const String& string, double fallbackValue)
{
// See HTML5 2.5.4.3 `Real numbers.'
diff --git a/Source/WebCore/html/parser/HTMLParserIdioms.h b/Source/WebCore/html/parser/HTMLParserIdioms.h
index 8a774f9ee..5f0186d44 100644
--- a/Source/WebCore/html/parser/HTMLParserIdioms.h
+++ b/Source/WebCore/html/parser/HTMLParserIdioms.h
@@ -30,6 +30,8 @@
namespace WebCore {
+class Decimal;
+
// Space characters as defined by the HTML specification.
bool isHTMLSpace(UChar);
bool isHTMLLineBreak(UChar);
@@ -39,11 +41,14 @@ bool isNotHTMLSpace(UChar);
String stripLeadingAndTrailingHTMLSpaces(const String&);
// An implementation of the HTML specification's algorithm to convert a number to a string for number and range types.
+String serializeForNumberType(const Decimal&);
String serializeForNumberType(double);
-// Convert the specified string to a double. If the conversion fails, the return value is false.
+// Convert the specified string to a decimal/double. If the conversion fails, the return value is fallback value or NaN if not specified.
// Leading or trailing illegal characters cause failure, as does passing an empty string.
// The double* parameter may be 0 to check if the string can be parsed without getting the result.
+Decimal parseToDecimalForNumberType(const String&);
+Decimal parseToDecimalForNumberType(const String&, const Decimal& fallbackValue);
double parseToDoubleForNumberType(const String&);
double parseToDoubleForNumberType(const String&, double fallbackValue);
double parseToDoubleForNumberTypeWithDecimalPlaces(const String&, unsigned*);
diff --git a/Source/WebCore/html/parser/HTMLParserScheduler.cpp b/Source/WebCore/html/parser/HTMLParserScheduler.cpp
index 2692036f3..a9dd24af6 100644
--- a/Source/WebCore/html/parser/HTMLParserScheduler.cpp
+++ b/Source/WebCore/html/parser/HTMLParserScheduler.cpp
@@ -95,6 +95,7 @@ void HTMLParserScheduler::checkForYieldBeforeScript(PumpSession& session)
bool needsFirstPaint = document->view() && !document->view()->hasEverPainted();
if (needsFirstPaint && document->isLayoutTimerActive())
session.needsYield = true;
+ session.didSeeScript = true;
}
void HTMLParserScheduler::scheduleForResume()
diff --git a/Source/WebCore/html/parser/HTMLParserScheduler.h b/Source/WebCore/html/parser/HTMLParserScheduler.h
index b0e2e85f0..e52f3ef3c 100644
--- a/Source/WebCore/html/parser/HTMLParserScheduler.h
+++ b/Source/WebCore/html/parser/HTMLParserScheduler.h
@@ -47,12 +47,14 @@ public:
, processedTokens(INT_MAX)
, startTime(0)
, needsYield(false)
+ , didSeeScript(false)
{
}
int processedTokens;
double startTime;
bool needsYield;
+ bool didSeeScript;
};
class HTMLParserScheduler {
@@ -67,13 +69,15 @@ public:
// Inline as this is called after every token in the parser.
void checkForYieldBeforeToken(PumpSession& session)
{
- if (session.processedTokens > m_parserChunkSize) {
+ if (session.processedTokens > m_parserChunkSize || session.didSeeScript) {
// currentTime() can be expensive. By delaying, we avoided calling
// currentTime() when constructing non-yielding PumpSessions.
if (!session.startTime)
session.startTime = currentTime();
session.processedTokens = 0;
+ session.didSeeScript = false;
+
double elapsedTime = currentTime() - session.startTime;
if (elapsedTime > m_parserTimeLimit)
session.needsYield = true;
diff --git a/Source/WebCore/html/shadow/CalendarPickerElement.cpp b/Source/WebCore/html/shadow/CalendarPickerElement.cpp
index 1a7b49fa6..5358ccaf7 100644
--- a/Source/WebCore/html/shadow/CalendarPickerElement.cpp
+++ b/Source/WebCore/html/shadow/CalendarPickerElement.cpp
@@ -208,7 +208,7 @@ void CalendarPickerElement::writeDocument(DocumentWriter& writer)
String minString = date.toString();
date.setMillisecondsSinceEpochForDate(input->maximum());
String maxString = date.toString();
- double step;
+ Decimal step;
String stepString = input->fastGetAttribute(stepAttr);
if (stepString.isEmpty() || !input->getAllowedValueStep(&step))
stepString = "1";
diff --git a/Source/WebCore/html/shadow/HTMLContentElement.cpp b/Source/WebCore/html/shadow/HTMLContentElement.cpp
index 08b45d4ab..b0bdd885f 100644
--- a/Source/WebCore/html/shadow/HTMLContentElement.cpp
+++ b/Source/WebCore/html/shadow/HTMLContentElement.cpp
@@ -29,7 +29,7 @@
#include "ContentDistributor.h"
#include "ContentSelectorQuery.h"
-#include "ContextEnabledFeatures.h"
+#include "ContextFeatures.h"
#include "ElementShadow.h"
#include "HTMLNames.h"
#include "QualifiedName.h"
@@ -43,7 +43,7 @@ using HTMLNames::selectAttr;
static const QualifiedName& contentTagName(Document* document)
{
#if ENABLE(SHADOW_DOM)
- if (!ContextEnabledFeatures::shadowDOMEnabled(document->domWindow()))
+ if (!ContextFeatures::shadowDOMEnabled(document))
return HTMLNames::webkitShadowContentTag;
return HTMLNames::contentTag;
#else
diff --git a/Source/WebCore/html/shadow/InsertionPoint.cpp b/Source/WebCore/html/shadow/InsertionPoint.cpp
index 1ca1e3101..580512862 100644
--- a/Source/WebCore/html/shadow/InsertionPoint.cpp
+++ b/Source/WebCore/html/shadow/InsertionPoint.cpp
@@ -49,8 +49,11 @@ void InsertionPoint::attach()
{
if (ShadowRoot* root = shadowRoot())
root->owner()->ensureDistribution();
- for (size_t i = 0; i < m_distribution.size(); ++i)
- m_distribution.at(i)->attach();
+ for (size_t i = 0; i < m_distribution.size(); ++i) {
+ if (!m_distribution.at(i)->attached())
+ m_distribution.at(i)->attach();
+ }
+
HTMLElement::attach();
}
@@ -60,6 +63,7 @@ void InsertionPoint::detach()
root->owner()->ensureDistribution();
for (size_t i = 0; i < m_distribution.size(); ++i)
m_distribution.at(i)->detach();
+
HTMLElement::detach();
}
diff --git a/Source/WebCore/html/shadow/InsertionPoint.h b/Source/WebCore/html/shadow/InsertionPoint.h
index f46d3d482..98ca15486 100644
--- a/Source/WebCore/html/shadow/InsertionPoint.h
+++ b/Source/WebCore/html/shadow/InsertionPoint.h
@@ -57,6 +57,7 @@ public:
virtual bool isInsertionPoint() const OVERRIDE { return true; }
size_t indexOf(Node* node) const { return m_distribution.find(node); }
+ bool contains(const Node* node) const { return m_distribution.contains(const_cast<Node*>(node)); }
size_t size() const { return m_distribution.size(); }
Node* at(size_t index) const { return m_distribution.at(index).get(); }
Node* first() const { return m_distribution.isEmpty() ? 0 : m_distribution.first().get(); }
diff --git a/Source/WebCore/html/shadow/MediaControlElements.cpp b/Source/WebCore/html/shadow/MediaControlElements.cpp
index 212048ab2..236384f16 100644
--- a/Source/WebCore/html/shadow/MediaControlElements.cpp
+++ b/Source/WebCore/html/shadow/MediaControlElements.cpp
@@ -901,6 +901,7 @@ const AtomicString& MediaControlTimelineElement::shadowPseudoId() const
inline MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(Document* document)
: MediaControlInputElement(document, MediaVolumeSlider)
+ , m_clearMutedOnUserInteraction(false)
{
}
@@ -934,6 +935,8 @@ void MediaControlVolumeSliderElement::defaultEventHandler(Event* event)
mediaController()->setVolume(volume, ec);
ASSERT(!ec);
}
+ if (m_clearMutedOnUserInteraction)
+ mediaController()->setMuted(false);
}
void MediaControlVolumeSliderElement::setVolume(float volume)
@@ -942,6 +945,11 @@ void MediaControlVolumeSliderElement::setVolume(float volume)
setValue(String::number(volume));
}
+void MediaControlVolumeSliderElement::setClearMutedOnUserInteraction(bool clearMute)
+{
+ m_clearMutedOnUserInteraction = clearMute;
+}
+
const AtomicString& MediaControlVolumeSliderElement::shadowPseudoId() const
{
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider"));
@@ -973,9 +981,8 @@ const AtomicString& MediaControlFullscreenVolumeSliderElement::shadowPseudoId()
// ----------------------------
-inline MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(Document* document, MediaControls* controls)
+inline MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(Document* document, MediaControls*)
: MediaControlInputElement(document, MediaEnterFullscreenButton)
- , m_controls(controls)
{
}
diff --git a/Source/WebCore/html/shadow/MediaControlElements.h b/Source/WebCore/html/shadow/MediaControlElements.h
index 03570f755..efdb21f0d 100644
--- a/Source/WebCore/html/shadow/MediaControlElements.h
+++ b/Source/WebCore/html/shadow/MediaControlElements.h
@@ -389,12 +389,14 @@ public:
virtual void defaultEventHandler(Event*);
void setVolume(float);
+ void setClearMutedOnUserInteraction(bool);
protected:
MediaControlVolumeSliderElement(Document*);
private:
virtual const AtomicString& shadowPseudoId() const;
+ bool m_clearMutedOnUserInteraction;
};
// ----------------------------
@@ -410,8 +412,6 @@ private:
MediaControlFullscreenButtonElement(Document*, MediaControls*);
virtual const AtomicString& shadowPseudoId() const;
-
- MediaControls* m_controls;
};
// ----------------------------
diff --git a/Source/WebCore/html/shadow/MediaControlRootElementChromium.cpp b/Source/WebCore/html/shadow/MediaControlRootElementChromium.cpp
index bdcd9164d..f4ce3d617 100644
--- a/Source/WebCore/html/shadow/MediaControlRootElementChromium.cpp
+++ b/Source/WebCore/html/shadow/MediaControlRootElementChromium.cpp
@@ -29,6 +29,7 @@
#if ENABLE(VIDEO)
#include "MediaControlRootElementChromium.h"
+#include "HTMLDivElement.h"
#include "HTMLMediaElement.h"
#include "HTMLNames.h"
#include "MediaControlElements.h"
@@ -45,23 +46,46 @@ using namespace std;
namespace WebCore {
+static const double timeWithoutMouseMovementBeforeHidingControls = 2;
+
+MediaControlChromiumEnclosureElement::MediaControlChromiumEnclosureElement(Document* document)
+ : HTMLDivElement(HTMLNames::divTag, document->document())
+ , m_mediaController(0)
+{
+}
+
+PassRefPtr<MediaControlChromiumEnclosureElement> MediaControlChromiumEnclosureElement::create(Document* document)
+{
+ return adoptRef(new MediaControlChromiumEnclosureElement(document));
+}
+
+const AtomicString& MediaControlChromiumEnclosureElement::shadowPseudoId() const
+{
+ DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-enclosure"));
+ return id;
+}
+
MediaControlRootElementChromium::MediaControlRootElementChromium(Document* document)
: MediaControls(document)
, m_mediaController(0)
, m_playButton(0)
, m_currentTimeDisplay(0)
+ , m_durationDisplay(0)
, m_timeline(0)
- , m_timelineContainer(0)
, m_panelMuteButton(0)
, m_volumeSlider(0)
- , m_volumeSliderContainer(0)
+#if ENABLE(FULLSCREEN_MEDIA_CONTROLS)
+ , m_fullscreenButton(0)
+#endif
, m_panel(0)
+ , m_enclosure(0)
#if ENABLE(VIDEO_TRACK)
, m_textDisplayContainer(0)
- , m_textTrackDisplay(0)
#endif
, m_opaque(true)
+ , m_hideFullscreenControlsTimer(this, &MediaControlRootElementChromium::hideFullscreenControlsTimerFired)
, m_isMouseOverControls(false)
+ , m_isFullscreen(false)
{
}
@@ -77,6 +101,9 @@ PassRefPtr<MediaControlRootElementChromium> MediaControlRootElementChromium::cre
RefPtr<MediaControlRootElementChromium> controls = adoptRef(new MediaControlRootElementChromium(document));
+ // Create an enclosing element for the panel so we can visually offset the controls correctly.
+ RefPtr<MediaControlChromiumEnclosureElement> enclosure = MediaControlChromiumEnclosureElement::create(document);
+
RefPtr<MediaControlPanelElement> panel = MediaControlPanelElement::create(document);
ExceptionCode ec;
@@ -87,52 +114,53 @@ PassRefPtr<MediaControlRootElementChromium> MediaControlRootElementChromium::cre
if (ec)
return 0;
- RefPtr<MediaControlTimelineContainerElement> timelineContainer = MediaControlTimelineContainerElement::create(document);
-
RefPtr<MediaControlTimelineElement> timeline = MediaControlTimelineElement::create(document, controls.get());
controls->m_timeline = timeline.get();
- timelineContainer->appendChild(timeline.release(), ec, true);
+ panel->appendChild(timeline.release(), ec, true);
if (ec)
return 0;
RefPtr<MediaControlCurrentTimeDisplayElement> currentTimeDisplay = MediaControlCurrentTimeDisplayElement::create(document);
controls->m_currentTimeDisplay = currentTimeDisplay.get();
- timelineContainer->appendChild(currentTimeDisplay.release(), ec, true);
+ controls->m_currentTimeDisplay->hide();
+ panel->appendChild(currentTimeDisplay.release(), ec, true);
if (ec)
return 0;
- controls->m_timelineContainer = timelineContainer.get();
- panel->appendChild(timelineContainer.release(), ec, true);
+ RefPtr<MediaControlTimeRemainingDisplayElement> durationDisplay = MediaControlTimeRemainingDisplayElement::create(document);
+ controls->m_durationDisplay = durationDisplay.get();
+ panel->appendChild(durationDisplay.release(), ec, true);
if (ec)
return 0;
- RefPtr<HTMLDivElement> panelVolumeControlContainer = HTMLDivElement::create(document);
-
- RefPtr<MediaControlVolumeSliderContainerElement> volumeSliderContainer = MediaControlVolumeSliderContainerElement::create(document);
+ RefPtr<MediaControlPanelMuteButtonElement> panelMuteButton = MediaControlPanelMuteButtonElement::create(document, controls.get());
+ controls->m_panelMuteButton = panelMuteButton.get();
+ panel->appendChild(panelMuteButton.release(), ec, true);
+ if (ec)
+ return 0;
RefPtr<MediaControlVolumeSliderElement> slider = MediaControlVolumeSliderElement::create(document);
controls->m_volumeSlider = slider.get();
- volumeSliderContainer->appendChild(slider.release(), ec, true);
+ controls->m_volumeSlider->setClearMutedOnUserInteraction(true);
+ panel->appendChild(slider.release(), ec, true);
if (ec)
return 0;
- controls->m_volumeSliderContainer = volumeSliderContainer.get();
- panelVolumeControlContainer->appendChild(volumeSliderContainer.release(), ec, true);
- if (ec)
- return 0;
-
- RefPtr<MediaControlPanelMuteButtonElement> panelMuteButton = MediaControlPanelMuteButtonElement::create(document, controls.get());
- controls->m_panelMuteButton = panelMuteButton.get();
- panelVolumeControlContainer->appendChild(panelMuteButton.release(), ec, true);
+#if ENABLE(FULLSCREEN_MEDIA_CONTROLS)
+ RefPtr<MediaControlFullscreenButtonElement> fullscreenButton = MediaControlFullscreenButtonElement::create(document, controls.get());
+ controls->m_fullscreenButton = fullscreenButton.get();
+ panel->appendChild(fullscreenButton.release(), ec, true);
if (ec)
return 0;
+#endif
- panel->appendChild(panelVolumeControlContainer, ec, true);
+ controls->m_panel = panel.get();
+ enclosure->appendChild(panel.release(), ec, true);
if (ec)
return 0;
- controls->m_panel = panel.get();
- controls->appendChild(panel.release(), ec, true);
+ controls->m_enclosure = enclosure.get();
+ controls->appendChild(enclosure.release(), ec, true);
if (ec)
return 0;
@@ -149,18 +177,22 @@ void MediaControlRootElementChromium::setMediaController(MediaControllerInterfac
m_playButton->setMediaController(controller);
if (m_currentTimeDisplay)
m_currentTimeDisplay->setMediaController(controller);
+ if (m_durationDisplay)
+ m_durationDisplay->setMediaController(controller);
if (m_timeline)
m_timeline->setMediaController(controller);
- if (m_timelineContainer)
- m_timelineContainer->setMediaController(controller);
if (m_panelMuteButton)
m_panelMuteButton->setMediaController(controller);
if (m_volumeSlider)
m_volumeSlider->setMediaController(controller);
- if (m_volumeSliderContainer)
- m_volumeSliderContainer->setMediaController(controller);
+#if ENABLE(FULLSCREEN_MEDIA_CONTROLS)
+ if (m_fullscreenButton)
+ m_fullscreenButton->setMediaController(controller);
+#endif
if (m_panel)
m_panel->setMediaController(controller);
+ if (m_enclosure)
+ m_enclosure->setMediaController(controller);
#if ENABLE(VIDEO_TRACK)
if (m_textDisplayContainer)
m_textDisplayContainer->setMediaController(controller);
@@ -178,7 +210,6 @@ void MediaControlRootElementChromium::hide()
{
m_panel->setIsDisplayed(false);
m_panel->hide();
- m_volumeSliderContainer->hide();
}
void MediaControlRootElementChromium::makeOpaque()
@@ -189,7 +220,6 @@ void MediaControlRootElementChromium::makeOpaque()
void MediaControlRootElementChromium::makeTransparent()
{
m_panel->makeTransparent();
- m_volumeSliderContainer->hide();
}
void MediaControlRootElementChromium::reset()
@@ -202,7 +232,11 @@ void MediaControlRootElementChromium::reset()
float duration = m_mediaController->duration();
m_timeline->setDuration(duration);
- m_timelineContainer->show();
+ m_timeline->show();
+
+ m_durationDisplay->setInnerText(page->theme()->formatMediaControlsTime(duration), ASSERT_NO_EXCEPTION);
+ m_durationDisplay->setCurrentValue(duration);
+
m_timeline->setPosition(m_mediaController->currentTime());
updateTimeDisplay();
@@ -211,6 +245,9 @@ void MediaControlRootElementChromium::reset()
if (m_volumeSlider)
m_volumeSlider->setVolume(m_mediaController->volume());
+#if ENABLE(FULLSCREEN_MEDIA_CONTROLS)
+ m_fullscreenButton->show();
+#endif
makeOpaque();
}
@@ -218,7 +255,12 @@ void MediaControlRootElementChromium::playbackStarted()
{
m_playButton->updateDisplayType();
m_timeline->setPosition(m_mediaController->currentTime());
+ m_currentTimeDisplay->show();
+ m_durationDisplay->hide();
updateTimeDisplay();
+
+ if (m_isFullscreen)
+ startHideFullscreenControlsTimer();
}
void MediaControlRootElementChromium::playbackProgressed()
@@ -236,6 +278,8 @@ void MediaControlRootElementChromium::playbackStopped()
m_timeline->setPosition(m_mediaController->currentTime());
updateTimeDisplay();
makeOpaque();
+
+ stopHideFullscreenControlsTimer();
}
void MediaControlRootElementChromium::updateTimeDisplay()
@@ -247,6 +291,12 @@ void MediaControlRootElementChromium::updateTimeDisplay()
if (!page)
return;
+ // After seek, hide duration display and show current time.
+ if (now > 0) {
+ m_currentTimeDisplay->show();
+ m_durationDisplay->hide();
+ }
+
// Allow the theme to format the time.
ExceptionCode ec;
m_currentTimeDisplay->setInnerText(page->theme()->formatMediaControlsCurrentTime(now, duration), ec);
@@ -259,9 +309,12 @@ void MediaControlRootElementChromium::reportedError()
if (!page)
return;
- m_timelineContainer->hide();
+ m_timeline->hide();
m_panelMuteButton->hide();
- m_volumeSliderContainer->hide();
+ m_volumeSlider->hide();
+#if ENABLE(FULLSCREEN_MEDIA_CONTROLS)
+ m_fullscreenButton->hide();
+#endif
}
void MediaControlRootElementChromium::updateStatusDisplay()
@@ -295,15 +348,55 @@ void MediaControlRootElementChromium::defaultEventHandler(Event* event)
if (event->type() == eventNames().mouseoverEvent) {
if (!containsRelatedTarget(event)) {
m_isMouseOverControls = true;
- if (!m_mediaController->canPlay())
+ if (!m_mediaController->canPlay()) {
makeOpaque();
+ if (shouldHideControls())
+ startHideFullscreenControlsTimer();
+ }
}
} else if (event->type() == eventNames().mouseoutEvent) {
- if (!containsRelatedTarget(event))
+ if (!containsRelatedTarget(event)) {
m_isMouseOverControls = false;
+ stopHideFullscreenControlsTimer();
+ }
+ } else if (event->type() == eventNames().mousemoveEvent) {
+ if (m_isFullscreen) {
+ // When we get a mouse move in fullscreen mode, show the media controls, and start a timer
+ // that will hide the media controls after a 2 seconds without a mouse move.
+ makeOpaque();
+ if (shouldHideControls())
+ startHideFullscreenControlsTimer();
+ }
}
}
+void MediaControlRootElementChromium::startHideFullscreenControlsTimer()
+{
+ if (!m_isFullscreen)
+ return;
+
+ m_hideFullscreenControlsTimer.startOneShot(timeWithoutMouseMovementBeforeHidingControls);
+}
+
+void MediaControlRootElementChromium::hideFullscreenControlsTimerFired(Timer<MediaControlRootElementChromium>*)
+{
+ if (m_mediaController->paused())
+ return;
+
+ if (!m_isFullscreen)
+ return;
+
+ if (!shouldHideControls())
+ return;
+
+ makeTransparent();
+}
+
+void MediaControlRootElementChromium::stopHideFullscreenControlsTimer()
+{
+ m_hideFullscreenControlsTimer.stop();
+}
+
void MediaControlRootElementChromium::changedClosedCaptionsVisibility()
{
}
@@ -311,6 +404,11 @@ void MediaControlRootElementChromium::changedClosedCaptionsVisibility()
void MediaControlRootElementChromium::changedMute()
{
m_panelMuteButton->changedMute();
+
+ if (m_mediaController->muted())
+ m_volumeSlider->setVolume(0);
+ else
+ m_volumeSlider->setVolume(m_mediaController->volume());
}
void MediaControlRootElementChromium::changedVolume()
@@ -320,10 +418,16 @@ void MediaControlRootElementChromium::changedVolume()
void MediaControlRootElementChromium::enteredFullscreen()
{
+ m_isFullscreen = true;
+ m_fullscreenButton->setIsFullscreen(true);
+ startHideFullscreenControlsTimer();
}
void MediaControlRootElementChromium::exitedFullscreen()
{
+ m_isFullscreen = false;
+ m_fullscreenButton->setIsFullscreen(false);
+ stopHideFullscreenControlsTimer();
}
void MediaControlRootElementChromium::showVolumeSlider()
@@ -331,7 +435,7 @@ void MediaControlRootElementChromium::showVolumeSlider()
if (!m_mediaController->hasAudio())
return;
- m_volumeSliderContainer->show();
+ m_volumeSlider->show();
}
#if ENABLE(VIDEO_TRACK)
@@ -344,8 +448,7 @@ void MediaControlRootElementChromium::createTextTrackDisplay()
m_textDisplayContainer = textDisplayContainer.get();
// Insert it before the first controller element so it always displays behind the controls.
- ExceptionCode ec;
- insertBefore(textDisplayContainer.release(), m_panel, ec, true);
+ insertBefore(textDisplayContainer.release(), m_enclosure, ASSERT_NO_EXCEPTION, true);
}
void MediaControlRootElementChromium::showTextTrackDisplay()
diff --git a/Source/WebCore/html/shadow/MediaControlRootElementChromium.h b/Source/WebCore/html/shadow/MediaControlRootElementChromium.h
index 366186b65..f10b728e8 100644
--- a/Source/WebCore/html/shadow/MediaControlRootElementChromium.h
+++ b/Source/WebCore/html/shadow/MediaControlRootElementChromium.h
@@ -40,6 +40,7 @@ class Event;
class MediaControlPanelMuteButtonElement;
class MediaControlPlayButtonElement;
class MediaControlCurrentTimeDisplayElement;
+class MediaControlTimeRemainingDisplayElement;
class MediaControlTimelineElement;
class MediaControlVolumeSliderElement;
class MediaControlFullscreenButtonElement;
@@ -47,8 +48,8 @@ class MediaControlTimeDisplayElement;
class MediaControlTimelineContainerElement;
class MediaControlMuteButtonElement;
class MediaControlVolumeSliderElement;
-class MediaControlVolumeSliderContainerElement;
class MediaControlPanelElement;
+class MediaControlChromiumEnclosureElement;
class MediaControllerInterface;
class MediaPlayer;
@@ -60,6 +61,24 @@ class MediaControlTextTrackContainerElement;
class MediaControlTextTrackDisplayElement;
#endif
+class MediaControlChromiumEnclosureElement : public HTMLDivElement {
+public:
+ static PassRefPtr<MediaControlChromiumEnclosureElement> create(Document*);
+
+ virtual const AtomicString& shadowPseudoId() const;
+
+ void setMediaController(MediaControllerInterface* controller) { m_mediaController = controller; }
+ MediaControllerInterface* mediaController() const { return m_mediaController; }
+
+protected:
+ MediaControlChromiumEnclosureElement(Document*);
+
+private:
+ virtual bool isMediaControlElement() const { return true; }
+
+ MediaControllerInterface* m_mediaController;
+};
+
class MediaControlRootElementChromium : public MediaControls {
public:
static PassRefPtr<MediaControlRootElementChromium> create(Document*);
@@ -107,6 +126,9 @@ private:
MediaControlRootElementChromium(Document*);
virtual void defaultEventHandler(Event*);
+ void hideFullscreenControlsTimerFired(Timer<MediaControlRootElementChromium>*);
+ void startHideFullscreenControlsTimer();
+ void stopHideFullscreenControlsTimer();
virtual const AtomicString& shadowPseudoId() const;
@@ -116,19 +138,24 @@ private:
MediaControlPlayButtonElement* m_playButton;
MediaControlCurrentTimeDisplayElement* m_currentTimeDisplay;
+ MediaControlTimeRemainingDisplayElement* m_durationDisplay;
MediaControlTimelineElement* m_timeline;
MediaControlTimelineContainerElement* m_timelineContainer;
MediaControlPanelMuteButtonElement* m_panelMuteButton;
MediaControlVolumeSliderElement* m_volumeSlider;
- MediaControlVolumeSliderContainerElement* m_volumeSliderContainer;
+#if ENABLE(FULLSCREEN_MEDIA_CONTROLS)
+ MediaControlFullscreenButtonElement* m_fullscreenButton;
+#endif
MediaControlPanelElement* m_panel;
+ MediaControlChromiumEnclosureElement* m_enclosure;
#if ENABLE(VIDEO_TRACK)
MediaControlTextTrackContainerElement* m_textDisplayContainer;
- MediaControlTextTrackDisplayElement* m_textTrackDisplay;
#endif
bool m_opaque;
+ Timer<MediaControlRootElementChromium> m_hideFullscreenControlsTimer;
bool m_isMouseOverControls;
+ bool m_isFullscreen;
};
}
diff --git a/Source/WebCore/html/shadow/SliderThumbElement.cpp b/Source/WebCore/html/shadow/SliderThumbElement.cpp
index 8422a3019..502dae13f 100644
--- a/Source/WebCore/html/shadow/SliderThumbElement.cpp
+++ b/Source/WebCore/html/shadow/SliderThumbElement.cpp
@@ -51,10 +51,10 @@ using namespace std;
namespace WebCore {
-inline static double sliderPosition(HTMLInputElement* element)
+inline static Decimal sliderPosition(HTMLInputElement* element)
{
const StepRange stepRange(element->createStepRange(RejectAny));
- const double oldValue = parseToDoubleForNumberType(element->value(), stepRange.defaultValue());
+ const Decimal oldValue = parseToDecimalForNumberType(element->value(), stepRange.defaultValue());
return stepRange.proportionFromValue(stepRange.clampValue(oldValue));
}
@@ -62,7 +62,13 @@ inline static bool hasVerticalAppearance(HTMLInputElement* input)
{
ASSERT(input->renderer());
RenderStyle* sliderStyle = input->renderer()->style();
- return sliderStyle->appearance() == SliderVerticalPart || sliderStyle->appearance() == MediaVolumeSliderPart;
+
+#if ENABLE(VIDEO)
+ if (sliderStyle->appearance() == MediaVolumeSliderPart && input->renderer()->theme()->usesVerticalVolumeSlider())
+ return true;
+#endif
+
+ return sliderStyle->appearance() == SliderVerticalPart;
}
SliderThumbElement* sliderThumbElementOf(Node* node)
@@ -95,7 +101,7 @@ void RenderSliderThumb::updateAppearance(RenderStyle* parentStyle)
else if (parentStyle->appearance() == MediaFullScreenVolumeSliderPart)
style()->setAppearance(MediaFullScreenVolumeSliderThumbPart);
if (style()->hasAppearance())
- theme()->adjustSliderThumbSize(style());
+ theme()->adjustSliderThumbSize(style(), toElement(node()));
}
bool RenderSliderThumb::isSliderThumb() const
@@ -108,9 +114,9 @@ void RenderSliderThumb::layout()
// Do not cast node() to SliderThumbElement. This renderer is used for
// TrackLimitElement too.
HTMLInputElement* input = node()->shadowAncestorNode()->toInputElement();
- bool isVertical = style()->appearance() == SliderThumbVerticalPart || style()->appearance() == MediaVolumeSliderThumbPart;
+ bool isVertical = hasVerticalAppearance(input);
- double fraction = sliderPosition(input) * 100;
+ double fraction = (sliderPosition(input) * 100).toDouble();
if (isVertical)
style()->setTop(Length(100 - fraction, Percent));
else if (style()->isLeftToRightDirection())
@@ -236,11 +242,10 @@ void SliderThumbElement::setPositionFromPoint(const LayoutPoint& point)
if (position == currentPosition)
return;
- double fraction = static_cast<double>(position) / trackSize;
- if (isVertical || !renderBox()->style()->isLeftToRightDirection())
- fraction = 1 - fraction;
+ const Decimal ratio = Decimal::fromDouble(static_cast<double>(position) / trackSize);
+ const Decimal fraction = isVertical || !renderBox()->style()->isLeftToRightDirection() ? Decimal(1) - ratio : ratio;
StepRange stepRange(input->createStepRange(RejectAny));
- double value = stepRange.clampValue(stepRange.valueFromProportion(fraction));
+ const Decimal value = stepRange.clampValue(stepRange.valueFromProportion(fraction));
// FIXME: This is no longer being set from renderer. Consider updating the method name.
input->setValueFromRenderer(serializeForNumberType(value));
@@ -322,12 +327,38 @@ HTMLInputElement* SliderThumbElement::hostInput() const
return shadowAncestorNode()->toInputElement();
}
-const AtomicString& SliderThumbElement::shadowPseudoId() const
+static const AtomicString& sliderThumbShadowPseudoId()
{
- DEFINE_STATIC_LOCAL(AtomicString, sliderThumb, ("-webkit-slider-thumb"));
+ DEFINE_STATIC_LOCAL(const AtomicString, sliderThumb, ("-webkit-slider-thumb"));
return sliderThumb;
}
+static const AtomicString& mediaSliderThumbShadowPseudoId()
+{
+ DEFINE_STATIC_LOCAL(const AtomicString, mediaSliderThumb, ("-webkit-media-slider-thumb"));
+ return mediaSliderThumb;
+}
+
+const AtomicString& SliderThumbElement::shadowPseudoId() const
+{
+ HTMLInputElement* input = hostInput();
+ if (!input)
+ return sliderThumbShadowPseudoId();
+
+ RenderStyle* sliderStyle = input->renderer()->style();
+ switch (sliderStyle->appearance()) {
+ case MediaSliderPart:
+ case MediaSliderThumbPart:
+ case MediaVolumeSliderPart:
+ case MediaVolumeSliderThumbPart:
+ case MediaFullScreenVolumeSliderPart:
+ case MediaFullScreenVolumeSliderThumbPart:
+ return mediaSliderThumbShadowPseudoId();
+ default:
+ return sliderThumbShadowPseudoId();
+ }
+}
+
// --------------------------------
inline TrackLimiterElement::TrackLimiterElement(Document* document)
@@ -352,8 +383,22 @@ RenderObject* TrackLimiterElement::createRenderer(RenderArena* arena, RenderStyl
const AtomicString& TrackLimiterElement::shadowPseudoId() const
{
- DEFINE_STATIC_LOCAL(AtomicString, sliderThumb, ("-webkit-slider-thumb"));
- return sliderThumb;
+ HTMLInputElement* input = shadowAncestorNode()->toInputElement();
+ if (!input)
+ return sliderThumbShadowPseudoId();
+
+ RenderStyle* sliderStyle = input->renderer()->style();
+ switch (sliderStyle->appearance()) {
+ case MediaSliderPart:
+ case MediaSliderThumbPart:
+ case MediaVolumeSliderPart:
+ case MediaVolumeSliderThumbPart:
+ case MediaFullScreenVolumeSliderPart:
+ case MediaFullScreenVolumeSliderThumbPart:
+ return mediaSliderThumbShadowPseudoId();
+ default:
+ return sliderThumbShadowPseudoId();
+ }
}
TrackLimiterElement* trackLimiterElementOf(Node* node)
@@ -386,8 +431,25 @@ RenderObject* SliderContainerElement::createRenderer(RenderArena* arena, RenderS
const AtomicString& SliderContainerElement::shadowPseudoId() const
{
- DEFINE_STATIC_LOCAL(AtomicString, sliderThumb, ("-webkit-slider-container"));
- return sliderThumb;
+ DEFINE_STATIC_LOCAL(const AtomicString, mediaSliderContainer, ("-webkit-media-slider-container"));
+ DEFINE_STATIC_LOCAL(const AtomicString, sliderContainer, ("-webkit-slider-container"));
+
+ HTMLInputElement* input = shadowAncestorNode()->toInputElement();
+ if (!input)
+ return sliderContainer;
+
+ RenderStyle* sliderStyle = input->renderer()->style();
+ switch (sliderStyle->appearance()) {
+ case MediaSliderPart:
+ case MediaSliderThumbPart:
+ case MediaVolumeSliderPart:
+ case MediaVolumeSliderThumbPart:
+ case MediaFullScreenVolumeSliderPart:
+ case MediaFullScreenVolumeSliderThumbPart:
+ return mediaSliderContainer;
+ default:
+ return sliderContainer;
+ }
}
}
diff --git a/Source/WebCore/html/shadow/TextControlInnerElements.cpp b/Source/WebCore/html/shadow/TextControlInnerElements.cpp
index 100daeb64..5d26841c2 100644
--- a/Source/WebCore/html/shadow/TextControlInnerElements.cpp
+++ b/Source/WebCore/html/shadow/TextControlInnerElements.cpp
@@ -37,7 +37,7 @@
#include "HTMLTextAreaElement.h"
#include "MouseEvent.h"
#include "Page.h"
-#include "RenderTextControlSingleLine.h"
+#include "RenderSearchField.h"
#include "RenderView.h"
#include "ScriptController.h"
#include "ScrollbarTheme.h"
@@ -151,7 +151,7 @@ void SearchFieldResultsButtonElement::defaultEventHandler(Event* event)
if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) {
input->focus();
input->select();
- RenderTextControlSingleLine* renderer = toRenderTextControlSingleLine(input->renderer());
+ RenderSearchField* renderer = toRenderSearchField(input->renderer());
if (renderer->popupIsVisible())
renderer->hidePopup();
else if (input->maxResults() > 0)
diff --git a/Source/WebCore/html/track/LoadableTextTrack.cpp b/Source/WebCore/html/track/LoadableTextTrack.cpp
index e03ff4bbe..d95e8ccf9 100644
--- a/Source/WebCore/html/track/LoadableTextTrack.cpp
+++ b/Source/WebCore/html/track/LoadableTextTrack.cpp
@@ -37,11 +37,10 @@
namespace WebCore {
-LoadableTextTrack::LoadableTextTrack(HTMLTrackElement* track, const String& kind, const String& label, const String& language, bool isDefault)
+LoadableTextTrack::LoadableTextTrack(HTMLTrackElement* track, const String& kind, const String& label, const String& language, bool)
: TextTrack(track->document(), track, kind, label, language, TrackElement)
, m_trackElement(track)
, m_loadTimer(this, &LoadableTextTrack::loadTimerFired)
- , m_isDefault(isDefault)
{
}
diff --git a/Source/WebCore/html/track/LoadableTextTrack.h b/Source/WebCore/html/track/LoadableTextTrack.h
index ad6f6addf..33183db9b 100644
--- a/Source/WebCore/html/track/LoadableTextTrack.h
+++ b/Source/WebCore/html/track/LoadableTextTrack.h
@@ -76,7 +76,6 @@ private:
Timer<LoadableTextTrack> m_loadTimer;
OwnPtr<TextTrackLoader> m_loader;
KURL m_url;
- bool m_isDefault;
};
} // namespace WebCore
diff --git a/Source/WebCore/html/track/TextTrack.cpp b/Source/WebCore/html/track/TextTrack.cpp
index 20d53c68c..a6e7f844c 100644
--- a/Source/WebCore/html/track/TextTrack.cpp
+++ b/Source/WebCore/html/track/TextTrack.cpp
@@ -78,6 +78,7 @@ const AtomicString& TextTrack::metadataKeyword()
TextTrack::TextTrack(ScriptExecutionContext* context, TextTrackClient* client, const String& kind, const String& label, const String& language, TextTrackType type)
: TrackBase(context, TrackBase::TextTrack)
+ , m_cues(0)
, m_mediaElement(0)
, m_label(label)
, m_language(language)
diff --git a/Source/WebCore/html/track/TextTrackCue.cpp b/Source/WebCore/html/track/TextTrackCue.cpp
index 85c7b2c52..d2de4d3e5 100644
--- a/Source/WebCore/html/track/TextTrackCue.cpp
+++ b/Source/WebCore/html/track/TextTrackCue.cpp
@@ -40,6 +40,7 @@
#include "DocumentFragment.h"
#include "Event.h"
#include "HTMLDivElement.h"
+#include "HTMLMediaElement.h"
#include "Text.h"
#include "TextTrack.h"
#include "TextTrackCueList.h"
@@ -99,10 +100,14 @@ TextTrackCue::TextTrackCue(ScriptExecutionContext* context, const String& id, do
, m_cueIndex(invalidCueIndex)
, m_writingDirection(Horizontal)
, m_cueAlignment(Middle)
+ , m_documentFragment(0)
, m_scriptExecutionContext(context)
, m_isActive(false)
, m_pauseOnExit(pauseOnExit)
, m_snapToLines(true)
+ , m_hasInnerTimestamps(false)
+ , m_pastDocumentNodes(HTMLDivElement::create(static_cast<Document*>(context)))
+ , m_futureDocumentNodes(HTMLDivElement::create(static_cast<Document*>(context)))
, m_displayTreeShouldChange(true)
, m_displayTree(HTMLDivElement::create(static_cast<Document*>(context)))
, m_displayXPosition(undefinedPosition)
@@ -372,9 +377,16 @@ PassRefPtr<DocumentFragment> TextTrackCue::getCueAsHTML()
RefPtr<DocumentFragment> clonedFragment;
Document* document;
- if (!m_documentFragment)
+ if (!m_documentFragment) {
+ m_hasInnerTimestamps = false;
m_documentFragment = WebVTTParser::create(0, m_scriptExecutionContext)->createDocumentFragmentFromCueText(m_content);
+ for (Node *child = m_documentFragment->firstChild(); !m_hasInnerTimestamps && child; child = child->nextSibling()) {
+ if (child->nodeName() == "timestamp")
+ m_hasInnerTimestamps = true;
+ }
+ }
+
document = static_cast<Document*>(m_scriptExecutionContext);
clonedFragment = DocumentFragment::create(document);
@@ -528,9 +540,53 @@ void TextTrackCue::calculateDisplayParameters()
// FIXME(Bug 79916): CSS top and left properties need to be applied.
}
+void TextTrackCue::updateDisplayTree(float movieTime)
+{
+ // The display tree may contain WebVTT timestamp objects representing
+ // timestamps (processing instructions), along with displayable nodes.
+ DEFINE_STATIC_LOCAL(const String, timestampTag, ("timestamp"));
+
+ DEFINE_STATIC_LOCAL(const AtomicString, trackPastNodesShadowPseudoId, ("-webkit-media-text-track-past-nodes"));
+ DEFINE_STATIC_LOCAL(const AtomicString, trackFutureNodesShadowPseudoId, ("-webkit-media-text-track-future-nodes"));
+
+ bool isPastNode = true;
+
+ // Clear the contents of the two sets.
+ m_futureDocumentNodes->removeChildren();
+ m_futureDocumentNodes->setShadowPseudoId(trackFutureNodesShadowPseudoId);
+
+ m_pastDocumentNodes->removeChildren();
+ m_pastDocumentNodes->setShadowPseudoId(trackPastNodesShadowPseudoId);
+
+ // Update the two sets containing past and future WebVTT objects.
+ RefPtr<DocumentFragment> referenceTree = getCueAsHTML();
+
+ if (!m_hasInnerTimestamps) {
+ m_pastDocumentNodes->appendChild(referenceTree);
+ return;
+ }
+
+ for (Node *child = referenceTree->firstChild(); child; child = child->nextSibling()) {
+ if (child->nodeName() == timestampTag) {
+ unsigned int position = 0;
+ String timestamp = child->nodeValue();
+
+ double timestampTime = WebVTTParser::create(0, m_scriptExecutionContext)->collectTimeStamp(timestamp, &position);
+ ASSERT(timestampTime != -1);
+
+ if (timestampTime > movieTime)
+ isPastNode = false;
+ }
+
+ if (isPastNode)
+ m_pastDocumentNodes->appendChild(child->cloneNode(true), ASSERT_NO_EXCEPTION, false);
+ else
+ m_futureDocumentNodes->appendChild(child->cloneNode(true), ASSERT_NO_EXCEPTION, false);
+ }
+}
+
PassRefPtr<HTMLDivElement> TextTrackCue::getDisplayTree()
{
- DEFINE_STATIC_LOCAL(const AtomicString, trackBackgroundShadowPseudoId, ("-webkit-media-text-track-background"));
DEFINE_STATIC_LOCAL(const AtomicString, trackDisplayBoxShadowPseudoId, ("-webkit-media-text-track-display"));
if (!m_displayTreeShouldChange)
@@ -542,6 +598,7 @@ PassRefPtr<HTMLDivElement> TextTrackCue::getDisplayTree()
// 10.11. Apply the terms of the CSS specifications to nodes within the
// following constraints, thus obtaining a set of CSS boxes positioned
// relative to an initial containing block:
+ m_displayTree->setShadowPseudoId(trackDisplayBoxShadowPseudoId, ASSERT_NO_EXCEPTION);
m_displayTree->removeChildren();
// The document tree is the tree of WebVTT Node Objects rooted at nodes.
@@ -549,13 +606,10 @@ PassRefPtr<HTMLDivElement> TextTrackCue::getDisplayTree()
// The children of the nodes must be wrapped in an anonymous box whose
// 'display' property has the value 'inline'. This is the WebVTT cue
// background box.
- RefPtr<HTMLDivElement> cueBackgroundBox = HTMLDivElement::create(static_cast<Document*>(m_scriptExecutionContext));
- cueBackgroundBox->setShadowPseudoId(trackBackgroundShadowPseudoId);
- cueBackgroundBox->appendChild(getCueAsHTML(), ASSERT_NO_EXCEPTION, true);
-
- m_displayTree->setShadowPseudoId(trackDisplayBoxShadowPseudoId, ASSERT_NO_EXCEPTION);
- m_displayTree->appendChild(cueBackgroundBox, ASSERT_NO_EXCEPTION, true);
+ // Note: This is contained by default in m_pastDocumentNodes.
+ m_displayTree->appendChild(m_pastDocumentNodes, ASSERT_NO_EXCEPTION, true);
+ m_displayTree->appendChild(m_futureDocumentNodes, ASSERT_NO_EXCEPTION, true);
// FIXME(BUG 79916): Runs of children of WebVTT Ruby Objects that are not
// WebVTT Ruby Text Objects must be wrapped in anonymous boxes whose
@@ -601,6 +655,9 @@ PassRefPtr<HTMLDivElement> TextTrackCue::getDisplayTree()
CSSValuePre);
}
+ if (m_hasInnerTimestamps)
+ updateDisplayTree(track()->mediaElement()->currentTime());
+
m_displayTreeShouldChange = false;
// 10.15. Let cue's text track cue display state have the CSS boxes in
diff --git a/Source/WebCore/html/track/TextTrackCue.h b/Source/WebCore/html/track/TextTrackCue.h
index a2cf30b1d..9c5ba5b71 100644
--- a/Source/WebCore/html/track/TextTrackCue.h
+++ b/Source/WebCore/html/track/TextTrackCue.h
@@ -102,6 +102,7 @@ public:
void setIsActive(bool);
PassRefPtr<HTMLDivElement> getDisplayTree();
+ void updateDisplayTree(float);
void removeDisplayTree();
virtual const AtomicString& interfaceName() const;
@@ -167,6 +168,10 @@ private:
bool m_pauseOnExit;
bool m_snapToLines;
+ bool m_hasInnerTimestamps;
+ RefPtr<HTMLDivElement> m_pastDocumentNodes;
+ RefPtr<HTMLDivElement> m_futureDocumentNodes;
+
bool m_displayTreeShouldChange;
RefPtr<HTMLDivElement> m_displayTree;
diff --git a/Source/WebCore/html/track/TextTrackList.idl b/Source/WebCore/html/track/TextTrackList.idl
index aedda2e07..3f6efac0c 100644
--- a/Source/WebCore/html/track/TextTrackList.idl
+++ b/Source/WebCore/html/track/TextTrackList.idl
@@ -28,6 +28,7 @@ module html {
interface [
Conditional=VIDEO_TRACK,
V8EnabledAtRuntime=webkitVideoTrack,
+ V8CustomToJSObject,
IndexedGetter,
EventTarget,
JSCustomMarkFunction,
diff --git a/Source/WebCore/html/track/WebVTTParser.h b/Source/WebCore/html/track/WebVTTParser.h
index 0b3b066aa..522bbffa7 100644
--- a/Source/WebCore/html/track/WebVTTParser.h
+++ b/Source/WebCore/html/track/WebVTTParser.h
@@ -94,6 +94,7 @@ public:
void getNewCues(Vector<RefPtr<TextTrackCue> >&);
PassRefPtr<DocumentFragment> createDocumentFragmentFromCueText(const String&);
+ double collectTimeStamp(const String&, unsigned*);
protected:
WebVTTParser(WebVTTParserClient*, ScriptExecutionContext*);
@@ -110,7 +111,7 @@ private:
void createNewCue();
void resetCueValues();
- double collectTimeStamp(const String&, unsigned*);
+
void skipWhiteSpace(const String&, unsigned*);
static void skipLineTerminator(const char* data, unsigned length, unsigned*);
static String collectNextLine(const char* data, unsigned length, unsigned*);