diff options
Diffstat (limited to 'WebCore/html')
79 files changed, 1025 insertions, 319 deletions
diff --git a/WebCore/html/BaseButtonInputType.cpp b/WebCore/html/BaseButtonInputType.cpp index fd6a8ff..0ba1d89 100644 --- a/WebCore/html/BaseButtonInputType.cpp +++ b/WebCore/html/BaseButtonInputType.cpp @@ -32,6 +32,7 @@ #include "BaseButtonInputType.h" #include "HTMLInputElement.h" +#include "KeyboardEvent.h" #include "RenderButton.h" namespace WebCore { @@ -42,6 +43,43 @@ bool BaseButtonInputType::appendFormData(FormDataList&, bool) const return false; } +bool BaseButtonInputType::handleKeydownEvent(KeyboardEvent* event) +{ + const String& key = event->keyIdentifier(); + if (key == "U+0020") { + element()->setActive(true, true); + // No setDefaultHandled(), because IE dispatches a keypress in this case + // and the caller will only dispatch a keypress if we don't call setDefaultHandled(). + } + return false; +} + +bool BaseButtonInputType::handleKeypressEvent(KeyboardEvent* event) +{ + int charCode = event->charCode(); + if (charCode == '\r') { + element()->dispatchSimulatedClick(event); + event->setDefaultHandled(); + return true; + } + if (charCode == ' ') { + // Prevent scrolling down the page. + event->setDefaultHandled(); + return true; + } + return false; +} + +bool BaseButtonInputType::handleKeyupEvent(KeyboardEvent* event) +{ + const String& key = event->keyIdentifier(); + if (key != "U+0020") + return false; + // Simulate mouse click for spacebar for button types. + dispatchSimulatedClickIfActive(event); + return true; +} + RenderObject* BaseButtonInputType::createRenderer(RenderArena* arena, RenderStyle*) const { return new (arena) RenderButton(element()); diff --git a/WebCore/html/BaseButtonInputType.h b/WebCore/html/BaseButtonInputType.h index e7f683b..59e28bf 100644 --- a/WebCore/html/BaseButtonInputType.h +++ b/WebCore/html/BaseButtonInputType.h @@ -42,6 +42,9 @@ protected: private: virtual bool appendFormData(FormDataList&, bool) const; + virtual bool handleKeydownEvent(KeyboardEvent*); + virtual bool handleKeypressEvent(KeyboardEvent*); + virtual bool handleKeyupEvent(KeyboardEvent*); virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) const; }; diff --git a/WebCore/html/BaseCheckableInputType.cpp b/WebCore/html/BaseCheckableInputType.cpp index 009e8e4..940acf4 100644 --- a/WebCore/html/BaseCheckableInputType.cpp +++ b/WebCore/html/BaseCheckableInputType.cpp @@ -34,6 +34,7 @@ #include "FormDataList.h" #include "HTMLInputElement.h" #include "HTMLNames.h" +#include "KeyboardEvent.h" #include "RegularExpression.h" namespace WebCore { @@ -57,4 +58,25 @@ bool BaseCheckableInputType::appendFormData(FormDataList& encoding, bool) const return true; } +bool BaseCheckableInputType::handleKeydownEvent(KeyboardEvent* event) +{ + const String& key = event->keyIdentifier(); + if (key == "U+0020") { + element()->setActive(true, true); + // No setDefaultHandled(), because IE dispatches a keypress in this case + // and the caller will only dispatch a keypress if we don't call setDefaultHandled(). + } + return false; +} + +bool BaseCheckableInputType::handleKeypressEvent(KeyboardEvent* event) +{ + if (event->charCode() == ' ') { + // Prevent scrolling down the page. + event->setDefaultHandled(); + return true; + } + return false; +} + } // namespace WebCore diff --git a/WebCore/html/BaseCheckableInputType.h b/WebCore/html/BaseCheckableInputType.h index 02edf29..8cb95cf 100644 --- a/WebCore/html/BaseCheckableInputType.h +++ b/WebCore/html/BaseCheckableInputType.h @@ -39,11 +39,13 @@ namespace WebCore { class BaseCheckableInputType : public InputType { protected: BaseCheckableInputType(HTMLInputElement* element) : InputType(element) { } + virtual bool handleKeydownEvent(KeyboardEvent*); private: virtual bool saveFormControlState(String&) const; virtual void restoreFormControlState(const String&) const; virtual bool appendFormData(FormDataList&, bool) const; + virtual bool handleKeypressEvent(KeyboardEvent*); }; } // namespace WebCore diff --git a/WebCore/html/BaseDateAndTimeInputType.cpp b/WebCore/html/BaseDateAndTimeInputType.cpp index e780ed6..70243e5 100644 --- a/WebCore/html/BaseDateAndTimeInputType.cpp +++ b/WebCore/html/BaseDateAndTimeInputType.cpp @@ -35,6 +35,8 @@ #include "HTMLInputElement.h" #include "HTMLNames.h" #include <limits> +#include <wtf/CurrentTime.h> +#include <wtf/DateMath.h> #include <wtf/MathExtras.h> #include <wtf/PassOwnPtr.h> #include <wtf/text/WTFString.h> @@ -91,6 +93,15 @@ bool BaseDateAndTimeInputType::rangeOverflow(const String& value) const return isfinite(doubleValue) && doubleValue > maximum(); } +double 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); +} + bool BaseDateAndTimeInputType::stepMismatch(const String& value, double step) const { const double nan = numeric_limits<double>::quiet_NaN(); diff --git a/WebCore/html/BaseDateAndTimeInputType.h b/WebCore/html/BaseDateAndTimeInputType.h index 11c60af..ad7302a 100644 --- a/WebCore/html/BaseDateAndTimeInputType.h +++ b/WebCore/html/BaseDateAndTimeInputType.h @@ -55,6 +55,7 @@ private: virtual bool typeMismatch() const; virtual bool rangeUnderflow(const String&) const; virtual bool rangeOverflow(const String&) const; + virtual double defaultValueForStepUp() const; virtual bool stepMismatch(const String&, double) const; virtual double stepBase() const; virtual bool handleKeydownEvent(KeyboardEvent*); diff --git a/WebCore/html/CheckboxInputType.cpp b/WebCore/html/CheckboxInputType.cpp index 572dde0..cd171c1 100644 --- a/WebCore/html/CheckboxInputType.cpp +++ b/WebCore/html/CheckboxInputType.cpp @@ -32,6 +32,8 @@ #include "CheckboxInputType.h" #include "HTMLInputElement.h" +#include "KeyboardEvent.h" +#include "LocalizedStrings.h" #include <wtf/PassOwnPtr.h> namespace WebCore { @@ -51,4 +53,18 @@ bool CheckboxInputType::valueMissing(const String&) const return !element()->checked(); } +String CheckboxInputType::valueMissingText() const +{ + return validationMessageValueMissingForCheckboxText(); +} + +bool CheckboxInputType::handleKeyupEvent(KeyboardEvent* event) +{ + const String& key = event->keyIdentifier(); + if (key != "U+0020") + return false; + dispatchSimulatedClickIfActive(event); + return true; +} + } // namespace WebCore diff --git a/WebCore/html/CheckboxInputType.h b/WebCore/html/CheckboxInputType.h index b68e14d..e66ab15 100644 --- a/WebCore/html/CheckboxInputType.h +++ b/WebCore/html/CheckboxInputType.h @@ -43,6 +43,8 @@ private: CheckboxInputType(HTMLInputElement* element) : BaseCheckableInputType(element) { } virtual const AtomicString& formControlType() const; virtual bool valueMissing(const String&) const; + virtual String valueMissingText() const; + virtual bool handleKeyupEvent(KeyboardEvent*); }; } // namespace WebCore diff --git a/WebCore/html/DateTimeInputType.cpp b/WebCore/html/DateTimeInputType.cpp index c78a540..78641f8 100644 --- a/WebCore/html/DateTimeInputType.cpp +++ b/WebCore/html/DateTimeInputType.cpp @@ -34,6 +34,7 @@ #include "DateComponents.h" #include "HTMLInputElement.h" #include "HTMLNames.h" +#include <wtf/CurrentTime.h> #include <wtf/PassOwnPtr.h> namespace WebCore { @@ -53,6 +54,11 @@ const AtomicString& DateTimeInputType::formControlType() const return InputTypeNames::datetime(); } +double DateTimeInputType::defaultValueForStepUp() const +{ + return currentTimeMS(); +} + double DateTimeInputType::minimum() const { return parseToDouble(element()->fastGetAttribute(minAttr), DateComponents::minimumDateTime()); diff --git a/WebCore/html/DateTimeInputType.h b/WebCore/html/DateTimeInputType.h index 140975b..9a0efd1 100644 --- a/WebCore/html/DateTimeInputType.h +++ b/WebCore/html/DateTimeInputType.h @@ -42,6 +42,7 @@ public: private: DateTimeInputType(HTMLInputElement* element) : BaseDateAndTimeInputType(element) { } virtual const AtomicString& formControlType() const; + virtual double defaultValueForStepUp() const; virtual double minimum() const; virtual double maximum() const; virtual double defaultStep() const; diff --git a/WebCore/html/DocTypeStrings.gperf b/WebCore/html/DocTypeStrings.gperf index 22488eb..2e2a7e8 100644 --- a/WebCore/html/DocTypeStrings.gperf +++ b/WebCore/html/DocTypeStrings.gperf @@ -1,3 +1,9 @@ +%{ +#include "HashTools.h" +#include <string.h> + +namespace WebCore { +%} %struct-type struct PubIDInfo; %omit-struct-type @@ -88,3 +94,10 @@ struct PubIDInfo; "-//webtechs//dtd mozilla html//en", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 "-/w3c/dtd html 4.0 transitional/en", PubIDInfo::eQuirks, PubIDInfo::eQuirks "html", PubIDInfo::eQuirks3, PubIDInfo::eQuirks3 +%% +const PubIDInfo* findDoctypeEntry(register const char* str, register unsigned int len) +{ + return DocTypeStringsHash::findDoctypeEntryImpl(str, len); +} + +} // namespace WebCore diff --git a/WebCore/html/FileInputType.cpp b/WebCore/html/FileInputType.cpp index e9d0b5e..b5fc2fb 100644 --- a/WebCore/html/FileInputType.cpp +++ b/WebCore/html/FileInputType.cpp @@ -27,6 +27,7 @@ #include "FileList.h" #include "FormDataList.h" #include "HTMLInputElement.h" +#include "LocalizedStrings.h" #include "RenderFileUploadControl.h" #include <wtf/PassOwnPtr.h> #include <wtf/text/WTFString.h> @@ -77,6 +78,11 @@ bool FileInputType::valueMissing(const String& value) const return value.isEmpty(); } +String FileInputType::valueMissingText() const +{ + return element()->multiple() ? validationMessageValueMissingForMultipleFileText() : validationMessageValueMissingForFileText(); +} + bool FileInputType::handleDOMActivateEvent(Event* event) { if (element()->disabled() || !element()->renderer()) diff --git a/WebCore/html/FileInputType.h b/WebCore/html/FileInputType.h index 142afaf..df95ffc 100644 --- a/WebCore/html/FileInputType.h +++ b/WebCore/html/FileInputType.h @@ -44,6 +44,7 @@ private: virtual const AtomicString& formControlType() const; virtual bool appendFormData(FormDataList&, bool) const; virtual bool valueMissing(const String&) const; + virtual String valueMissingText() const; virtual bool handleDOMActivateEvent(Event*); virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) const; }; diff --git a/WebCore/html/HTMLAreaElement.cpp b/WebCore/html/HTMLAreaElement.cpp index cebfda2..dc87ef6 100644 --- a/WebCore/html/HTMLAreaElement.cpp +++ b/WebCore/html/HTMLAreaElement.cpp @@ -23,6 +23,7 @@ #include "HTMLAreaElement.h" #include "Attribute.h" +#include "Frame.h" #include "HTMLImageElement.h" #include "HTMLMapElement.h" #include "HTMLNames.h" @@ -98,6 +99,13 @@ Path HTMLAreaElement::getPath(RenderObject* obj) const size = obj->absoluteOutlineBounds().size(); Path p = getRegion(size); + float zoomFactor = document()->frame()->pageZoomFactor(); + if (zoomFactor != 1.0f) { + AffineTransform zoomTransform; + zoomTransform.scale(zoomFactor); + p.transform(zoomTransform); + } + p.translate(absPos - FloatPoint()); return p; } diff --git a/WebCore/html/HTMLFieldSetElement.h b/WebCore/html/HTMLFieldSetElement.h index db99a89..dcc8d0c 100644 --- a/WebCore/html/HTMLFieldSetElement.h +++ b/WebCore/html/HTMLFieldSetElement.h @@ -35,6 +35,7 @@ public: private: HTMLFieldSetElement(const QualifiedName&, Document*, HTMLFormElement*); + virtual bool isEnumeratable() const { return true; } virtual bool supportsFocus() const; virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); virtual const AtomicString& formControlType() const; diff --git a/WebCore/html/HTMLImageLoader.cpp b/WebCore/html/HTMLImageLoader.cpp index f620542..a1a3b26 100644 --- a/WebCore/html/HTMLImageLoader.cpp +++ b/WebCore/html/HTMLImageLoader.cpp @@ -48,7 +48,7 @@ HTMLImageLoader::~HTMLImageLoader() void HTMLImageLoader::dispatchLoadEvent() { bool errorOccurred = image()->errorOccurred(); - if (!errorOccurred && image()->httpStatusCodeErrorOccurred()) + if (!errorOccurred && image()->response().httpStatusCode() >= 400) errorOccurred = element()->hasTagName(HTMLNames::objectTag); // An <object> considers a 404 to be an error and should fire onerror. element()->dispatchEvent(Event::create(errorOccurred ? eventNames().errorEvent : eventNames().loadEvent, false, false)); } @@ -65,8 +65,9 @@ void HTMLImageLoader::notifyFinished(CachedResource*) Element* elem = element(); ImageLoader::notifyFinished(cachedImage); + bool loadError = cachedImage->errorOccurred() || cachedImage->response().httpStatusCode() >= 400; #if USE(JSC) - if (!cachedImage->errorOccurred() && !cachedImage->httpStatusCodeErrorOccurred()) { + if (!loadError) { if (!elem->inDocument()) { JSC::JSGlobalData* globalData = JSDOMWindowBase::commonJSGlobalData(); globalData->heap.reportExtraMemoryCost(cachedImage->encodedSize()); @@ -74,7 +75,7 @@ void HTMLImageLoader::notifyFinished(CachedResource*) } #endif - if ((cachedImage->errorOccurred() || cachedImage->httpStatusCodeErrorOccurred()) && elem->hasTagName(HTMLNames::objectTag)) + if (loadError && elem->hasTagName(HTMLNames::objectTag)) static_cast<HTMLObjectElement*>(elem)->renderFallbackContent(); } diff --git a/WebCore/html/HTMLInputElement.cpp b/WebCore/html/HTMLInputElement.cpp index b704fc1..765e4fc 100644 --- a/WebCore/html/HTMLInputElement.cpp +++ b/WebCore/html/HTMLInputElement.cpp @@ -283,6 +283,11 @@ String HTMLInputElement::typeMismatchText() const return m_inputType->typeMismatchText(); } +String HTMLInputElement::valueMissingText() const +{ + return m_inputType->valueMissingText(); +} + bool HTMLInputElement::getAllowedValueStep(double* step) const { return getAllowedValueStepWithDecimalPlaces(step, 0); @@ -332,13 +337,13 @@ bool HTMLInputElement::getAllowedValueStepWithDecimalPlaces(double* step, unsign void HTMLInputElement::applyStep(double count, ExceptionCode& ec) { double step; - unsigned stepDecimalPlaces; + unsigned stepDecimalPlaces, currentDecimalPlaces; if (!getAllowedValueStepWithDecimalPlaces(&step, &stepDecimalPlaces)) { ec = INVALID_STATE_ERR; return; } const double nan = numeric_limits<double>::quiet_NaN(); - double current = m_inputType->parseToDouble(value(), nan); + double current = m_inputType->parseToDoubleWithDecimalPlaces(value(), nan, ¤tDecimalPlaces); if (!isfinite(current)) { ec = INVALID_STATE_ERR; return; @@ -359,8 +364,13 @@ void HTMLInputElement::applyStep(double count, ExceptionCode& ec) double base = m_inputType->stepBaseWithDecimalPlaces(&baseDecimalPlaces); baseDecimalPlaces = min(baseDecimalPlaces, 16u); if (newValue < pow(10.0, 21.0)) { - double scale = pow(10.0, static_cast<double>(max(stepDecimalPlaces, baseDecimalPlaces))); - newValue = round((base + round((newValue - base) / step) * step) * scale) / scale; + if (stepMismatch(value())) { + double scale = pow(10.0, static_cast<double>(max(stepDecimalPlaces, currentDecimalPlaces))); + newValue = round(newValue * scale) / scale; + } else { + double scale = pow(10.0, static_cast<double>(max(stepDecimalPlaces, baseDecimalPlaces))); + newValue = round((base + round((newValue - base) / step) * step) * scale) / scale; + } } if (newValue - m_inputType->maximum() > acceptableError) { ec = INVALID_STATE_ERR; @@ -774,7 +784,7 @@ void HTMLInputElement::parseMappedAttribute(Attribute* attr) #if ENABLE(INPUT_SPEECH) else if (attr->name() == webkitspeechAttr) { if (renderer()) - renderer()->updateFromElement(); + toRenderTextControlSingleLine(renderer())->speechAttributeChanged(); setNeedsStyleRecalc(); } else if (attr->name() == onwebkitspeechchangeAttr) setAttributeEventListener(eventNames().webkitspeechchangeEvent, createAttributeEventListener(this, attr)); @@ -1293,11 +1303,6 @@ void HTMLInputElement::defaultEventHandler(Event* evt) // FIXME: It would be better to refactor this for the different types of input element. // Having them all in one giant function makes this hard to read, and almost all the handling is type-specific. - bool implicitSubmission = false; - - if (isTextField() && evt->type() == eventNames().textInputEvent && evt->isTextEvent() && static_cast<TextEvent*>(evt)->data() == "\n") - implicitSubmission = true; - if (evt->isMouseEvent() && evt->type() == eventNames().clickEvent && m_inputType->handleClickEvent(static_cast<MouseEvent*>(evt))) return; @@ -1306,8 +1311,7 @@ void HTMLInputElement::defaultEventHandler(Event* evt) // Call the base event handler before any of our own event handling for almost all events in text fields. // Makes editing keyboard handling take precedence over the keydown and keypress handling in this function. - bool callBaseClassEarly = isTextField() && !implicitSubmission - && (evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent); + bool callBaseClassEarly = isTextField() && (evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent); if (callBaseClassEarly) { HTMLFormControlElementWithState::defaultEventHandler(evt); if (evt->defaultHandled()) @@ -1323,180 +1327,13 @@ void HTMLInputElement::defaultEventHandler(Event* evt) // Use key press event here since sending simulated mouse events // on key down blocks the proper sending of the key press event. - if (evt->type() == eventNames().keypressEvent && evt->isKeyboardEvent()) { - bool clickElement = false; - - int charCode = static_cast<KeyboardEvent*>(evt)->charCode(); - - if (charCode == '\r') { - switch (deprecatedInputType()) { - case CHECKBOX: - case COLOR: - case DATE: - case DATETIME: - case DATETIMELOCAL: - case EMAIL: - case HIDDEN: - case ISINDEX: - case MONTH: - case NUMBER: - case PASSWORD: - case RADIO: - case RANGE: - case SEARCH: - case TELEPHONE: - case TEXT: - case TIME: - case URL: - case WEEK: - // Simulate mouse click on the default form button for enter for these types of elements. - implicitSubmission = true; - break; - case BUTTON: - case FILE: - case IMAGE: - case RESET: - case SUBMIT: - // Simulate mouse click for enter for these types of elements. - clickElement = true; - break; - } - } else if (charCode == ' ') { - switch (deprecatedInputType()) { - case BUTTON: - case CHECKBOX: - case FILE: - case IMAGE: - case RESET: - case SUBMIT: - case RADIO: - // Prevent scrolling down the page. - evt->setDefaultHandled(); - return; - default: - break; - } - } - - if (clickElement) { - dispatchSimulatedClick(evt); - evt->setDefaultHandled(); - return; - } - } - - if (evt->type() == eventNames().keydownEvent && evt->isKeyboardEvent()) { - const String& key = static_cast<KeyboardEvent*>(evt)->keyIdentifier(); - - if (key == "U+0020") { - switch (deprecatedInputType()) { - case BUTTON: - case CHECKBOX: - case FILE: - case IMAGE: - case RESET: - case SUBMIT: - case RADIO: - setActive(true, true); - // No setDefaultHandled(), because IE dispatches a keypress in this case - // and the caller will only dispatch a keypress if we don't call setDefaultHandled. - return; - default: - break; - } - } - - if (deprecatedInputType() == RADIO && (key == "Up" || key == "Down" || key == "Left" || key == "Right")) { - // Left and up mean "previous radio button". - // Right and down mean "next radio button". - // Tested in WinIE, and even for RTL, left still means previous radio button (and so moves - // to the right). Seems strange, but we'll match it. - // However, when using Spatial Navigation, we need to be able to navigate without changing the selection. - if (!document()->frame() || !document()->frame()->settings() || !document()->frame()->settings()->isSpatialNavigationEnabled()) { - bool forward = (key == "Down" || key == "Right"); - - // We can only stay within the form's children if the form hasn't been demoted to a leaf because - // of malformed HTML. - Node* n = this; - while ((n = (forward ? n->traverseNextNode() : n->traversePreviousNode()))) { - // Once we encounter a form element, we know we're through. - if (n->hasTagName(formTag)) - break; - - // Look for more radio buttons. - if (n->hasTagName(inputTag)) { - HTMLInputElement* elt = static_cast<HTMLInputElement*>(n); - if (elt->form() != form()) - break; - if (n->hasTagName(inputTag)) { - HTMLInputElement* inputElt = static_cast<HTMLInputElement*>(n); - if (inputElt->deprecatedInputType() == RADIO && inputElt->name() == name() && inputElt->isFocusable()) { - inputElt->setChecked(true); - document()->setFocusedNode(inputElt); - inputElt->dispatchSimulatedClick(evt, false, false); - evt->setDefaultHandled(); - break; - } - } - } - } - } - } - } - - if (evt->type() == eventNames().keyupEvent && evt->isKeyboardEvent()) { - bool clickElement = false; - - const String& key = static_cast<KeyboardEvent*>(evt)->keyIdentifier(); - - if (key == "U+0020") { - switch (deprecatedInputType()) { - case BUTTON: - case CHECKBOX: - case FILE: - case IMAGE: - case RESET: - case SUBMIT: - // Simulate mouse click for spacebar for these types of elements. - // The AppKit already does this for some, but not all, of them. - clickElement = true; - break; - case RADIO: - // If an unselected radio is tabbed into (because the entire group has nothing - // checked, or because of some explicit .focus() call), then allow space to check it. - if (!checked()) - clickElement = true; - break; - case COLOR: - case DATE: - case DATETIME: - case DATETIMELOCAL: - case EMAIL: - case HIDDEN: - case ISINDEX: - case MONTH: - case NUMBER: - case PASSWORD: - case RANGE: - case SEARCH: - case TELEPHONE: - case TEXT: - case TIME: - case URL: - case WEEK: - break; - } - } + if (evt->isKeyboardEvent() && evt->type() == eventNames().keypressEvent && m_inputType->handleKeypressEvent(static_cast<KeyboardEvent*>(evt))) + return; - if (clickElement) { - if (active()) - dispatchSimulatedClick(evt); - evt->setDefaultHandled(); - return; - } - } + if (evt->isKeyboardEvent() && evt->type() == eventNames().keyupEvent && m_inputType->handleKeyupEvent(static_cast<KeyboardEvent*>(evt))) + return; - if (implicitSubmission) { + if (m_inputType->shouldSubmitImplicitly(evt)) { if (isSearchField()) { addSearchResult(); onSearch(); @@ -1860,37 +1697,113 @@ HTMLOptionElement* HTMLInputElement::selectedOption() const void HTMLInputElement::stepUpFromRenderer(int n) { // The differences from stepUp()/stepDown(): - // If the current value is not a number, the value will be - // - The value should be the minimum value if n > 0 - // - The value should be the maximum value if n < 0 + // + // Difference 1: the current value + // If the current value is not a number, including empty, the current value is assumed as 0. + // * If 0 is in-range, and matches to step value + // - The value should be the +step if n > 0 + // - The value should be the -step if n < 0 + // If -step or +step is out of range, new value should be 0. + // * If 0 is smaller than the minimum value + // - The value should be the minimum value for any n + // * If 0 is larger than the maximum value + // - The value should be the maximum value for any n + // * If 0 is in-range, but not matched to step value + // - The value should be the larger matched value nearest to 0 if n > 0 + // e.g. <input type=number min=-100 step=3> -> 2 + // - The value should be the smaler matched value nearest to 0 if n < 0 + // e.g. <input type=number min=-100 step=3> -> -1 + // As for date/datetime-local/month/time/week types, the current value is assumed as "the current local date/time". + // As for datetime type, the current value is assumed as "the current date/time in UTC". // If the current value is smaller than the minimum value: // - The value should be the minimum value if n > 0 // - Nothing should happen if n < 0 // If the current value is larger than the maximum value: // - The value should be the maximum value if n < 0 // - Nothing should happen if n > 0 - - ASSERT(hasSpinButton()); - if (!hasSpinButton()) + // + // Difference 2: clamping steps + // If the current value is not matched to step value: + // - The value should be the larger matched value nearest to 0 if n > 0 + // e.g. <input type=number value=3 min=-100 step=3> -> 5 + // - The value should be the smaler matched value nearest to 0 if n < 0 + // e.g. <input type=number value=3 min=-100 step=3> -> 2 + // + // n is assumed as -n if step < 0. + + ASSERT(hasSpinButton() || m_inputType->isRangeControl()); + if (!hasSpinButton() && !m_inputType->isRangeControl()) return; ASSERT(n); if (!n) return; + unsigned stepDecimalPlaces, baseDecimalPlaces; + double step, base; + // The value will be the default value after stepping for <input value=(empty/invalid) step="any" /> + // FIXME: Not any changes after stepping, even if it is an invalid value, may be better. + // (e.g. Stepping-up for <input type="number" value="foo" step="any" /> => "foo") + if (equalIgnoringCase(getAttribute(stepAttr), "any")) + step = 0; + else if (!getAllowedValueStepWithDecimalPlaces(&step, &stepDecimalPlaces)) + return; + base = m_inputType->stepBaseWithDecimalPlaces(&baseDecimalPlaces); + baseDecimalPlaces = min(baseDecimalPlaces, 16u); + + int sign; + if (step > 0) + sign = n; + else if (step < 0) + sign = -n; + else + sign = 0; + const double nan = numeric_limits<double>::quiet_NaN(); String currentStringValue = value(); double current = m_inputType->parseToDouble(currentStringValue, nan); - if (!isfinite(current) || (n > 0 && current < m_inputType->minimum()) || (n < 0 && current > m_inputType->maximum())) - setValue(m_inputType->serialize(n > 0 ? m_inputType->minimum() : m_inputType->maximum())); + if (!isfinite(current)) { + ExceptionCode ec; + current = m_inputType->defaultValueForStepUp(); + setValueAsNumber(current, ec); + } + if ((sign > 0 && current < m_inputType->minimum()) || (sign < 0 && current > m_inputType->maximum())) + setValue(m_inputType->serialize(sign > 0 ? m_inputType->minimum() : m_inputType->maximum())); else { ExceptionCode ec; - stepUp(n, ec); + if (stepMismatch(currentStringValue)) { + ASSERT(step); + double newValue; + double scale = pow(10.0, static_cast<double>(max(stepDecimalPlaces, baseDecimalPlaces))); + + if (sign < 0) + newValue = round((base + floor((current - base) / step) * step) * scale) / scale; + else if (sign > 0) + newValue = round((base + ceil((current - base) / step) * step) * scale) / scale; + else + newValue = current; + + if (newValue < m_inputType->minimum()) + newValue = m_inputType->minimum(); + if (newValue > m_inputType->maximum()) + newValue = m_inputType->maximum(); + + setValueAsNumber(newValue, ec); + current = newValue; + if (n > 1) + applyStep(n - 1, ec); + else if (n < -1) + applyStep(n + 1, ec); + } else + applyStep(n, ec); } if (currentStringValue != value()) { if (renderer() && renderer()->isTextField()) toRenderTextControl(renderer())->setChangedSinceLastChangeEvent(true); - dispatchEvent(Event::create(eventNames().inputEvent, true, false)); + if (m_inputType->isRangeControl()) + dispatchFormControlChangeEvent(); + else + dispatchEvent(Event::create(eventNames().inputEvent, true, false)); } } @@ -1938,11 +1851,6 @@ bool HTMLInputElement::isSpeechEnabled() const return false; } -void HTMLInputElement::dispatchWebkitSpeechChangeEvent() -{ - ASSERT(isSpeechEnabled()); - dispatchEvent(Event::create(eventNames().webkitspeechchangeEvent, true, false)); -} #endif } // namespace diff --git a/WebCore/html/HTMLInputElement.h b/WebCore/html/HTMLInputElement.h index 9884117..0f0e97e 100644 --- a/WebCore/html/HTMLInputElement.h +++ b/WebCore/html/HTMLInputElement.h @@ -27,6 +27,7 @@ #include "HTMLFormControlElement.h" #include "HTMLFormElement.h" #include "InputElement.h" +#include "InputType.h" #include <wtf/OwnPtr.h> namespace WebCore { @@ -73,6 +74,7 @@ public: String stepBaseString() const; String stepString() const; String typeMismatchText() const; + String valueMissingText() const; // Implementations of HTMLInputElement::stepUp() and stepDown(). void stepUp(int, ExceptionCode&); @@ -107,7 +109,6 @@ public: #if ENABLE(INPUT_SPEECH) virtual bool isSpeechEnabled() const; - void dispatchWebkitSpeechChangeEvent(); #endif bool checked() const { return m_checked; } diff --git a/WebCore/html/HTMLKeygenElement.h b/WebCore/html/HTMLKeygenElement.h index 4c08014..f722e5b 100644 --- a/WebCore/html/HTMLKeygenElement.h +++ b/WebCore/html/HTMLKeygenElement.h @@ -36,7 +36,6 @@ private: HTMLKeygenElement(const QualifiedName&, Document*, HTMLFormElement*); virtual const AtomicString& formControlType() const; - virtual bool isEnumeratable() const { return false; } virtual void parseMappedAttribute(Attribute*); virtual bool appendFormData(FormDataList&, bool); diff --git a/WebCore/html/HTMLLinkElement.idl b/WebCore/html/HTMLLinkElement.idl index 734e8cc..9419e15 100644 --- a/WebCore/html/HTMLLinkElement.idl +++ b/WebCore/html/HTMLLinkElement.idl @@ -20,7 +20,7 @@ module html { - interface HTMLLinkElement : HTMLElement { + interface [CustomMarkFunction] HTMLLinkElement : HTMLElement { attribute [Reflect] boolean disabled; attribute [Reflect] DOMString charset; attribute [Reflect, URL] DOMString href; diff --git a/WebCore/html/HTMLMeterElement.cpp b/WebCore/html/HTMLMeterElement.cpp index 3de69df..09c5210 100644 --- a/WebCore/html/HTMLMeterElement.cpp +++ b/WebCore/html/HTMLMeterElement.cpp @@ -36,17 +36,15 @@ namespace WebCore { using namespace HTMLNames; -// FIXME: This constructor should take an explicit form element pointer passed from the -// parser like the constructors for all the other classes derived from HTMLFormControlElement. -HTMLMeterElement::HTMLMeterElement(const QualifiedName& tagName, Document* document) - : HTMLFormControlElement(tagName, document, 0) +HTMLMeterElement::HTMLMeterElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form) + : HTMLFormControlElement(tagName, document, form) { ASSERT(hasTagName(meterTag)); } -PassRefPtr<HTMLMeterElement> HTMLMeterElement::create(const QualifiedName& tagName, Document* document) +PassRefPtr<HTMLMeterElement> HTMLMeterElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form) { - return adoptRef(new HTMLMeterElement(tagName, document)); + return adoptRef(new HTMLMeterElement(tagName, document, form)); } RenderObject* HTMLMeterElement::createRenderer(RenderArena* arena, RenderStyle*) diff --git a/WebCore/html/HTMLMeterElement.h b/WebCore/html/HTMLMeterElement.h index cefad97..dedad6a 100644 --- a/WebCore/html/HTMLMeterElement.h +++ b/WebCore/html/HTMLMeterElement.h @@ -28,7 +28,7 @@ namespace WebCore { class HTMLMeterElement : public HTMLFormControlElement { public: - static PassRefPtr<HTMLMeterElement> create(const QualifiedName&, Document*); + static PassRefPtr<HTMLMeterElement> create(const QualifiedName&, Document*, HTMLFormElement*); enum GaugeRegion { GaugeRegionOptimum, @@ -56,7 +56,7 @@ public: GaugeRegion gaugeRegion() const; private: - HTMLMeterElement(const QualifiedName&, Document*); + HTMLMeterElement(const QualifiedName&, Document*, HTMLFormElement*); virtual bool recalcWillValidate() const { return false; } diff --git a/WebCore/html/HTMLObjectElement.cpp b/WebCore/html/HTMLObjectElement.cpp index c07d050..69974a8 100644 --- a/WebCore/html/HTMLObjectElement.cpp +++ b/WebCore/html/HTMLObjectElement.cpp @@ -287,12 +287,8 @@ bool HTMLObjectElement::rendererIsNeeded(RenderStyle* style) Frame* frame = document()->frame(); if (!frame) return false; - - // Temporary Workaround for Gears plugin - see bug 24215 for details and bug 24346 to track removal. - // Gears expects the plugin to be instantiated even if display:none is set - // for the object element. - bool isGearsPlugin = equalIgnoringCase(getAttribute(typeAttr), "application/x-googlegears"); - return isGearsPlugin || HTMLPlugInImageElement::rendererIsNeeded(style); + + return HTMLPlugInImageElement::rendererIsNeeded(style); } void HTMLObjectElement::insertedIntoDocument() diff --git a/WebCore/html/HTMLOutputElement.cpp b/WebCore/html/HTMLOutputElement.cpp index b83263e..2f1d490 100644 --- a/WebCore/html/HTMLOutputElement.cpp +++ b/WebCore/html/HTMLOutputElement.cpp @@ -40,7 +40,7 @@ inline HTMLOutputElement::HTMLOutputElement(const QualifiedName& tagName, Docume : HTMLFormControlElement(tagName, document, form) , m_isDefaultValueMode(true) , m_isSetTextContentInProgress(false) - , m_defaultValue() + , m_defaultValue("") , m_tokens(DOMSettableTokenList::create()) { } @@ -91,6 +91,8 @@ void HTMLOutputElement::reset() // value mode flag to "default" and then to set the element's textContent // attribute to the default value. m_isDefaultValueMode = true; + if (m_defaultValue == value()) + return; setTextContentInternal(m_defaultValue); } @@ -103,6 +105,8 @@ void HTMLOutputElement::setValue(const String& value) { // The value mode flag set to "value" when the value attribute is set. m_isDefaultValueMode = false; + if (value == this->value()) + return; setTextContentInternal(value); } @@ -113,11 +117,13 @@ String HTMLOutputElement::defaultValue() const void HTMLOutputElement::setDefaultValue(const String& value) { - m_defaultValue = value; - // The spec requires the value attribute set to the default value - // when the element's value mode flag to "default". - if (m_isDefaultValueMode) - setTextContentInternal(value); + if (m_defaultValue == value) + return; + m_defaultValue = value; + // The spec requires the value attribute set to the default value + // when the element's value mode flag to "default". + if (m_isDefaultValueMode) + setTextContentInternal(value); } void HTMLOutputElement::setTextContentInternal(const String& value) diff --git a/WebCore/html/HTMLProgressElement.h b/WebCore/html/HTMLProgressElement.h index 7900063..429e9c0 100644 --- a/WebCore/html/HTMLProgressElement.h +++ b/WebCore/html/HTMLProgressElement.h @@ -28,7 +28,7 @@ namespace WebCore { class HTMLProgressElement : public HTMLFormControlElement { public: - static PassRefPtr<HTMLProgressElement> create(const QualifiedName&, Document*, HTMLFormElement* = 0); + static PassRefPtr<HTMLProgressElement> create(const QualifiedName&, Document*, HTMLFormElement*); double value() const; void setValue(double, ExceptionCode&); diff --git a/WebCore/html/HTMLScriptElement.cpp b/WebCore/html/HTMLScriptElement.cpp index 0ee93df..e229bb8 100644 --- a/WebCore/html/HTMLScriptElement.cpp +++ b/WebCore/html/HTMLScriptElement.cpp @@ -35,16 +35,16 @@ namespace WebCore { using namespace HTMLNames; -inline HTMLScriptElement::HTMLScriptElement(const QualifiedName& tagName, Document* document, bool createdByParser, bool isEvaluated) +inline HTMLScriptElement::HTMLScriptElement(const QualifiedName& tagName, Document* document, bool wasInsertedByParser, bool wasAlreadyStarted) : HTMLElement(tagName, document) - , ScriptElement(this, createdByParser, isEvaluated) + , ScriptElement(this, wasInsertedByParser, wasAlreadyStarted) { ASSERT(hasTagName(scriptTag)); } -PassRefPtr<HTMLScriptElement> HTMLScriptElement::create(const QualifiedName& tagName, Document* document, bool createdByParser) +PassRefPtr<HTMLScriptElement> HTMLScriptElement::create(const QualifiedName& tagName, Document* document, bool wasInsertedByParser) { - return adoptRef(new HTMLScriptElement(tagName, document, createdByParser, false)); + return adoptRef(new HTMLScriptElement(tagName, document, wasInsertedByParser, false)); } bool HTMLScriptElement::isURLAttribute(Attribute* attr) const @@ -175,7 +175,7 @@ void HTMLScriptElement::dispatchErrorEvent() PassRefPtr<Element> HTMLScriptElement::cloneElementWithoutAttributesAndChildren() const { - return adoptRef(new HTMLScriptElement(tagQName(), document(), false, isEvaluated())); + return adoptRef(new HTMLScriptElement(tagQName(), document(), false, wasAlreadyStarted())); } } diff --git a/WebCore/html/HTMLScriptElement.h b/WebCore/html/HTMLScriptElement.h index 5b91ecc..09773c5 100644 --- a/WebCore/html/HTMLScriptElement.h +++ b/WebCore/html/HTMLScriptElement.h @@ -31,17 +31,15 @@ namespace WebCore { class HTMLScriptElement : public HTMLElement, public ScriptElement { public: - static PassRefPtr<HTMLScriptElement> create(const QualifiedName&, Document*, bool createdByParser); + static PassRefPtr<HTMLScriptElement> create(const QualifiedName&, Document*, bool wasInsertedByParser); String text() const { return scriptContent(); } void setText(const String&); KURL src() const; - bool haveFiredLoadEvent() const { return ScriptElement::haveFiredLoadEvent(); } - private: - HTMLScriptElement(const QualifiedName&, Document*, bool createdByParser, bool isEvaluated); + HTMLScriptElement(const QualifiedName&, Document*, bool wasInsertedByParser, bool wasAlreadyStarted); virtual void parseMappedAttribute(Attribute*); virtual void insertedIntoDocument(); diff --git a/WebCore/html/HTMLStyleElement.idl b/WebCore/html/HTMLStyleElement.idl index 29a8924..d78e9d3 100644 --- a/WebCore/html/HTMLStyleElement.idl +++ b/WebCore/html/HTMLStyleElement.idl @@ -20,7 +20,7 @@ module html { - interface HTMLStyleElement : HTMLElement { + interface [CustomMarkFunction] HTMLStyleElement : HTMLElement { attribute [Reflect] boolean disabled; attribute [Reflect] DOMString media; attribute [Reflect] DOMString type; diff --git a/WebCore/html/HTMLTagNames.in b/WebCore/html/HTMLTagNames.in index be2cf90..cd4ebcc 100644 --- a/WebCore/html/HTMLTagNames.in +++ b/WebCore/html/HTMLTagNames.in @@ -83,7 +83,7 @@ mark interfaceName=HTMLElement marquee menu meta -meter interfaceName=HTMLMeterElement, conditional=METER_TAG +meter interfaceName=HTMLMeterElement, constructorNeedsFormElement, conditional=METER_TAG nav interfaceName=HTMLElement nobr interfaceName=HTMLElement noembed interfaceName=HTMLElement @@ -98,7 +98,7 @@ p interfaceName=HTMLParagraphElement param plaintext interfaceName=HTMLElement pre -progress interfaceName=HTMLProgressElement, conditional=PROGRESS_TAG +progress interfaceName=HTMLProgressElement, constructorNeedsFormElement, conditional=PROGRESS_TAG q interfaceName=HTMLQuoteElement rp interfaceName=HTMLElement rt interfaceName=HTMLElement diff --git a/WebCore/html/InputType.cpp b/WebCore/html/InputType.cpp index 6dd002c..8a7a979 100644 --- a/WebCore/html/InputType.cpp +++ b/WebCore/html/InputType.cpp @@ -41,6 +41,7 @@ #include "HiddenInputType.h" #include "ImageInputType.h" #include "IsIndexInputType.h" +#include "KeyboardEvent.h" #include "LocalizedStrings.h" #include "MonthInputType.h" #include "NumberInputType.h" @@ -125,6 +126,11 @@ bool InputType::isTextType() const return false; } +bool InputType::isRangeControl() const +{ + return false; +} + bool InputType::saveFormControlState(String& result) const { String currentValue = element()->value(); @@ -213,6 +219,11 @@ bool InputType::rangeOverflow(const String&) const return false; } +double InputType::defaultValueForStepUp() const +{ + return 0; +} + double InputType::minimum() const { ASSERT_NOT_REACHED(); @@ -275,6 +286,11 @@ String InputType::typeMismatchText() const return validationMessageTypeMismatchText(); } +String InputType::valueMissingText() const +{ + return validationMessageValueMissingText(); +} + bool InputType::handleClickEvent(MouseEvent*) { return false; @@ -290,6 +306,21 @@ bool InputType::handleKeydownEvent(KeyboardEvent*) return false; } +bool InputType::handleKeypressEvent(KeyboardEvent*) +{ + return false; +} + +bool InputType::handleKeyupEvent(KeyboardEvent*) +{ + return false; +} + +bool InputType::shouldSubmitImplicitly(Event* event) +{ + return event->isKeyboardEvent() && event->type() == eventNames().keypressEvent && static_cast<KeyboardEvent*>(event)->charCode() == '\r'; +} + RenderObject* InputType::createRenderer(RenderArena*, RenderStyle* style) const { return RenderObject::createObject(element(), style); @@ -319,6 +350,12 @@ String InputType::serialize(double) const return String(); } +void InputType::dispatchSimulatedClickIfActive(KeyboardEvent* event) const +{ + if (element()->active()) + element()->dispatchSimulatedClick(event); + event->setDefaultHandled(); +} namespace InputTypeNames { @@ -472,4 +509,3 @@ const AtomicString& week() } // namespace WebCore::InpuTypeNames } // namespace WebCore - diff --git a/WebCore/html/InputType.h b/WebCore/html/InputType.h index f1a5b6d..f275ae8 100644 --- a/WebCore/html/InputType.h +++ b/WebCore/html/InputType.h @@ -60,6 +60,7 @@ public: virtual bool isTextField() const; virtual bool isTextType() const; + virtual bool isRangeControl() const; virtual const AtomicString& formControlType() const = 0; // Form value functions @@ -89,6 +90,7 @@ public: virtual bool patternMismatch(const String&) const; virtual bool rangeUnderflow(const String&) const; virtual bool rangeOverflow(const String&) const; + virtual double defaultValueForStepUp() const; virtual double minimum() const; virtual double maximum() const; virtual bool stepMismatch(const String&, double) const; @@ -100,6 +102,7 @@ public: virtual bool scaledStepValeuShouldBeInteger() const; virtual double acceptableError(double) const; virtual String typeMismatchText() const; + virtual String valueMissingText() const; // Event handlers // If the return value is true, do no further default event handling in the @@ -109,6 +112,10 @@ public: virtual bool handleClickEvent(MouseEvent*); virtual bool handleDOMActivateEvent(Event*); virtual bool handleKeydownEvent(KeyboardEvent*); + virtual bool handleKeypressEvent(KeyboardEvent*); + virtual bool handleKeyupEvent(KeyboardEvent*); + // A helper for event handlers. + virtual bool shouldSubmitImplicitly(Event*); // Miscellaneous functions @@ -136,6 +143,7 @@ public: protected: InputType(HTMLInputElement* element) : m_element(element) { } HTMLInputElement* element() const { return m_element; } + void dispatchSimulatedClickIfActive(KeyboardEvent*) const; // We can't make this a static const data member because VC++ doesn't like it. static double defaultStepBase() { return 0.0; } diff --git a/WebCore/html/MonthInputType.cpp b/WebCore/html/MonthInputType.cpp index cbde5cb..38f9d00 100644 --- a/WebCore/html/MonthInputType.cpp +++ b/WebCore/html/MonthInputType.cpp @@ -34,6 +34,8 @@ #include "DateComponents.h" #include "HTMLInputElement.h" #include "HTMLNames.h" +#include <wtf/CurrentTime.h> +#include <wtf/DateMath.h> #include <wtf/MathExtras.h> #include <wtf/PassOwnPtr.h> @@ -74,6 +76,21 @@ void MonthInputType::setValueAsDate(double value, ExceptionCode&) const element()->setValue(date.toString()); } +double MonthInputType::defaultValueForStepUp() const +{ + double current = currentTimeMS(); + double utcOffset = calculateUTCOffset(); + double dstOffset = calculateDSTOffset(current, utcOffset); + int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute); + current += offset * msPerMinute; + + DateComponents date; + date.setMillisecondsSinceEpochForMonth(current); + double months = date.monthsSinceEpoch(); + ASSERT(isfinite(months)); + return months; +} + double MonthInputType::minimum() const { return parseToDouble(element()->fastGetAttribute(minAttr), DateComponents::minimumMonth()); diff --git a/WebCore/html/MonthInputType.h b/WebCore/html/MonthInputType.h index 50cf7d5..23536e2 100644 --- a/WebCore/html/MonthInputType.h +++ b/WebCore/html/MonthInputType.h @@ -45,6 +45,7 @@ private: virtual double valueAsDate() const; virtual void setValueAsDate(double, ExceptionCode&) const; virtual double parseToDouble(const String&, double) const; + virtual double defaultValueForStepUp() const; virtual double minimum() const; virtual double maximum() const; virtual double defaultStep() const; diff --git a/WebCore/html/RadioInputType.cpp b/WebCore/html/RadioInputType.cpp index a6c4707..4c459be 100644 --- a/WebCore/html/RadioInputType.cpp +++ b/WebCore/html/RadioInputType.cpp @@ -1,42 +1,41 @@ /* + * Copyright (C) 2005 Apple Inc. All rights reserved. * Copyright (C) 2010 Google Inc. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: + * 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. * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. + * This 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. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "RadioInputType.h" +#include "Frame.h" #include "HTMLInputElement.h" +#include "HTMLNames.h" +#include "KeyboardEvent.h" +#include "LocalizedStrings.h" #include "MouseEvent.h" +#include "Settings.h" +#include "SpatialNavigation.h" #include <wtf/PassOwnPtr.h> namespace WebCore { +using namespace HTMLNames; + PassOwnPtr<InputType> RadioInputType::create(HTMLInputElement* element) { return adoptPtr(new RadioInputType(element)); @@ -52,10 +51,70 @@ bool RadioInputType::valueMissing(const String&) const return !element()->checkedRadioButtons().checkedButtonForGroup(element()->name()); } +String RadioInputType::valueMissingText() const +{ + return validationMessageValueMissingForRadioText(); +} + bool RadioInputType::handleClickEvent(MouseEvent* event) { event->setDefaultHandled(); return true; } +bool RadioInputType::handleKeydownEvent(KeyboardEvent* event) +{ + if (BaseCheckableInputType::handleKeydownEvent(event)) + return true; + const String& key = event->keyIdentifier(); + if (key != "Up" && key != "Down" && key != "Left" && key != "Right") + return false; + + // Left and up mean "previous radio button". + // Right and down mean "next radio button". + // Tested in WinIE, and even for RTL, left still means previous radio button (and so moves + // to the right). Seems strange, but we'll match it. + // However, when using Spatial Navigation, we need to be able to navigate without changing the selection. + Document* document = element()->document(); + if (isSpatialNavigationEnabled(document->frame())) + return false; + bool forward = (key == "Down" || key == "Right"); + + // We can only stay within the form's children if the form hasn't been demoted to a leaf because + // of malformed HTML. + Node* node = element(); + while ((node = (forward ? node->traverseNextNode() : node->traversePreviousNode()))) { + // Once we encounter a form element, we know we're through. + if (node->hasTagName(formTag)) + break; + // Look for more radio buttons. + if (!node->hasTagName(inputTag)) + continue; + HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(node); + if (inputElement->form() != element()->form()) + break; + if (inputElement->isRadioButton() && inputElement->name() == element()->name() && inputElement->isFocusable()) { + inputElement->setChecked(true); + document->setFocusedNode(inputElement); + inputElement->dispatchSimulatedClick(event, false, false); + event->setDefaultHandled(); + return true; + } + } + return false; +} + +bool RadioInputType::handleKeyupEvent(KeyboardEvent* event) +{ + const String& key = event->keyIdentifier(); + if (key != "U+0020") + return false; + // If an unselected radio is tabbed into (because the entire group has nothing + // checked, or because of some explicit .focus() call), then allow space to check it. + if (element()->checked()) + return false; + dispatchSimulatedClickIfActive(event); + return true; +} + } // namespace WebCore diff --git a/WebCore/html/RadioInputType.h b/WebCore/html/RadioInputType.h index 2798010..62becf6 100644 --- a/WebCore/html/RadioInputType.h +++ b/WebCore/html/RadioInputType.h @@ -43,7 +43,10 @@ private: RadioInputType(HTMLInputElement* element) : BaseCheckableInputType(element) { } virtual const AtomicString& formControlType() const; virtual bool valueMissing(const String&) const; + virtual String valueMissingText() const; virtual bool handleClickEvent(MouseEvent*); + virtual bool handleKeydownEvent(KeyboardEvent*); + virtual bool handleKeyupEvent(KeyboardEvent*); }; } // namespace WebCore diff --git a/WebCore/html/RangeInputType.cpp b/WebCore/html/RangeInputType.cpp index ad47f14..50520cd 100644 --- a/WebCore/html/RangeInputType.cpp +++ b/WebCore/html/RangeInputType.cpp @@ -55,6 +55,11 @@ PassOwnPtr<InputType> RangeInputType::create(HTMLInputElement* element) return adoptPtr(new RangeInputType(element)); } +bool RangeInputType::isRangeControl() const +{ + return true; +} + const AtomicString& RangeInputType::formControlType() const { return InputTypeNames::range(); @@ -143,6 +148,9 @@ bool RangeInputType::handleKeydownEvent(KeyboardEvent* event) double step = (max - min) / 100; double current = parseToDouble(element()->value(), numeric_limits<double>::quiet_NaN()); ASSERT(isfinite(current)); + // Stepping-up and -down for step="any" are special cases for type="range" from renderer for convenient. + // No stepping normally for step="any". They cannot be handled by stepUp()/stepDown()/stepUpFromRenderer(). + // So calculating values stepped-up or -down here. double newValue; if (key == "Up" || key == "Right") { newValue = current + step; @@ -159,10 +167,8 @@ bool RangeInputType::handleKeydownEvent(KeyboardEvent* event) } } else { int stepMagnification = (key == "Up" || key == "Right") ? 1 : -1; - String lastStringValue = element()->value(); - element()->stepUp(stepMagnification, ec); - if (lastStringValue != element()->value()) - element()->dispatchFormControlChangeEvent(); + // Reasonable stepping-up/-down by stepUpFromRenderer() unless step="any" + element()->stepUpFromRenderer(stepMagnification); } event->setDefaultHandled(); return true; diff --git a/WebCore/html/RangeInputType.h b/WebCore/html/RangeInputType.h index c2bbb0f..14280e8 100644 --- a/WebCore/html/RangeInputType.h +++ b/WebCore/html/RangeInputType.h @@ -41,6 +41,7 @@ public: private: RangeInputType(HTMLInputElement* element) : InputType(element) { } + virtual bool isRangeControl() const; virtual const AtomicString& formControlType() const; virtual double valueAsNumber() const; virtual void setValueAsNumber(double, ExceptionCode&) const; diff --git a/WebCore/html/TextFieldInputType.cpp b/WebCore/html/TextFieldInputType.cpp index d93f972..8b74359 100644 --- a/WebCore/html/TextFieldInputType.cpp +++ b/WebCore/html/TextFieldInputType.cpp @@ -35,6 +35,7 @@ #include "HTMLInputElement.h" #include "KeyboardEvent.h" #include "RenderTextControlSingleLine.h" +#include "TextEvent.h" #include <wtf/text/WTFString.h> namespace WebCore { @@ -75,6 +76,11 @@ bool TextFieldInputType::handleKeydownEventForSpinButton(KeyboardEvent* event) return true; } +bool TextFieldInputType::shouldSubmitImplicitly(Event* event) +{ + return (event->type() == eventNames().textInputEvent && event->isTextEvent() && static_cast<TextEvent*>(event)->data() == "\n") || InputType::shouldSubmitImplicitly(event); +} + RenderObject* TextFieldInputType::createRenderer(RenderArena* arena, RenderStyle*) const { return new (arena) RenderTextControlSingleLine(element(), element()->placeholderShouldBeVisible()); diff --git a/WebCore/html/TextFieldInputType.h b/WebCore/html/TextFieldInputType.h index 50418aa..07f06e9 100644 --- a/WebCore/html/TextFieldInputType.h +++ b/WebCore/html/TextFieldInputType.h @@ -44,6 +44,7 @@ protected: virtual bool valueMissing(const String&) const; virtual bool handleKeydownEvent(KeyboardEvent*); bool handleKeydownEventForSpinButton(KeyboardEvent*); + virtual bool shouldSubmitImplicitly(Event*); virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) const; }; diff --git a/WebCore/html/TimeInputType.cpp b/WebCore/html/TimeInputType.cpp index 27dce90..6b381be 100644 --- a/WebCore/html/TimeInputType.cpp +++ b/WebCore/html/TimeInputType.cpp @@ -34,6 +34,9 @@ #include "DateComponents.h" #include "HTMLInputElement.h" #include "HTMLNames.h" +#include <wtf/CurrentTime.h> +#include <wtf/DateMath.h> +#include <wtf/MathExtras.h> #include <wtf/PassOwnPtr.h> namespace WebCore { @@ -53,6 +56,21 @@ const AtomicString& TimeInputType::formControlType() const return InputTypeNames::time(); } +double TimeInputType::defaultValueForStepUp() const +{ + double current = currentTimeMS(); + double utcOffset = calculateUTCOffset(); + double dstOffset = calculateDSTOffset(current, utcOffset); + int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute); + current += offset * msPerMinute; + + DateComponents date; + date.setMillisecondsSinceMidnight(current); + double milliseconds = date.millisecondsSinceEpoch(); + ASSERT(isfinite(milliseconds)); + return milliseconds; +} + double TimeInputType::minimum() const { return parseToDouble(element()->fastGetAttribute(minAttr), DateComponents::minimumTime()); diff --git a/WebCore/html/TimeInputType.h b/WebCore/html/TimeInputType.h index 6070fa0..b50d987 100644 --- a/WebCore/html/TimeInputType.h +++ b/WebCore/html/TimeInputType.h @@ -42,6 +42,7 @@ public: private: TimeInputType(HTMLInputElement* element) : BaseDateAndTimeInputType(element) { } virtual const AtomicString& formControlType() const; + virtual double defaultValueForStepUp() const; virtual double minimum() const; virtual double maximum() const; virtual double defaultStep() const; diff --git a/WebCore/html/ValidityState.cpp b/WebCore/html/ValidityState.cpp index 84fc664..ef3de66 100644 --- a/WebCore/html/ValidityState.cpp +++ b/WebCore/html/ValidityState.cpp @@ -42,17 +42,24 @@ String ValidityState::validationMessage() const if (customError()) return m_customErrorMessage; - if (valueMissing()) - return validationMessageValueMissingText(); - if (patternMismatch()) - return validationMessagePatternMismatchText(); bool isInputElement = m_control->hasTagName(inputTag); bool isTextAreaElement = m_control->hasTagName(textareaTag); + // The order of the following checks is meaningful. e.g. We'd like to show the + // valueMissing message even if the control has other validation errors. + if (valueMissing()) { + if (m_control->hasTagName(selectTag)) + return validationMessageValueMissingForSelectText(); + if (isInputElement) + return static_cast<HTMLInputElement*>(m_control)->valueMissingText(); + return validationMessageValueMissingText(); + } if (typeMismatch()) { if (isInputElement) return static_cast<HTMLInputElement*>(m_control)->typeMismatchText(); return validationMessageTypeMismatchText(); } + if (patternMismatch()) + return validationMessagePatternMismatchText(); if (tooLong()) { if (!isInputElement && !isTextAreaElement) { ASSERT_NOT_REACHED(); diff --git a/WebCore/html/canvas/ArrayBuffer.cpp b/WebCore/html/canvas/ArrayBuffer.cpp index ee8f149..2136f64 100644 --- a/WebCore/html/canvas/ArrayBuffer.cpp +++ b/WebCore/html/canvas/ArrayBuffer.cpp @@ -85,7 +85,10 @@ ArrayBuffer::~ArrayBuffer() void* ArrayBuffer::tryAllocate(unsigned numElements, unsigned elementByteSize) { void* result; - // Do not allow 32-bit overflow of the total size + // Do not allow 32-bit overflow of the total size. + // FIXME: Why not? The tryFastCalloc function already checks its arguments, + // and will fail if there is any overflow, so why should we include a + // redudant unnecessarily restrictive check here? if (numElements) { unsigned totalSize = numElements * elementByteSize; if (totalSize / numElements != elementByteSize) diff --git a/WebCore/html/canvas/ArrayBufferView.h b/WebCore/html/canvas/ArrayBufferView.h index ee685b1..701abbc 100644 --- a/WebCore/html/canvas/ArrayBufferView.h +++ b/WebCore/html/canvas/ArrayBufferView.h @@ -46,6 +46,7 @@ class ArrayBufferView : public RefCounted<ArrayBufferView> { virtual bool isIntArray() const { return false; } virtual bool isUnsignedIntArray() const { return false; } virtual bool isFloatArray() const { return false; } + virtual bool isDataView() const { return false; } PassRefPtr<ArrayBuffer> buffer() const { @@ -62,9 +63,7 @@ class ArrayBufferView : public RefCounted<ArrayBufferView> { return m_byteOffset; } - virtual unsigned length() const = 0; virtual unsigned byteLength() const = 0; - virtual PassRefPtr<ArrayBufferView> slice(int start, int end) const = 0; virtual ~ArrayBufferView(); diff --git a/WebCore/html/canvas/ArrayBufferView.idl b/WebCore/html/canvas/ArrayBufferView.idl index 74a3fe3..be217c1 100644 --- a/WebCore/html/canvas/ArrayBufferView.idl +++ b/WebCore/html/canvas/ArrayBufferView.idl @@ -28,8 +28,5 @@ module html { readonly attribute ArrayBuffer buffer; readonly attribute unsigned long byteOffset; readonly attribute unsigned long byteLength; - readonly attribute unsigned long length; - - [Custom] ArrayBufferView slice(in long start, in long end); }; } diff --git a/WebCore/html/canvas/CanvasRenderingContext2D.cpp b/WebCore/html/canvas/CanvasRenderingContext2D.cpp index b9f86ce..eb552c6 100644 --- a/WebCore/html/canvas/CanvasRenderingContext2D.cpp +++ b/WebCore/html/canvas/CanvasRenderingContext2D.cpp @@ -813,9 +813,7 @@ void CanvasRenderingContext2D::fill() return; if (!m_path.isEmpty()) { - c->beginPath(); - c->addPath(m_path); - c->fillPath(); + c->fillPath(m_path); didDraw(m_path.boundingRect()); } @@ -833,9 +831,6 @@ void CanvasRenderingContext2D::stroke() return; if (!m_path.isEmpty()) { - c->beginPath(); - c->addPath(m_path); - #if PLATFORM(QT) // Fast approximation of the stroke's bounding rect. // This yields a slightly oversized rect but is very fast @@ -846,7 +841,7 @@ void CanvasRenderingContext2D::stroke() CanvasStrokeStyleApplier strokeApplier(this); FloatRect boundingRect = m_path.strokeBoundingRect(&strokeApplier); #endif - c->strokePath(); + c->strokePath(m_path); didDraw(boundingRect); } diff --git a/WebCore/html/canvas/DataView.cpp b/WebCore/html/canvas/DataView.cpp new file mode 100755 index 0000000..d030211 --- /dev/null +++ b/WebCore/html/canvas/DataView.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(3D_CANVAS) || ENABLE(BLOB) + +#include "DataView.h" + +namespace { + +template<typename T> +union Value { + T data; + char bytes[sizeof(T)]; +}; + +} + +namespace WebCore { + +PassRefPtr<DataView> DataView::create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned byteLength) +{ + if (byteOffset + byteLength > buffer->byteLength()) + return 0; + return adoptRef(new DataView(buffer, byteOffset, byteLength)); +} + +DataView::DataView(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned byteLength) + : ArrayBufferView(buffer, byteOffset) + , m_byteLength(byteLength) +{ +} + +static bool needToFlipBytes(bool littleEndian) +{ +#if CPU(BIG_ENDIAN) + return littleEndian; +#else + return !littleEndian; +#endif +} + +inline void swapBytes(char* p, char* q) +{ + char temp = *p; + *p = *q; + *q = temp; +} + +static void flipBytesFor16Bits(char* p) +{ + swapBytes(p, p + 1); +} + +static void flipBytesFor32Bits(char* p) +{ + swapBytes(p, p + 3); + swapBytes(p + 1, p + 2); +} + +static void flipBytesFor64Bits(char* p) +{ + swapBytes(p, p + 7); + swapBytes(p + 1, p + 6); + swapBytes(p + 2, p + 5); + swapBytes(p + 3, p + 4); +} + +static void flipBytesIfNeeded(char* value, size_t size, bool littleEndian) +{ + if (!needToFlipBytes(littleEndian)) + return; + + switch (size) { + case 1: + // Nothing to do. + break; + case 2: + flipBytesFor16Bits(value); + break; + case 4: + flipBytesFor32Bits(value); + break; + case 8: + flipBytesFor64Bits(value); + break; + default: + ASSERT_NOT_REACHED(); + break; + } +} + +template<typename T> +T DataView::getData(unsigned byteOffset, bool littleEndian, ExceptionCode& ec) const +{ + if (beyondRange<T>(byteOffset)) { + ec = INDEX_SIZE_ERR; + return 0; + } + + // We do not want to load the data directly since it would cause a bus error on architectures that don't support unaligned loads. + Value<T> value; + memcpy(value.bytes, static_cast<const char*>(m_baseAddress) + byteOffset, sizeof(T)); + flipBytesIfNeeded(value.bytes, sizeof(T), littleEndian); + return value.data; +} + +template<typename T> +void DataView::setData(unsigned byteOffset, T value, bool littleEndian, ExceptionCode& ec) +{ + if (beyondRange<T>(byteOffset)) { + ec = INDEX_SIZE_ERR; + return; + } + + // We do not want to store the data directly since it would cause a bus error on architectures that don't support unaligned stores. + Value<T> tempValue; + tempValue.data = value; + flipBytesIfNeeded(tempValue.bytes, sizeof(T), littleEndian); + memcpy(static_cast<char*>(m_baseAddress) + byteOffset, tempValue.bytes, sizeof(T)); +} + +char DataView::getInt8(unsigned byteOffset, ExceptionCode& ec) +{ + return getData<char>(byteOffset, false, ec); +} + +unsigned char DataView::getUint8(unsigned byteOffset, ExceptionCode& ec) +{ + return getData<unsigned char>(byteOffset, false, ec); +} + +short DataView::getInt16(unsigned byteOffset, bool littleEndian, ExceptionCode& ec) +{ + return getData<short>(byteOffset, littleEndian, ec); +} + +unsigned short DataView::getUint16(unsigned byteOffset, bool littleEndian, ExceptionCode& ec) +{ + return getData<unsigned short>(byteOffset, littleEndian, ec); +} + +int DataView::getInt32(unsigned byteOffset, bool littleEndian, ExceptionCode& ec) +{ + return getData<int>(byteOffset, littleEndian, ec); +} + +unsigned DataView::getUint32(unsigned byteOffset, bool littleEndian, ExceptionCode& ec) +{ + return getData<unsigned>(byteOffset, littleEndian, ec); +} + +float DataView::getFloat32(unsigned byteOffset, bool littleEndian, ExceptionCode& ec) +{ + return getData<float>(byteOffset, littleEndian, ec); +} + +double DataView::getFloat64(unsigned byteOffset, bool littleEndian, ExceptionCode& ec) +{ + return getData<double>(byteOffset, littleEndian, ec); +} + +void DataView::setInt8(unsigned byteOffset, char value, ExceptionCode& ec) +{ + setData<char>(byteOffset, value, false, ec); +} + +void DataView::setUint8(unsigned byteOffset, unsigned char value, ExceptionCode& ec) +{ + setData<unsigned char>(byteOffset, value, false, ec); +} + +void DataView::setInt16(unsigned byteOffset, short value, bool littleEndian, ExceptionCode& ec) +{ + setData<short>(byteOffset, value, littleEndian, ec); +} + +void DataView::setUint16(unsigned byteOffset, unsigned short value, bool littleEndian, ExceptionCode& ec) +{ + setData<unsigned short>(byteOffset, value, littleEndian, ec); +} + +void DataView::setInt32(unsigned byteOffset, int value, bool littleEndian, ExceptionCode& ec) +{ + setData<int>(byteOffset, value, littleEndian, ec); +} + +void DataView::setUint32(unsigned byteOffset, unsigned value, bool littleEndian, ExceptionCode& ec) +{ + setData<unsigned>(byteOffset, value, littleEndian, ec); +} + +void DataView::setFloat32(unsigned byteOffset, float value, bool littleEndian, ExceptionCode& ec) +{ + setData<float>(byteOffset, value, littleEndian, ec); +} + +void DataView::setFloat64(unsigned byteOffset, double value, bool littleEndian, ExceptionCode& ec) +{ + setData<double>(byteOffset, value, littleEndian, ec); +} + +} + +#endif // ENABLE(3D_CANVAS) || ENABLE(BLOB) diff --git a/WebCore/html/canvas/DataView.h b/WebCore/html/canvas/DataView.h new file mode 100755 index 0000000..0681341 --- /dev/null +++ b/WebCore/html/canvas/DataView.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DataView_h +#define DataView_h + +#include "ArrayBufferView.h" +#include "ExceptionCode.h" +#include <wtf/PassRefPtr.h> + +namespace WebCore { + +class DataView : public ArrayBufferView { +public: + static PassRefPtr<DataView> create(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned byteLength); + + virtual bool isDataView() const { return true; } + virtual unsigned length() const { return m_byteLength; } + virtual unsigned byteLength() const { return m_byteLength; } + virtual PassRefPtr<ArrayBufferView> slice(int, int) const { return 0; } + + char getInt8(unsigned byteOffset, ExceptionCode&); + unsigned char getUint8(unsigned byteOffset, ExceptionCode&); + short getInt16(unsigned byteOffset, ExceptionCode& ec) { return getInt16(byteOffset, false, ec); } + short getInt16(unsigned byteOffset, bool littleEndian, ExceptionCode&); + unsigned short getUint16(unsigned byteOffset, ExceptionCode& ec) { return getUint16(byteOffset, false, ec); } + unsigned short getUint16(unsigned byteOffset, bool littleEndian, ExceptionCode&); + int getInt32(unsigned byteOffset, ExceptionCode& ec) { return getInt32(byteOffset, false, ec); } + int getInt32(unsigned byteOffset, bool littleEndian, ExceptionCode&); + unsigned getUint32(unsigned byteOffset, ExceptionCode& ec) { return getUint32(byteOffset, false, ec); } + unsigned getUint32(unsigned byteOffset, bool littleEndian, ExceptionCode&); + float getFloat32(unsigned byteOffset, ExceptionCode& ec) { return getFloat32(byteOffset, false, ec); } + float getFloat32(unsigned byteOffset, bool littleEndian, ExceptionCode&); + double getFloat64(unsigned byteOffset, ExceptionCode& ec) { return getFloat64(byteOffset, false, ec); } + double getFloat64(unsigned byteOffset, bool littleEndian, ExceptionCode&); + + void setInt8(unsigned byteOffset, char value, ExceptionCode&); + void setUint8(unsigned byteOffset, unsigned char value, ExceptionCode&); + void setInt16(unsigned byteOffset, short value, ExceptionCode& ec) { setInt16(byteOffset, value, false, ec); } + void setInt16(unsigned byteOffset, short value, bool littleEndian, ExceptionCode&); + void setUint16(unsigned byteOffset, unsigned short value, ExceptionCode& ec) { setUint16(byteOffset, value, false, ec); } + void setUint16(unsigned byteOffset, unsigned short value, bool littleEndian, ExceptionCode&); + void setInt32(unsigned byteOffset, int value, ExceptionCode& ec) { setInt32(byteOffset, value, false, ec); } + void setInt32(unsigned byteOffset, int value, bool littleEndian, ExceptionCode&); + void setUint32(unsigned byteOffset, unsigned value, ExceptionCode& ec) { setUint32(byteOffset, value, false, ec); } + void setUint32(unsigned byteOffset, unsigned value, bool littleEndian, ExceptionCode&); + void setFloat32(unsigned byteOffset, float value, ExceptionCode& ec) { setFloat32(byteOffset, value, false, ec); } + void setFloat32(unsigned byteOffset, float value, bool littleEndian, ExceptionCode&); + void setFloat64(unsigned byteOffset, double value, ExceptionCode& ec) { setFloat64(byteOffset, value, false, ec); } + void setFloat64(unsigned byteOffset, double value, bool littleEndian, ExceptionCode&); + +private: + DataView(PassRefPtr<ArrayBuffer>, unsigned byteOffset, unsigned byteLength); + + template<typename T> + inline bool beyondRange(unsigned byteOffset) const { return byteOffset + sizeof(T) > m_byteLength; } + + template<typename T> + T getData(unsigned byteOffset, bool littleEndian, ExceptionCode&) const; + + template<typename T> + void setData(unsigned byteOffset, T value, bool littleEndian, ExceptionCode&); + + unsigned m_byteLength; +}; + + +} // namespace WebCore + +#endif // DataView_h diff --git a/WebCore/html/canvas/DataView.idl b/WebCore/html/canvas/DataView.idl new file mode 100755 index 0000000..bef8805 --- /dev/null +++ b/WebCore/html/canvas/DataView.idl @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module html { + + interface [ + Conditional=3D_CANVAS|BLOB, + CanBeConstructed, + CustomConstructFunction, + CustomToJS, + NoStaticTables, + V8CustomConstructor + ] DataView : ArrayBufferView { + // All these methods raise an exception if they would read or write beyond the end of the view. + + // We have to use custom code because our code generator does not support char type. + // char getInt8(in unsigned long byteOffset); + // unsigned char getUint8(in unsigned long byteOffset); + [Custom] DOMObject getInt8() + raises (DOMException); + [Custom] DOMObject getUint8() + raises (DOMException); + + [StrictTypeChecking, RequiresAllArguments=Raise] short getInt16(in unsigned long byteOffset, in [Optional] boolean littleEndian) + raises (DOMException); + [StrictTypeChecking, RequiresAllArguments=Raise] unsigned short getUint16(in unsigned long byteOffset, in [Optional] boolean littleEndian) + raises (DOMException); + [StrictTypeChecking, RequiresAllArguments=Raise] long getInt32(in unsigned long byteOffset, in [Optional] boolean littleEndian) + raises (DOMException); + [StrictTypeChecking, RequiresAllArguments=Raise] unsigned long getUint32(in unsigned long byteOffset, in [Optional] boolean littleEndian) + raises (DOMException); + + // Use custom code to handle NaN case for JSC. + [JSCCustom, StrictTypeChecking, RequiresAllArguments=Raise] float getFloat32(in unsigned long byteOffset, in [Optional] boolean littleEndian) + raises (DOMException); + [JSCCustom, StrictTypeChecking, RequiresAllArguments=Raise] double getFloat64(in unsigned long byteOffset, in [Optional] boolean littleEndian) + raises (DOMException); + + // We have to use custom code because our code generator does not support char type. + // void setInt8(in unsigned long byteOffset, in byte value); + // void setUint8(in unsigned long byteOffset, in unsigned byte value); + [Custom] void setInt8() + raises (DOMException); + [Custom] void setUint8() + raises (DOMException); + + [StrictTypeChecking, RequiresAllArguments=Raise] void setInt16(in unsigned long byteOffset, in short value, in [Optional] boolean littleEndian) + raises (DOMException); + [StrictTypeChecking, RequiresAllArguments=Raise] void setUint16(in unsigned long byteOffset, in unsigned short value, in [Optional] boolean littleEndian) + raises (DOMException); + [StrictTypeChecking, RequiresAllArguments=Raise] void setInt32(in unsigned long byteOffset, in long value, in [Optional] boolean littleEndian) + raises (DOMException); + [StrictTypeChecking, RequiresAllArguments=Raise] void setUint32(in unsigned long byteOffset, in unsigned long value, in [Optional] boolean littleEndian) + raises (DOMException); + [StrictTypeChecking, RequiresAllArguments=Raise] void setFloat32(in unsigned long byteOffset, in float value, in [Optional] boolean littleEndian) + raises (DOMException); + [StrictTypeChecking, RequiresAllArguments=Raise] void setFloat64(in unsigned long byteOffset, in double value, in [Optional] boolean littleEndian) + raises (DOMException); + }; + +} diff --git a/WebCore/html/canvas/Float32Array.cpp b/WebCore/html/canvas/Float32Array.cpp index e918d8f..1b26aef 100644 --- a/WebCore/html/canvas/Float32Array.cpp +++ b/WebCore/html/canvas/Float32Array.cpp @@ -52,7 +52,12 @@ Float32Array::Float32Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, { } -PassRefPtr<ArrayBufferView> Float32Array::slice(int start, int end) const +PassRefPtr<Float32Array> Float32Array::slice(int start) const +{ + return slice(start, length()); +} + +PassRefPtr<Float32Array> Float32Array::slice(int start, int end) const { return sliceImpl<Float32Array>(start, end); } diff --git a/WebCore/html/canvas/Float32Array.h b/WebCore/html/canvas/Float32Array.h index ab57087..c03fcc3 100644 --- a/WebCore/html/canvas/Float32Array.h +++ b/WebCore/html/canvas/Float32Array.h @@ -33,7 +33,7 @@ namespace WebCore { class Float32Array : public TypedArrayBase<float> { - public: +public: static PassRefPtr<Float32Array> create(unsigned length); static PassRefPtr<Float32Array> create(const float* array, unsigned length); static PassRefPtr<Float32Array> create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length); @@ -62,7 +62,10 @@ class Float32Array : public TypedArrayBase<float> { return result; } - private: + PassRefPtr<Float32Array> slice(int start) const; + PassRefPtr<Float32Array> slice(int start, int end) const; + +private: Float32Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length); @@ -71,7 +74,6 @@ class Float32Array : public TypedArrayBase<float> { // Overridden from ArrayBufferView. virtual bool isFloatArray() const { return true; } - virtual PassRefPtr<ArrayBufferView> slice(int start, int end) const; }; } // namespace WebCore diff --git a/WebCore/html/canvas/Float32Array.idl b/WebCore/html/canvas/Float32Array.idl index c3c0a2d..b979d29 100644 --- a/WebCore/html/canvas/Float32Array.idl +++ b/WebCore/html/canvas/Float32Array.idl @@ -39,6 +39,9 @@ module html { ] Float32Array : ArrayBufferView { const unsigned int BYTES_PER_ELEMENT = 4; + readonly attribute unsigned long length; + Float32Array slice(in long start, in [Optional] long end); + // void set(in Float32Array array, [Optional] in unsigned long offset); // void set(in sequence<long> array, [Optional] in unsigned long offset); [Custom] void set(); diff --git a/WebCore/html/canvas/Int16Array.cpp b/WebCore/html/canvas/Int16Array.cpp index 635ea5e..a3d04bc 100644 --- a/WebCore/html/canvas/Int16Array.cpp +++ b/WebCore/html/canvas/Int16Array.cpp @@ -51,7 +51,12 @@ Int16Array::Int16Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsi { } -PassRefPtr<ArrayBufferView> Int16Array::slice(int start, int end) const +PassRefPtr<Int16Array> Int16Array::slice(int start) const +{ + return slice(start, length()); +} + +PassRefPtr<Int16Array> Int16Array::slice(int start, int end) const { return sliceImpl<Int16Array>(start, end); } diff --git a/WebCore/html/canvas/Int16Array.h b/WebCore/html/canvas/Int16Array.h index 00877ef..a6286c6 100644 --- a/WebCore/html/canvas/Int16Array.h +++ b/WebCore/html/canvas/Int16Array.h @@ -33,7 +33,7 @@ namespace WebCore { class ArrayBuffer; class Int16Array : public IntegralTypedArrayBase<short> { - public: +public: static PassRefPtr<Int16Array> create(unsigned length); static PassRefPtr<Int16Array> create(short* array, unsigned length); static PassRefPtr<Int16Array> create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length); @@ -41,7 +41,10 @@ class Int16Array : public IntegralTypedArrayBase<short> { using TypedArrayBase<short>::set; using IntegralTypedArrayBase<short>::set; - private: + PassRefPtr<Int16Array> slice(int start) const; + PassRefPtr<Int16Array> slice(int start, int end) const; + +private: Int16Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length); @@ -50,7 +53,6 @@ class Int16Array : public IntegralTypedArrayBase<short> { // Overridden from ArrayBufferView. virtual bool isShortArray() const { return true; } - virtual PassRefPtr<ArrayBufferView> slice(int start, int end) const; }; } // namespace WebCore diff --git a/WebCore/html/canvas/Int16Array.idl b/WebCore/html/canvas/Int16Array.idl index 7980a69..f1f5c8b 100644 --- a/WebCore/html/canvas/Int16Array.idl +++ b/WebCore/html/canvas/Int16Array.idl @@ -38,6 +38,9 @@ module html { ] Int16Array : ArrayBufferView { const unsigned int BYTES_PER_ELEMENT = 2; + readonly attribute unsigned long length; + Int16Array slice(in long start, in [Optional] long end); + // void set(in Int16Array array, [Optional] in unsigned long offset); // void set(in sequence<long> array, [Optional] in unsigned long offset); [Custom] void set(); diff --git a/WebCore/html/canvas/Int32Array.cpp b/WebCore/html/canvas/Int32Array.cpp index cc926a3..266c941 100644 --- a/WebCore/html/canvas/Int32Array.cpp +++ b/WebCore/html/canvas/Int32Array.cpp @@ -52,7 +52,12 @@ Int32Array::Int32Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsi { } -PassRefPtr<ArrayBufferView> Int32Array::slice(int start, int end) const +PassRefPtr<Int32Array> Int32Array::slice(int start) const +{ + return slice(start, length()); +} + +PassRefPtr<Int32Array> Int32Array::slice(int start, int end) const { return sliceImpl<Int32Array>(start, end); } diff --git a/WebCore/html/canvas/Int32Array.h b/WebCore/html/canvas/Int32Array.h index bd05450..068a677 100644 --- a/WebCore/html/canvas/Int32Array.h +++ b/WebCore/html/canvas/Int32Array.h @@ -32,7 +32,7 @@ namespace WebCore { class Int32Array : public IntegralTypedArrayBase<int> { - public: +public: static PassRefPtr<Int32Array> create(unsigned length); static PassRefPtr<Int32Array> create(int* array, unsigned length); static PassRefPtr<Int32Array> create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length); @@ -42,7 +42,10 @@ class Int32Array : public IntegralTypedArrayBase<int> { using IntegralTypedArrayBase<int>::set; #endif - private: + PassRefPtr<Int32Array> slice(int start) const; + PassRefPtr<Int32Array> slice(int start, int end) const; + +private: Int32Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length); @@ -51,7 +54,6 @@ class Int32Array : public IntegralTypedArrayBase<int> { // Overridden from ArrayBufferView. virtual bool isIntArray() const { return true; } - virtual PassRefPtr<ArrayBufferView> slice(int start, int end) const; }; } // namespace WebCore diff --git a/WebCore/html/canvas/Int32Array.idl b/WebCore/html/canvas/Int32Array.idl index bd1554d..f96b53c 100644 --- a/WebCore/html/canvas/Int32Array.idl +++ b/WebCore/html/canvas/Int32Array.idl @@ -39,6 +39,9 @@ module html { ] Int32Array : ArrayBufferView { const unsigned int BYTES_PER_ELEMENT = 4; + readonly attribute unsigned long length; + Int32Array slice(in long start, in [Optional] long end); + // void set(in Int32Array array, [Optional] in unsigned long offset); // void set(in sequence<long> array, [Optional] in unsigned long offset); [Custom] void set(); diff --git a/WebCore/html/canvas/Int8Array.cpp b/WebCore/html/canvas/Int8Array.cpp index c2dd2fa..89ed316 100644 --- a/WebCore/html/canvas/Int8Array.cpp +++ b/WebCore/html/canvas/Int8Array.cpp @@ -52,7 +52,12 @@ Int8Array::Int8Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsign { } -PassRefPtr<ArrayBufferView> Int8Array::slice(int start, int end) const +PassRefPtr<Int8Array> Int8Array::slice(int start) const +{ + return slice(start, length()); +} + +PassRefPtr<Int8Array> Int8Array::slice(int start, int end) const { return sliceImpl<Int8Array>(start, end); } diff --git a/WebCore/html/canvas/Int8Array.h b/WebCore/html/canvas/Int8Array.h index d267f7f..a5df302 100644 --- a/WebCore/html/canvas/Int8Array.h +++ b/WebCore/html/canvas/Int8Array.h @@ -34,7 +34,7 @@ namespace WebCore { class ArrayBuffer; class Int8Array : public IntegralTypedArrayBase<signed char> { - public: +public: static PassRefPtr<Int8Array> create(unsigned length); static PassRefPtr<Int8Array> create(signed char* array, unsigned length); static PassRefPtr<Int8Array> create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length); @@ -42,7 +42,10 @@ class Int8Array : public IntegralTypedArrayBase<signed char> { using TypedArrayBase<signed char>::set; using IntegralTypedArrayBase<signed char>::set; - private: + PassRefPtr<Int8Array> slice(int start) const; + PassRefPtr<Int8Array> slice(int start, int end) const; + +private: Int8Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length); @@ -51,7 +54,6 @@ class Int8Array : public IntegralTypedArrayBase<signed char> { // Overridden from ArrayBufferView. virtual bool isByteArray() const { return true; } - virtual PassRefPtr<ArrayBufferView> slice(int start, int end) const; }; } // namespace WebCore diff --git a/WebCore/html/canvas/Int8Array.idl b/WebCore/html/canvas/Int8Array.idl index ec0bdb7..08a608b 100644 --- a/WebCore/html/canvas/Int8Array.idl +++ b/WebCore/html/canvas/Int8Array.idl @@ -39,6 +39,9 @@ module html { ] Int8Array : ArrayBufferView { const unsigned int BYTES_PER_ELEMENT = 1; + readonly attribute unsigned long length; + Int8Array slice(in long start, in [Optional] long end); + // void set(in Int8Array array, [Optional] in unsigned long offset); // void set(in sequence<long> array, [Optional] in unsigned long offset); [Custom] void set(); diff --git a/WebCore/html/canvas/TypedArrayBase.h b/WebCore/html/canvas/TypedArrayBase.h index 77283df..2bef6f0 100644 --- a/WebCore/html/canvas/TypedArrayBase.h +++ b/WebCore/html/canvas/TypedArrayBase.h @@ -55,12 +55,12 @@ class TypedArrayBase : public ArrayBufferView { // Overridden from ArrayBufferView. This must be public because of // rules about inheritance of members in template classes, and // because it is accessed via pointers to subclasses. - virtual unsigned length() const + unsigned length() const { return m_length; } - protected: + protected: TypedArrayBase(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length) : ArrayBufferView(buffer, byteOffset) , m_length(length) diff --git a/WebCore/html/canvas/Uint16Array.cpp b/WebCore/html/canvas/Uint16Array.cpp index a0f891c..5312888 100644 --- a/WebCore/html/canvas/Uint16Array.cpp +++ b/WebCore/html/canvas/Uint16Array.cpp @@ -52,7 +52,12 @@ Uint16Array::Uint16Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, un { } -PassRefPtr<ArrayBufferView> Uint16Array::slice(int start, int end) const +PassRefPtr<Uint16Array> Uint16Array::slice(int start) const +{ + return slice(start, length()); +} + +PassRefPtr<Uint16Array> Uint16Array::slice(int start, int end) const { return sliceImpl<Uint16Array>(start, end); } diff --git a/WebCore/html/canvas/Uint16Array.h b/WebCore/html/canvas/Uint16Array.h index fee31f6..f63b67d 100644 --- a/WebCore/html/canvas/Uint16Array.h +++ b/WebCore/html/canvas/Uint16Array.h @@ -34,7 +34,7 @@ namespace WebCore { class ArrayBuffer; class Uint16Array : public IntegralTypedArrayBase<unsigned short> { - public: +public: static PassRefPtr<Uint16Array> create(unsigned length); static PassRefPtr<Uint16Array> create(unsigned short* array, unsigned length); static PassRefPtr<Uint16Array> create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length); @@ -42,7 +42,10 @@ class Uint16Array : public IntegralTypedArrayBase<unsigned short> { using TypedArrayBase<unsigned short>::set; using IntegralTypedArrayBase<unsigned short>::set; - private: + PassRefPtr<Uint16Array> slice(int start) const; + PassRefPtr<Uint16Array> slice(int start, int end) const; + +private: Uint16Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length); @@ -51,7 +54,6 @@ class Uint16Array : public IntegralTypedArrayBase<unsigned short> { // Overridden from ArrayBufferView. virtual bool isUnsignedShortArray() const { return true; } - virtual PassRefPtr<ArrayBufferView> slice(int start, int end) const; }; } // namespace WebCore diff --git a/WebCore/html/canvas/Uint16Array.idl b/WebCore/html/canvas/Uint16Array.idl index 75a7499..8e778b4 100644 --- a/WebCore/html/canvas/Uint16Array.idl +++ b/WebCore/html/canvas/Uint16Array.idl @@ -39,6 +39,9 @@ module html { ] Uint16Array : ArrayBufferView { const unsigned int BYTES_PER_ELEMENT = 2; + readonly attribute unsigned long length; + Uint16Array slice(in long start, in [Optional] long end); + // void set(in Uint16Array array, [Optional] in unsigned long offset); // void set(in sequence<long> array, [Optional] in unsigned long offset); [Custom] void set(); diff --git a/WebCore/html/canvas/Uint32Array.cpp b/WebCore/html/canvas/Uint32Array.cpp index f49a83a..f5bd959 100644 --- a/WebCore/html/canvas/Uint32Array.cpp +++ b/WebCore/html/canvas/Uint32Array.cpp @@ -52,7 +52,12 @@ Uint32Array::Uint32Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, un { } -PassRefPtr<ArrayBufferView> Uint32Array::slice(int start, int end) const +PassRefPtr<Uint32Array> Uint32Array::slice(int start) const +{ + return slice(start, length()); +} + +PassRefPtr<Uint32Array> Uint32Array::slice(int start, int end) const { return sliceImpl<Uint32Array>(start, end); } diff --git a/WebCore/html/canvas/Uint32Array.h b/WebCore/html/canvas/Uint32Array.h index db23088..9c0f137 100644 --- a/WebCore/html/canvas/Uint32Array.h +++ b/WebCore/html/canvas/Uint32Array.h @@ -34,7 +34,7 @@ namespace WebCore { class ArrayBuffer; class Uint32Array : public IntegralTypedArrayBase<unsigned int> { - public: +public: static PassRefPtr<Uint32Array> create(unsigned length); static PassRefPtr<Uint32Array> create(unsigned int* array, unsigned length); static PassRefPtr<Uint32Array> create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length); @@ -42,7 +42,10 @@ class Uint32Array : public IntegralTypedArrayBase<unsigned int> { using TypedArrayBase<unsigned int>::set; using IntegralTypedArrayBase<unsigned int>::set; - private: + PassRefPtr<Uint32Array> slice(int start) const; + PassRefPtr<Uint32Array> slice(int start, int end) const; + +private: Uint32Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length); @@ -51,7 +54,6 @@ class Uint32Array : public IntegralTypedArrayBase<unsigned int> { // Overridden from ArrayBufferView. virtual bool isUnsignedIntArray() const { return true; } - virtual PassRefPtr<ArrayBufferView> slice(int start, int end) const; }; } // namespace WebCore diff --git a/WebCore/html/canvas/Uint32Array.idl b/WebCore/html/canvas/Uint32Array.idl index 06e17c6..9fbf30c 100644 --- a/WebCore/html/canvas/Uint32Array.idl +++ b/WebCore/html/canvas/Uint32Array.idl @@ -39,6 +39,9 @@ module html { ] Uint32Array : ArrayBufferView { const unsigned int BYTES_PER_ELEMENT = 4; + readonly attribute unsigned long length; + Uint32Array slice(in long start, in [Optional] long end); + // void set(in Uint32Array array, [Optional] in unsigned long offset); // void set(in sequence<long> array, [Optional] in unsigned long offset); [Custom] void set(); diff --git a/WebCore/html/canvas/Uint8Array.cpp b/WebCore/html/canvas/Uint8Array.cpp index 6c785f9..99b8a09 100644 --- a/WebCore/html/canvas/Uint8Array.cpp +++ b/WebCore/html/canvas/Uint8Array.cpp @@ -52,7 +52,12 @@ Uint8Array::Uint8Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsi { } -PassRefPtr<ArrayBufferView> Uint8Array::slice(int start, int end) const +PassRefPtr<Uint8Array> Uint8Array::slice(int start) const +{ + return slice(start, length()); +} + +PassRefPtr<Uint8Array> Uint8Array::slice(int start, int end) const { return sliceImpl<Uint8Array>(start, end); } diff --git a/WebCore/html/canvas/Uint8Array.h b/WebCore/html/canvas/Uint8Array.h index fce63da..66154b5 100644 --- a/WebCore/html/canvas/Uint8Array.h +++ b/WebCore/html/canvas/Uint8Array.h @@ -34,7 +34,7 @@ namespace WebCore { class ArrayBuffer; class Uint8Array : public IntegralTypedArrayBase<unsigned char> { - public: +public: static PassRefPtr<Uint8Array> create(unsigned length); static PassRefPtr<Uint8Array> create(unsigned char* array, unsigned length); static PassRefPtr<Uint8Array> create(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length); @@ -44,7 +44,10 @@ class Uint8Array : public IntegralTypedArrayBase<unsigned char> { using IntegralTypedArrayBase<unsigned char>::set; #endif - private: + PassRefPtr<Uint8Array> slice(int start) const; + PassRefPtr<Uint8Array> slice(int start, int end) const; + +private: Uint8Array(PassRefPtr<ArrayBuffer> buffer, unsigned byteOffset, unsigned length); @@ -53,7 +56,6 @@ class Uint8Array : public IntegralTypedArrayBase<unsigned char> { // Overridden from ArrayBufferView. virtual bool isUnsignedByteArray() const { return true; } - virtual PassRefPtr<ArrayBufferView> slice(int start, int end) const; }; } // namespace WebCore diff --git a/WebCore/html/canvas/Uint8Array.idl b/WebCore/html/canvas/Uint8Array.idl index bd28023..7fe7e21 100644 --- a/WebCore/html/canvas/Uint8Array.idl +++ b/WebCore/html/canvas/Uint8Array.idl @@ -39,6 +39,9 @@ module html { ] Uint8Array : ArrayBufferView { const unsigned int BYTES_PER_ELEMENT = 1; + readonly attribute unsigned long length; + Uint8Array slice(in long start, in [Optional] long end); + // void set(in Uint8Array array, [Optional] in unsigned long offset); // void set(in sequence<long> array, [Optional] in unsigned long offset); [Custom] void set(); diff --git a/WebCore/html/canvas/WebGLBuffer.cpp b/WebCore/html/canvas/WebGLBuffer.cpp index 99d9cad..36ef048 100644 --- a/WebCore/html/canvas/WebGLBuffer.cpp +++ b/WebCore/html/canvas/WebGLBuffer.cpp @@ -170,8 +170,7 @@ unsigned WebGLBuffer::byteLength() const long WebGLBuffer::getCachedMaxIndex(unsigned long type) { - size_t numEntries = sizeof(m_maxIndexCache) / sizeof(MaxIndexCacheEntry); - for (size_t i = 0; i < numEntries; i++) + for (size_t i = 0; i < WTF_ARRAY_LENGTH(m_maxIndexCache); ++i) if (m_maxIndexCache[i].type == type) return m_maxIndexCache[i].maxIndex; return -1; @@ -179,8 +178,8 @@ long WebGLBuffer::getCachedMaxIndex(unsigned long type) void WebGLBuffer::setCachedMaxIndex(unsigned long type, long value) { - int numEntries = sizeof(m_maxIndexCache) / sizeof(MaxIndexCacheEntry); - for (int i = 0; i < numEntries; i++) + size_t numEntries = WTF_ARRAY_LENGTH(m_maxIndexCache); + for (size_t i = 0; i < numEntries; ++i) if (m_maxIndexCache[i].type == type) { m_maxIndexCache[i].maxIndex = value; return; diff --git a/WebCore/html/canvas/WebGLBuffer.h b/WebCore/html/canvas/WebGLBuffer.h index f18a9bf..af819a3 100644 --- a/WebCore/html/canvas/WebGLBuffer.h +++ b/WebCore/html/canvas/WebGLBuffer.h @@ -59,6 +59,8 @@ public: unsigned long getTarget() const { return m_target; } void setTarget(unsigned long); + bool hasEverBeenBound() const { return object() && m_target; } + protected: WebGLBuffer(WebGLRenderingContext*); diff --git a/WebCore/html/canvas/WebGLFramebuffer.cpp b/WebCore/html/canvas/WebGLFramebuffer.cpp index 5bf3779..9e2db56 100644 --- a/WebCore/html/canvas/WebGLFramebuffer.cpp +++ b/WebCore/html/canvas/WebGLFramebuffer.cpp @@ -75,6 +75,7 @@ PassRefPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContext* ctx WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContext* ctx) : WebGLObject(ctx) + , m_hasEverBeenBound(false) { setObject(context()->graphicsContext3D()->createFramebuffer()); } diff --git a/WebCore/html/canvas/WebGLFramebuffer.h b/WebCore/html/canvas/WebGLFramebuffer.h index 394b770..b86417d 100644 --- a/WebCore/html/canvas/WebGLFramebuffer.h +++ b/WebCore/html/canvas/WebGLFramebuffer.h @@ -56,6 +56,10 @@ public: // Return false does not mean COMPLETE, might still be INCOMPLETE. bool isIncomplete(bool checkInternalFormat) const; + bool hasEverBeenBound() const { return object() && m_hasEverBeenBound; } + + void setHasEverBeenBound() { m_hasEverBeenBound = true; } + protected: WebGLFramebuffer(WebGLRenderingContext*); @@ -76,6 +80,8 @@ private: RefPtr<WebGLObject> m_depthAttachment; RefPtr<WebGLObject> m_stencilAttachment; RefPtr<WebGLObject> m_depthStencilAttachment; + + bool m_hasEverBeenBound; }; } // namespace WebCore diff --git a/WebCore/html/canvas/WebGLRenderbuffer.cpp b/WebCore/html/canvas/WebGLRenderbuffer.cpp index b9efd47..0c3ac84 100644 --- a/WebCore/html/canvas/WebGLRenderbuffer.cpp +++ b/WebCore/html/canvas/WebGLRenderbuffer.cpp @@ -45,6 +45,7 @@ WebGLRenderbuffer::WebGLRenderbuffer(WebGLRenderingContext* ctx) , m_width(0) , m_height(0) , m_isValid(true) + , m_hasEverBeenBound(false) { setObject(context()->graphicsContext3D()->createRenderbuffer()); } diff --git a/WebCore/html/canvas/WebGLRenderbuffer.h b/WebCore/html/canvas/WebGLRenderbuffer.h index 9a23ca5..a432f9d 100644 --- a/WebCore/html/canvas/WebGLRenderbuffer.h +++ b/WebCore/html/canvas/WebGLRenderbuffer.h @@ -60,6 +60,10 @@ public: bool isInitialized() const { return m_initialized; } void setInitialized() { m_initialized = true; } + bool hasEverBeenBound() const { return object() && m_hasEverBeenBound; } + + void setHasEverBeenBound() { m_hasEverBeenBound = true; } + protected: WebGLRenderbuffer(WebGLRenderingContext*); @@ -72,6 +76,8 @@ private: bool m_initialized; unsigned long m_width, m_height; bool m_isValid; // This is only false if internalFormat is DEPTH_STENCIL and packed_depth_stencil is not supported. + + bool m_hasEverBeenBound; }; } // namespace WebCore diff --git a/WebCore/html/canvas/WebGLRenderingContext.cpp b/WebCore/html/canvas/WebGLRenderingContext.cpp index 0cbbc8e..b201692 100644 --- a/WebCore/html/canvas/WebGLRenderingContext.cpp +++ b/WebCore/html/canvas/WebGLRenderingContext.cpp @@ -310,6 +310,8 @@ void WebGLRenderingContext::bindFramebuffer(unsigned long target, WebGLFramebuff } m_framebufferBinding = buffer; m_context->bindFramebuffer(target, objectOrZero(buffer)); + if (buffer) + buffer->setHasEverBeenBound(); cleanupAfterGraphicsCall(false); } @@ -328,6 +330,8 @@ void WebGLRenderingContext::bindRenderbuffer(unsigned long target, WebGLRenderbu } m_renderbufferBinding = renderBuffer; m_context->bindRenderbuffer(target, objectOrZero(renderBuffer)); + if (renderBuffer) + renderBuffer->setHasEverBeenBound(); cleanupAfterGraphicsCall(false); } @@ -2080,6 +2084,9 @@ bool WebGLRenderingContext::isBuffer(WebGLBuffer* buffer) if (!buffer || isContextLost()) return false; + if (!buffer->hasEverBeenBound()) + return false; + return m_context->isBuffer(buffer->object()); } @@ -2100,6 +2107,9 @@ bool WebGLRenderingContext::isFramebuffer(WebGLFramebuffer* framebuffer) if (!framebuffer || isContextLost()) return false; + if (!framebuffer->hasEverBeenBound()) + return false; + return m_context->isFramebuffer(framebuffer->object()); } @@ -2116,6 +2126,9 @@ bool WebGLRenderingContext::isRenderbuffer(WebGLRenderbuffer* renderbuffer) if (!renderbuffer || isContextLost()) return false; + if (!renderbuffer->hasEverBeenBound()) + return false; + return m_context->isRenderbuffer(renderbuffer->object()); } @@ -2132,6 +2145,9 @@ bool WebGLRenderingContext::isTexture(WebGLTexture* texture) if (!texture || isContextLost()) return false; + if (!texture->hasEverBeenBound()) + return false; + return m_context->isTexture(texture->object()); } @@ -2233,10 +2249,14 @@ void WebGLRenderingContext::readPixels(long x, long y, long width, long height, m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); return; } - if (format != GraphicsContext3D::RGBA || type != GraphicsContext3D::UNSIGNED_BYTE) { + if (format != GraphicsContext3D::RGBA && type != GraphicsContext3D::UNSIGNED_BYTE) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } + if (format != GraphicsContext3D::RGBA || type != GraphicsContext3D::UNSIGNED_BYTE) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); + return; + } // Validate array type against pixel type. if ((type == GraphicsContext3D::UNSIGNED_BYTE && !pixels->isUnsignedByteArray()) || (type != GraphicsContext3D::UNSIGNED_BYTE && !pixels->isUnsignedShortArray())) { @@ -2258,7 +2278,7 @@ void WebGLRenderingContext::readPixels(long x, long y, long width, long height, // The last row needs no padding. unsigned long totalBytes = bytesPerRow * height - padding; unsigned long num = totalBytes / bytesPerComponent; - if (pixels->length() < num) { + if (pixels->byteLength() / bytesPerComponent < num) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } diff --git a/WebCore/html/canvas/WebGLTexture.h b/WebCore/html/canvas/WebGLTexture.h index 6ee3dcc..493ef7e 100644 --- a/WebCore/html/canvas/WebGLTexture.h +++ b/WebCore/html/canvas/WebGLTexture.h @@ -61,6 +61,8 @@ public: // Determine if texture sampling should always return [0, 0, 0, 1] (OpenGL ES 2.0 Sec 3.8.2). bool needToUseBlackTexture() const; + bool hasEverBeenBound() const { return object() && m_target; } + static int computeLevelCount(int width, int height); protected: |