diff options
Diffstat (limited to 'Source/WebCore/html')
42 files changed, 681 insertions, 280 deletions
diff --git a/Source/WebCore/html/DateTimeFieldsState.cpp b/Source/WebCore/html/DateTimeFieldsState.cpp new file mode 100644 index 000000000..8e2bd6c1c --- /dev/null +++ b/Source/WebCore/html/DateTimeFieldsState.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" +#if ENABLE(INPUT_TYPE_TIME_MULTIPLE_FIELDS) +#include "DateTimeFieldsState.h" + +#include "FormController.h" + +namespace WebCore { + +const unsigned DateTimeFieldsState::emptyValue = static_cast<unsigned>(-1); + +static unsigned getNumberFromFormControlState(const FormControlState& state, size_t index) +{ + if (index >= state.valueSize()) + return DateTimeFieldsState::emptyValue; + bool parsed; + unsigned const value = state[index].toUInt(&parsed); + return parsed ? value : DateTimeFieldsState::emptyValue; +} + +static DateTimeFieldsState::AMPMValue getAMPMFromFormControlState(const FormControlState& state, size_t index) +{ + if (index >= state.valueSize()) + return DateTimeFieldsState::AMPMValueEmpty; + const String value = state[index]; + if (value == "A") + return DateTimeFieldsState::AMPMValueAM; + if (value == "P") + return DateTimeFieldsState::AMPMValuePM; + return DateTimeFieldsState::AMPMValueEmpty; +} + +DateTimeFieldsState::DateTimeFieldsState() + : m_year(emptyValue) + , m_month(emptyValue) + , m_dayOfMonth(emptyValue) + , m_hour(emptyValue) + , m_minute(emptyValue) + , m_second(emptyValue) + , m_millisecond(emptyValue) + , m_weekOfYear(emptyValue) + , m_ampm(AMPMValueEmpty) +{ +} + +DateTimeFieldsState DateTimeFieldsState::restoreFormControlState(const FormControlState& state) +{ + DateTimeFieldsState dateTimeFieldsState; + dateTimeFieldsState.setYear(getNumberFromFormControlState(state, 0)); + dateTimeFieldsState.setMonth(getNumberFromFormControlState(state, 1)); + dateTimeFieldsState.setDayOfMonth(getNumberFromFormControlState(state, 2)); + dateTimeFieldsState.setHour(getNumberFromFormControlState(state, 3)); + dateTimeFieldsState.setMinute(getNumberFromFormControlState(state, 4)); + dateTimeFieldsState.setSecond(getNumberFromFormControlState(state, 5)); + dateTimeFieldsState.setMillisecond(getNumberFromFormControlState(state, 6)); + dateTimeFieldsState.setWeekOfYear(getNumberFromFormControlState(state, 7)); + dateTimeFieldsState.setAMPM(getAMPMFromFormControlState(state, 8)); + return dateTimeFieldsState; +} + +FormControlState DateTimeFieldsState::saveFormControlState() const +{ + FormControlState state; + state.append(hasYear() ? String::number(m_year) : emptyString()); + state.append(hasMonth() ? String::number(m_month) : emptyString()); + state.append(hasDayOfMonth() ? String::number(m_dayOfMonth) : emptyString()); + state.append(hasHour() ? String::number(m_hour) : emptyString()); + state.append(hasMinute() ? String::number(m_minute) : emptyString()); + state.append(hasSecond() ? String::number(m_second) : emptyString()); + state.append(hasMillisecond() ? String::number(m_millisecond) : emptyString()); + state.append(hasWeekOfYear() ? String::number(m_weekOfYear) : emptyString()); + if (hasAMPM()) + state.append(m_ampm == AMPMValueAM ? "A" : "P"); + else + state.append(emptyString()); + return state; +} + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/html/DateTimeFieldsState.h b/Source/WebCore/html/DateTimeFieldsState.h new file mode 100644 index 000000000..b6240629e --- /dev/null +++ b/Source/WebCore/html/DateTimeFieldsState.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef DateTimeFieldsState_h +#define DateTimeFieldsState_h + +#if ENABLE(INPUT_TYPE_TIME_MULTIPLE_FIELDS) +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class FormControlState; + +// DateTimeFieldsState represents fields in date/time for form state +// save/restore for input type "date", "datetime", "datetime-local", "month", +// "time", and "week" with multiple fields input UI. +// +// Each field can contain invalid value for date, e.g. day of month field can +// be 30 even if month field is February. +class DateTimeFieldsState { +public: + enum AMPMValue { + AMPMValueEmpty = -1, + AMPMValueAM, + AMPMValuePM, + }; + + static const unsigned emptyValue; + + DateTimeFieldsState(); + + static DateTimeFieldsState restoreFormControlState(const FormControlState&); + FormControlState saveFormControlState() const; + + AMPMValue ampm() const { return m_ampm; } + unsigned dayOfMonth() const { return m_dayOfMonth; } + unsigned hour() const { return m_hour; } + unsigned millisecond() const { return m_millisecond; } + unsigned minute() const { return m_minute; } + unsigned month() const { return m_month; } + unsigned second() const { return m_second; } + unsigned weekOfYear() const { return m_weekOfYear; } + unsigned year() const { return m_year; } + + bool hasAMPM() const { return m_ampm != AMPMValueEmpty; } + bool hasDayOfMonth() const { return m_dayOfMonth != emptyValue; } + bool hasHour() const { return m_hour != emptyValue; } + bool hasMillisecond() const { return m_millisecond != emptyValue; } + bool hasMinute() const { return m_minute != emptyValue; } + bool hasMonth() const { return m_month != emptyValue; } + bool hasSecond() const { return m_second != emptyValue; } + bool hasWeekOfYear() const { return m_weekOfYear != emptyValue; } + bool hasYear() const { return m_year != emptyValue; } + + void setAMPM(AMPMValue ampm) { m_ampm = ampm; } + void setDayOfMonth(unsigned dayOfMonth) { m_dayOfMonth = dayOfMonth; } + void setHour(unsigned hour12) { m_hour = hour12; } + void setMillisecond(unsigned millisecond) { m_millisecond = millisecond; } + void setMinute(unsigned minute) { m_minute = minute; } + void setMonth(unsigned month) { m_month = month; } + void setSecond(unsigned second) { m_second = second; } + void setWeekOfYear(unsigned weekOfYear) { m_weekOfYear = weekOfYear; } + void setYear(unsigned year) { m_year = year; } + +private: + unsigned m_year; + unsigned m_month; + unsigned m_dayOfMonth; + unsigned m_hour; + unsigned m_minute; + unsigned m_second; + unsigned m_millisecond; + unsigned m_weekOfYear; + AMPMValue m_ampm; +}; + +} // namespace WebCore + +#endif +#endif diff --git a/Source/WebCore/html/FormAssociatedElement.cpp b/Source/WebCore/html/FormAssociatedElement.cpp index 99377df34..3d889783e 100644 --- a/Source/WebCore/html/FormAssociatedElement.cpp +++ b/Source/WebCore/html/FormAssociatedElement.cpp @@ -39,6 +39,7 @@ namespace WebCore { using namespace HTMLNames; class FormAttributeTargetObserver : IdTargetObserver { + WTF_MAKE_FAST_ALLOCATED; public: static PassOwnPtr<FormAttributeTargetObserver> create(const AtomicString& id, FormAssociatedElement*); virtual void idTargetChanged() OVERRIDE; diff --git a/Source/WebCore/html/FormController.cpp b/Source/WebCore/html/FormController.cpp index e5767e1b3..fbfe7b714 100644 --- a/Source/WebCore/html/FormController.cpp +++ b/Source/WebCore/html/FormController.cpp @@ -391,7 +391,7 @@ static String formStateSignature() // In the legacy version of serialized state, the first item was a name // attribute value of a form control. The following string literal should // contain some characters which are rarely used for name attribute values. - DEFINE_STATIC_LOCAL(String, signature, (ASCIILiteral("\n\r?% WebKit serialized form state version 7 \n\r=&"))); + DEFINE_STATIC_LOCAL(String, signature, (ASCIILiteral("\n\r?% WebKit serialized form state version 8 \n\r=&"))); return signature; } diff --git a/Source/WebCore/html/FormController.h b/Source/WebCore/html/FormController.h index 0402b2cd1..265d60152 100644 --- a/Source/WebCore/html/FormController.h +++ b/Source/WebCore/html/FormController.h @@ -73,6 +73,7 @@ inline void FormControlState::append(const String& value) } class FormController { + WTF_MAKE_FAST_ALLOCATED; public: static PassOwnPtr<FormController> create() { diff --git a/Source/WebCore/html/HTMLCanvasElement.h b/Source/WebCore/html/HTMLCanvasElement.h index 2dde80fd4..e80d85979 100644 --- a/Source/WebCore/html/HTMLCanvasElement.h +++ b/Source/WebCore/html/HTMLCanvasElement.h @@ -143,6 +143,7 @@ private: virtual void parseAttribute(const Attribute&) OVERRIDE; virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); virtual void attach(); + virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; } void reset(); diff --git a/Source/WebCore/html/HTMLFieldSetElement.h b/Source/WebCore/html/HTMLFieldSetElement.h index 7a3f3597a..e483bebc5 100644 --- a/Source/WebCore/html/HTMLFieldSetElement.h +++ b/Source/WebCore/html/HTMLFieldSetElement.h @@ -55,6 +55,7 @@ private: virtual const AtomicString& formControlType() const; virtual bool recalcWillValidate() const { return false; } virtual void childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) OVERRIDE; + virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; } static void invalidateDisabledStateUnder(Element*); void refreshElementsIfNeeded() const; diff --git a/Source/WebCore/html/HTMLFormControlElement.cpp b/Source/WebCore/html/HTMLFormControlElement.cpp index 2d47ac8c4..db368c485 100644 --- a/Source/WebCore/html/HTMLFormControlElement.cpp +++ b/Source/WebCore/html/HTMLFormControlElement.cpp @@ -402,29 +402,11 @@ void HTMLFormControlElement::updateVisibleValidationMessage() if (!page) return; String message; - if (renderer() && willValidate()) { + if (renderer() && willValidate()) message = validationMessage().stripWhiteSpace(); - // HTML5 specification doesn't ask UA to show the title attribute value - // with the validationMessage. However, this behavior is same as Opera - // and the specification describes such behavior as an example. - const AtomicString& title = getAttribute(titleAttr); - if (!message.isEmpty() && !title.isEmpty()) { - message.append('\n'); - message.append(title); - } - } - if (message.isEmpty()) { - hideVisibleValidationMessage(); - return; - } - if (!m_validationMessage) { + if (!m_validationMessage) m_validationMessage = ValidationMessage::create(this); - m_validationMessage->setMessage(message); - } else { - // Call setMessage() even if m_validationMesage->message() == message - // because the existing message might be to be hidden. - m_validationMessage->setMessage(message); - } + m_validationMessage->updateValidationMessage(message); } void HTMLFormControlElement::hideVisibleValidationMessage() @@ -433,11 +415,6 @@ void HTMLFormControlElement::hideVisibleValidationMessage() m_validationMessage->requestToHideMessage(); } -String HTMLFormControlElement::visibleValidationMessage() const -{ - return m_validationMessage ? m_validationMessage->message() : String(); -} - bool HTMLFormControlElement::checkValidity(Vector<RefPtr<FormAssociatedElement> >* unhandledInvalidControls) { if (!willValidate() || isValidFormControlElement()) @@ -469,7 +446,7 @@ void HTMLFormControlElement::setNeedsValidityCheck() m_isValid = newIsValid; // Updates only if this control already has a validtion message. - if (!visibleValidationMessage().isEmpty()) { + if (m_validationMessage && m_validationMessage->isVisible()) { // Calls updateVisibleValidationMessage() even if m_isValid is not // changed because a validation message can be chagned. updateVisibleValidationMessage(); diff --git a/Source/WebCore/html/HTMLFormControlElement.h b/Source/WebCore/html/HTMLFormControlElement.h index d129bc2c2..24de97669 100644 --- a/Source/WebCore/html/HTMLFormControlElement.h +++ b/Source/WebCore/html/HTMLFormControlElement.h @@ -148,7 +148,6 @@ private: virtual HTMLFormElement* virtualForm() const; virtual bool isDefaultButtonForForm() const; virtual bool isValidFormControlElement(); - String visibleValidationMessage() const; void updateAncestorDisabledState() const; OwnPtr<ValidationMessage> m_validationMessage; diff --git a/Source/WebCore/html/HTMLFrameElementBase.h b/Source/WebCore/html/HTMLFrameElementBase.h index a4163ea11..be9abc8e7 100644 --- a/Source/WebCore/html/HTMLFrameElementBase.h +++ b/Source/WebCore/html/HTMLFrameElementBase.h @@ -53,6 +53,7 @@ protected: virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE; virtual void didNotifySubtreeInsertions(ContainerNode*) OVERRIDE; virtual void attach(); + virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; } private: virtual bool supportsFocus() const; diff --git a/Source/WebCore/html/HTMLInputElement.cpp b/Source/WebCore/html/HTMLInputElement.cpp index c82de2fef..d1ea76cae 100644 --- a/Source/WebCore/html/HTMLInputElement.cpp +++ b/Source/WebCore/html/HTMLInputElement.cpp @@ -80,6 +80,7 @@ using namespace HTMLNames; #if ENABLE(DATALIST_ELEMENT) class ListAttributeTargetObserver : IdTargetObserver { + WTF_MAKE_FAST_ALLOCATED; public: static PassOwnPtr<ListAttributeTargetObserver> create(const AtomicString& id, HTMLInputElement*); virtual void idTargetChanged() OVERRIDE; @@ -119,7 +120,9 @@ HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document* docum , m_valueAttributeWasUpdatedAfterParsing(false) , m_wasModifiedByUser(false) , m_canReceiveDroppedFiles(false) +#if ENABLE(TOUCH_EVENTS) , m_hasTouchEventHandler(false) +#endif , m_inputType(InputType::createText(this)) { ASSERT(hasTagName(inputTag) || hasTagName(isindexTag)); diff --git a/Source/WebCore/html/HTMLInputElement.h b/Source/WebCore/html/HTMLInputElement.h index 678f59aff..7fe0d6c14 100644 --- a/Source/WebCore/html/HTMLInputElement.h +++ b/Source/WebCore/html/HTMLInputElement.h @@ -412,7 +412,9 @@ private: bool m_valueAttributeWasUpdatedAfterParsing : 1; bool m_wasModifiedByUser : 1; bool m_canReceiveDroppedFiles : 1; - bool m_hasTouchEventHandler: 1; +#if ENABLE(TOUCH_EVENTS) + bool m_hasTouchEventHandler : 1; +#endif OwnPtr<InputType> m_inputType; #if ENABLE(DATALIST_ELEMENT) OwnPtr<ListAttributeTargetObserver> m_listAttributeTargetObserver; diff --git a/Source/WebCore/html/HTMLMediaElement.cpp b/Source/WebCore/html/HTMLMediaElement.cpp index c3dd65d11..5f5674517 100644 --- a/Source/WebCore/html/HTMLMediaElement.cpp +++ b/Source/WebCore/html/HTMLMediaElement.cpp @@ -4477,6 +4477,11 @@ bool HTMLMediaElement::mediaPlayerIsPaused() const return paused(); } +bool HTMLMediaElement::mediaPlayerIsLooping() const +{ + return loop(); +} + HostWindow* HTMLMediaElement::mediaPlayerHostWindow() { return mediaPlayerOwningDocument()->view()->hostWindow(); diff --git a/Source/WebCore/html/HTMLMediaElement.h b/Source/WebCore/html/HTMLMediaElement.h index 1f30b296e..821e2285b 100644 --- a/Source/WebCore/html/HTMLMediaElement.h +++ b/Source/WebCore/html/HTMLMediaElement.h @@ -86,6 +86,7 @@ public: void createShadowSubtree(); virtual void willAddAuthorShadowRoot() OVERRIDE; + virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; } virtual bool isVideo() const = 0; virtual bool hasVideo() const { return false; } @@ -431,6 +432,7 @@ private: virtual void mediaPlayerPause() OVERRIDE; virtual void mediaPlayerPlay() OVERRIDE; virtual bool mediaPlayerIsPaused() const OVERRIDE; + virtual bool mediaPlayerIsLooping() const OVERRIDE; virtual HostWindow* mediaPlayerHostWindow() OVERRIDE; virtual IntRect mediaPlayerWindowClipRect() OVERRIDE; diff --git a/Source/WebCore/html/HTMLPlugInElement.h b/Source/WebCore/html/HTMLPlugInElement.h index 94887748d..eeec60cb5 100644 --- a/Source/WebCore/html/HTMLPlugInElement.h +++ b/Source/WebCore/html/HTMLPlugInElement.h @@ -62,6 +62,7 @@ protected: virtual void detach(); virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE; virtual void collectStyleForAttribute(const Attribute&, StylePropertySet*) OVERRIDE; + virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; } bool m_inBeforeLoadEventHandler; // Subclasses should use guardedDispatchBeforeLoadEvent instead of calling dispatchBeforeLoadEvent directly. diff --git a/Source/WebCore/html/HTMLSelectElement.h b/Source/WebCore/html/HTMLSelectElement.h index 474c15a64..9147c3f0f 100644 --- a/Source/WebCore/html/HTMLSelectElement.h +++ b/Source/WebCore/html/HTMLSelectElement.h @@ -179,6 +179,7 @@ private: int nextSelectableListIndexPageAway(int startIndex, SkipDirection) const; virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); + virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; } // m_listItems contains HTMLOptionElement, HTMLOptGroupElement, and HTMLHRElement objects. mutable Vector<HTMLElement*> m_listItems; diff --git a/Source/WebCore/html/HTMLStyleElement.cpp b/Source/WebCore/html/HTMLStyleElement.cpp index 26990a5df..9bfc91a43 100644 --- a/Source/WebCore/html/HTMLStyleElement.cpp +++ b/Source/WebCore/html/HTMLStyleElement.cpp @@ -123,6 +123,42 @@ void HTMLStyleElement::finishParsingChildren() } #if ENABLE(STYLE_SCOPED) +inline bool HTMLStyleElement::isRegisteredAsScoped() const +{ + // Note: We cannot rely on the 'scoped' attribute still being present when this method is invoked. + // Therefore we cannot rely on scoped()! + if (m_scopedStyleRegistrationState == NotRegistered) + return false; + if (!ContextFeatures::styleScopedEnabled(document())) + return false; + return true; +} + +// These three Node methods are placed here to +// make the header inclusion dependency sane. + +inline void Node::registerScopedHTMLStyleChild() +{ + setHasScopedHTMLStyleChild(true); +} + +inline void Node::unregisterScopedHTMLStyleChild() +{ + ASSERT(hasScopedHTMLStyleChild()); + setHasScopedHTMLStyleChild(numberOfScopedHTMLStyleChildren()); +} + +size_t Node::numberOfScopedHTMLStyleChildren() const +{ + size_t count = 0; + for (Node* child = firstChild(); child; child = child->nextSibling()) { + if (child->hasTagName(styleTag) && static_cast<HTMLStyleElement*>(child)->isRegisteredAsScoped()) + count++; + } + + return count; +} + void HTMLStyleElement::registerWithScopingNode(bool scoped) { // Note: We cannot rely on the 'scoped' element already being present when this method is invoked. @@ -154,12 +190,8 @@ void HTMLStyleElement::registerWithScopingNode(bool scoped) void HTMLStyleElement::unregisterWithScopingNode(ContainerNode* scope) { - // Note: We cannot rely on the 'scoped' element still being present when this method is invoked. - // Therefore we cannot rely on scoped()! ASSERT(m_scopedStyleRegistrationState != NotRegistered || !ContextFeatures::styleScopedEnabled(document())); - if (m_scopedStyleRegistrationState == NotRegistered) - return; - if (!ContextFeatures::styleScopedEnabled(document())) + if (!isRegisteredAsScoped()) return; ASSERT(scope); @@ -173,6 +205,11 @@ void HTMLStyleElement::unregisterWithScopingNode(ContainerNode* scope) m_scopedStyleRegistrationState = NotRegistered; } +#else +size_t Node::numberOfScopedHTMLStyleChildren() const +{ + return 0; +} #endif Node::InsertionNotificationRequest HTMLStyleElement::insertedInto(ContainerNode* insertionPoint) diff --git a/Source/WebCore/html/HTMLStyleElement.h b/Source/WebCore/html/HTMLStyleElement.h index 63a82c4ee..8476c648f 100644 --- a/Source/WebCore/html/HTMLStyleElement.h +++ b/Source/WebCore/html/HTMLStyleElement.h @@ -45,6 +45,7 @@ public: bool scoped() const; void setScoped(bool); Element* scopingElement() const; + bool isRegisteredAsScoped() const; #endif using StyleElement::sheet; diff --git a/Source/WebCore/html/PublicURLManager.h b/Source/WebCore/html/PublicURLManager.h index 55fefc3bd..e17e46a8d 100644 --- a/Source/WebCore/html/PublicURLManager.h +++ b/Source/WebCore/html/PublicURLManager.h @@ -47,7 +47,7 @@ namespace WebCore { class ScriptExecutionContext; class PublicURLManager { - + WTF_MAKE_FAST_ALLOCATED; public: static PassOwnPtr<PublicURLManager> create() { return adoptPtr(new PublicURLManager); } void contextDestroyed() diff --git a/Source/WebCore/html/StepRange.h b/Source/WebCore/html/StepRange.h index 63ab7561a..697a7b53d 100644 --- a/Source/WebCore/html/StepRange.h +++ b/Source/WebCore/html/StepRange.h @@ -40,6 +40,8 @@ public: }; struct StepDescription { + WTF_MAKE_FAST_ALLOCATED; + public: int defaultStep; int defaultStepBase; int stepScaleFactor; diff --git a/Source/WebCore/html/TimeInputType.cpp b/Source/WebCore/html/TimeInputType.cpp index edd12e7a6..880e44719 100644 --- a/Source/WebCore/html/TimeInputType.cpp +++ b/Source/WebCore/html/TimeInputType.cpp @@ -42,7 +42,9 @@ #if ENABLE(INPUT_TYPE_TIME) #if ENABLE(INPUT_TYPE_TIME_MULTIPLE_FIELDS) +#include "DateTimeFieldsState.h" #include "ElementShadow.h" +#include "FormController.h" #include "KeyboardEvent.h" #include "ShadowRoot.h" #endif @@ -259,6 +261,25 @@ bool TimeInputType::isTextField() const return false; } +void TimeInputType::restoreFormControlState(const FormControlState& state) +{ + if (!m_dateTimeEditElement) + return; + DateComponents date; + setMillisecondToDateComponents(createStepRange(AnyIsDefaultStep).minimum().toDouble(), &date); + DateTimeFieldsState dateTimeFieldsState = DateTimeFieldsState::restoreFormControlState(state); + m_dateTimeEditElement->setValueAsDateTimeFieldsState(dateTimeFieldsState, date); + element()->setValueInternal(serialize(Decimal::fromDouble(m_dateTimeEditElement->valueAsDouble())), DispatchNoEvent); +} + +FormControlState TimeInputType::saveFormControlState() const +{ + if (!m_dateTimeEditElement) + return FormControlState(); + + return m_dateTimeEditElement->valueAsDateTimeFieldsState().saveFormControlState(); +} + void TimeInputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior) { InputType::setValue(sanitizedValue, valueChanged, eventBehavior); @@ -281,13 +302,14 @@ void TimeInputType::updateInnerTextValue() if (!m_dateTimeEditElement) return; + Localizer& localizer = element()->document()->getLocalizer(element()->computeInheritedLanguage()); const StepRange stepRange(createStepRange(AnyIsDefaultStep)); DateComponents date; if (parseToDateComponents(element()->value(), &date)) - m_dateTimeEditElement->setValueAsDate(stepRange, date); + m_dateTimeEditElement->setValueAsDate(stepRange, date, localizer); else { setMillisecondToDateComponents(stepRange.minimum().toDouble(), &date); - m_dateTimeEditElement->setEmptyValue(stepRange, date); + m_dateTimeEditElement->setEmptyValue(stepRange, date, localizer); } } #else diff --git a/Source/WebCore/html/TimeInputType.h b/Source/WebCore/html/TimeInputType.h index acd57b34d..0787c3a21 100644 --- a/Source/WebCore/html/TimeInputType.h +++ b/Source/WebCore/html/TimeInputType.h @@ -94,6 +94,8 @@ private: virtual bool isTextField() const OVERRIDE FINAL; virtual void minOrMaxAttributeChanged() OVERRIDE FINAL; virtual void readonlyAttributeChanged() OVERRIDE FINAL; + virtual void restoreFormControlState(const FormControlState&) OVERRIDE FINAL; + virtual FormControlState saveFormControlState() const OVERRIDE FINAL; virtual void setValue(const String&, bool valueChanged, TextFieldEventBehavior) OVERRIDE FINAL; virtual bool shouldUseInputMethod() const OVERRIDE FINAL; virtual void stepAttributeChanged() OVERRIDE FINAL; diff --git a/Source/WebCore/html/ValidationMessage.cpp b/Source/WebCore/html/ValidationMessage.cpp index 67d32dc81..1d551c931 100644 --- a/Source/WebCore/html/ValidationMessage.cpp +++ b/Source/WebCore/html/ValidationMessage.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2010, 2012 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -35,9 +35,9 @@ #include "CSSValueKeywords.h" #include "ElementShadow.h" #include "ExceptionCodePlaceholder.h" -#include "FormAssociatedElement.h" #include "HTMLBRElement.h" #include "HTMLDivElement.h" +#include "HTMLFormControlElement.h" #include "HTMLNames.h" #include "Page.h" #include "RenderBlock.h" @@ -46,29 +46,69 @@ #include "ShadowRoot.h" #include "StyleResolver.h" #include "Text.h" +#include "ValidationMessageClient.h" #include <wtf/PassOwnPtr.h> namespace WebCore { using namespace HTMLNames; -ALWAYS_INLINE ValidationMessage::ValidationMessage(FormAssociatedElement* element) +ALWAYS_INLINE ValidationMessage::ValidationMessage(HTMLFormControlElement* element) : m_element(element) { + ASSERT(m_element); } ValidationMessage::~ValidationMessage() { + if (ValidationMessageClient* client = validationMessageClient()) { + client->hideValidationMessage(*m_element); + return; + } + deleteBubbleTree(); } -PassOwnPtr<ValidationMessage> ValidationMessage::create(FormAssociatedElement* element) +PassOwnPtr<ValidationMessage> ValidationMessage::create(HTMLFormControlElement* element) { return adoptPtr(new ValidationMessage(element)); } +ValidationMessageClient* ValidationMessage::validationMessageClient() const +{ + if (Page* page = m_element->document()->page()) + return page->validationMessageClient(); + return 0; +} + +void ValidationMessage::updateValidationMessage(const String& message) +{ + String updatedMessage = message; + if (!validationMessageClient()) { + // HTML5 specification doesn't ask UA to show the title attribute value + // with the validationMessage. However, this behavior is same as Opera + // and the specification describes such behavior as an example. + const AtomicString& title = m_element->fastGetAttribute(titleAttr); + if (!updatedMessage.isEmpty() && !title.isEmpty()) { + updatedMessage.append('\n'); + updatedMessage.append(title); + } + } + + if (updatedMessage.isEmpty()) { + requestToHideMessage(); + return; + } + setMessage(updatedMessage); +} + void ValidationMessage::setMessage(const String& message) { + if (ValidationMessageClient* client = validationMessageClient()) { + client->showValidationMessage(*m_element, message); + return; + } + // Don't modify the DOM tree in this context. // If so, an assertion in Node::isFocusable() fails. ASSERT(!message.isEmpty()); @@ -82,6 +122,7 @@ void ValidationMessage::setMessage(const String& message) void ValidationMessage::setMessageDOMAndStartTimer(Timer<ValidationMessage>*) { + ASSERT(!validationMessageClient()); ASSERT(m_messageHeading); ASSERT(m_messageBody); m_messageHeading->removeAllChildren(); @@ -133,10 +174,10 @@ static void adjustBubblePosition(const LayoutRect& hostRect, HTMLElement* bubble void ValidationMessage::buildBubbleTree(Timer<ValidationMessage>*) { - HTMLElement* host = toHTMLElement(m_element); + ASSERT(!validationMessageClient()); ShadowRoot* shadowRoot = m_element->ensureUserAgentShadowRoot(); - Document* doc = host->document(); + Document* doc = m_element->document(); m_bubble = HTMLDivElement::create(doc); m_bubble->setShadowPseudoId("-webkit-validation-bubble"); // Need to force position:absolute because RenderMenuList doesn't assume it @@ -145,8 +186,8 @@ void ValidationMessage::buildBubbleTree(Timer<ValidationMessage>*) ExceptionCode ec = 0; shadowRoot->appendChild(m_bubble.get(), ec); ASSERT(!ec); - host->document()->updateLayout(); - adjustBubblePosition(host->boundingBox(), m_bubble.get()); + m_element->document()->updateLayout(); + adjustBubblePosition(m_element->boundingBox(), m_bubble.get()); RefPtr<HTMLDivElement> clipper = HTMLDivElement::create(doc); clipper->setShadowPseudoId("-webkit-validation-bubble-arrow-clipper"); @@ -180,6 +221,11 @@ void ValidationMessage::buildBubbleTree(Timer<ValidationMessage>*) void ValidationMessage::requestToHideMessage() { + if (ValidationMessageClient* client = validationMessageClient()) { + client->hideValidationMessage(*m_element); + return; + } + // We must not modify the DOM tree in this context by the same reason as setMessage(). m_timer = adoptPtr(new Timer<ValidationMessage>(this, &ValidationMessage::deleteBubbleTree)); m_timer->startOneShot(0); @@ -187,22 +233,28 @@ void ValidationMessage::requestToHideMessage() bool ValidationMessage::shadowTreeContains(Node* node) const { - if (!m_bubble) + if (validationMessageClient() || !m_bubble) return false; return m_bubble->treeScope() == node->treeScope(); } void ValidationMessage::deleteBubbleTree(Timer<ValidationMessage>*) { + ASSERT(!validationMessageClient()); if (m_bubble) { m_messageHeading = 0; m_messageBody = 0; - HTMLElement* host = toHTMLElement(m_element); - ExceptionCode ec; - host->userAgentShadowRoot()->removeChild(m_bubble.get(), ec); + m_element->userAgentShadowRoot()->removeChild(m_bubble.get(), ASSERT_NO_EXCEPTION); m_bubble = 0; } m_message = String(); } +bool ValidationMessage::isVisible() const +{ + if (ValidationMessageClient* client = validationMessageClient()) + return client->isValidationMessageVisible(*m_element); + return !m_message.isEmpty(); +} + } // namespace WebCore diff --git a/Source/WebCore/html/ValidationMessage.h b/Source/WebCore/html/ValidationMessage.h index 42982e507..983442731 100644 --- a/Source/WebCore/html/ValidationMessage.h +++ b/Source/WebCore/html/ValidationMessage.h @@ -39,27 +39,32 @@ namespace WebCore { -class FormAssociatedElement; class HTMLElement; +class HTMLFormControlElement; class Node; +class ValidationMessageClient; +// FIXME: We should remove the code for !validationMessageClient() when all +// ports supporting interactive validation switch to ValidationMessageClient. class ValidationMessage { - WTF_MAKE_NONCOPYABLE(ValidationMessage); + WTF_MAKE_NONCOPYABLE(ValidationMessage); WTF_MAKE_FAST_ALLOCATED; public: - static PassOwnPtr<ValidationMessage> create(FormAssociatedElement*); + static PassOwnPtr<ValidationMessage> create(HTMLFormControlElement*); ~ValidationMessage(); - String message() const { return m_message; } - void setMessage(const String&); + void updateValidationMessage(const String&); void requestToHideMessage(); + bool isVisible() const; bool shadowTreeContains(Node*) const; private: - ValidationMessage(FormAssociatedElement*); + ValidationMessage(HTMLFormControlElement*); + ValidationMessageClient* validationMessageClient() const; + void setMessage(const String&); void setMessageDOMAndStartTimer(Timer<ValidationMessage>* = 0); void buildBubbleTree(Timer<ValidationMessage>*); void deleteBubbleTree(Timer<ValidationMessage>* = 0); - FormAssociatedElement* m_element; + HTMLFormControlElement* m_element; String m_message; OwnPtr<Timer<ValidationMessage> > m_timer; RefPtr<HTMLElement> m_bubble; diff --git a/Source/WebCore/html/canvas/CanvasRenderingContext.idl b/Source/WebCore/html/canvas/CanvasRenderingContext.idl index b9373931f..ab5beb189 100644 --- a/Source/WebCore/html/canvas/CanvasRenderingContext.idl +++ b/Source/WebCore/html/canvas/CanvasRenderingContext.idl @@ -28,11 +28,9 @@ module html { interface [ JSCustomMarkFunction, JSGenerateIsReachable, - JSCustomToJSObject + CustomToJSObject ] CanvasRenderingContext { - readonly attribute HTMLCanvasElement canvas; }; } - diff --git a/Source/WebCore/html/canvas/WebGLExtension.h b/Source/WebCore/html/canvas/WebGLExtension.h index c66a60861..6968a02b4 100644 --- a/Source/WebCore/html/canvas/WebGLExtension.h +++ b/Source/WebCore/html/canvas/WebGLExtension.h @@ -31,6 +31,7 @@ namespace WebCore { class WebGLExtension { + WTF_MAKE_FAST_ALLOCATED; public: // Extension names are needed to properly wrap instances in JavaScript objects. enum ExtensionName { diff --git a/Source/WebCore/html/canvas/WebGLRenderingContext.cpp b/Source/WebCore/html/canvas/WebGLRenderingContext.cpp index c40ba43e9..24b9c33f9 100644 --- a/Source/WebCore/html/canvas/WebGLRenderingContext.cpp +++ b/Source/WebCore/html/canvas/WebGLRenderingContext.cpp @@ -375,6 +375,7 @@ private: }; class WebGLRenderingContextLostCallback : public GraphicsContext3D::ContextLostCallback { + WTF_MAKE_FAST_ALLOCATED; public: explicit WebGLRenderingContextLostCallback(WebGLRenderingContext* cb) : m_context(cb) { } virtual void onContextLost() { m_context->forceLostContext(WebGLRenderingContext::RealLostContext); } @@ -384,6 +385,7 @@ private: }; class WebGLRenderingContextErrorMessageCallback : public GraphicsContext3D::ErrorMessageCallback { + WTF_MAKE_FAST_ALLOCATED; public: explicit WebGLRenderingContextErrorMessageCallback(WebGLRenderingContext* cb) : m_context(cb) { } virtual void onErrorMessage(const String& message, GC3Dint) { m_context->printGLErrorToConsole(message); } diff --git a/Source/WebCore/html/parser/HTMLElementStack.h b/Source/WebCore/html/parser/HTMLElementStack.h index b203ef15d..873cbdeb9 100644 --- a/Source/WebCore/html/parser/HTMLElementStack.h +++ b/Source/WebCore/html/parser/HTMLElementStack.h @@ -51,7 +51,7 @@ public: ~HTMLElementStack(); class ElementRecord { - WTF_MAKE_NONCOPYABLE(ElementRecord); + WTF_MAKE_NONCOPYABLE(ElementRecord); WTF_MAKE_FAST_ALLOCATED; public: ~ElementRecord(); // Public for ~PassOwnPtr() diff --git a/Source/WebCore/html/parser/HTMLMetaCharsetParser.h b/Source/WebCore/html/parser/HTMLMetaCharsetParser.h index 1ee87df9a..436ea7926 100644 --- a/Source/WebCore/html/parser/HTMLMetaCharsetParser.h +++ b/Source/WebCore/html/parser/HTMLMetaCharsetParser.h @@ -37,7 +37,7 @@ class HTMLTokenizer; class TextCodec; class HTMLMetaCharsetParser { - WTF_MAKE_NONCOPYABLE(HTMLMetaCharsetParser); + WTF_MAKE_NONCOPYABLE(HTMLMetaCharsetParser); WTF_MAKE_FAST_ALLOCATED; public: static PassOwnPtr<HTMLMetaCharsetParser> create() { return adoptPtr(new HTMLMetaCharsetParser()); } diff --git a/Source/WebCore/html/parser/HTMLTreeBuilder.cpp b/Source/WebCore/html/parser/HTMLTreeBuilder.cpp index 522a4409b..3e9b303c6 100644 --- a/Source/WebCore/html/parser/HTMLTreeBuilder.cpp +++ b/Source/WebCore/html/parser/HTMLTreeBuilder.cpp @@ -1420,74 +1420,81 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken* token) static const int outerIterationLimit = 8; static const int innerIterationLimit = 3; + // 1, 2, 3 and 16 are covered by the for() loop. for (int i = 0; i < outerIterationLimit; ++i) { - // 1. + // 4. Element* formattingElement = m_tree.activeFormattingElements()->closestElementInScopeWithName(token->name()); - if (!formattingElement || ((m_tree.openElements()->contains(formattingElement)) && !m_tree.openElements()->inScope(formattingElement))) { + // 4.a + if (!formattingElement) + return processAnyOtherEndTagForInBody(token); + // 4.c + if ((m_tree.openElements()->contains(formattingElement)) && !m_tree.openElements()->inScope(formattingElement)) { parseError(token); notImplemented(); // Check the stack of open elements for a more specific parse error. return; } + // 4.b HTMLElementStack::ElementRecord* formattingElementRecord = m_tree.openElements()->find(formattingElement); if (!formattingElementRecord) { parseError(token); m_tree.activeFormattingElements()->remove(formattingElement); return; } + // 4.d if (formattingElement != m_tree.currentElement()) parseError(token); - // 2. + // 5. HTMLElementStack::ElementRecord* furthestBlock = m_tree.openElements()->furthestBlockForFormattingElement(formattingElement); - // 3. + // 6. if (!furthestBlock) { m_tree.openElements()->popUntilPopped(formattingElement); m_tree.activeFormattingElements()->remove(formattingElement); return; } - // 4. + // 7. ASSERT(furthestBlock->isAbove(formattingElementRecord)); RefPtr<HTMLStackItem> commonAncestor = formattingElementRecord->next()->stackItem(); - // 5. + // 8. HTMLFormattingElementList::Bookmark bookmark = m_tree.activeFormattingElements()->bookmarkFor(formattingElement); - // 6. + // 9. HTMLElementStack::ElementRecord* node = furthestBlock; HTMLElementStack::ElementRecord* nextNode = node->next(); HTMLElementStack::ElementRecord* lastNode = furthestBlock; + // 9.1, 9.2, 9.3 and 9.11 are covered by the for() loop. for (int i = 0; i < innerIterationLimit; ++i) { - // 6.1 + // 9.4 node = nextNode; ASSERT(node); - nextNode = node->next(); // Save node->next() for the next iteration in case node is deleted in 6.2. - // 6.2 + nextNode = node->next(); // Save node->next() for the next iteration in case node is deleted in 9.5. + // 9.5 if (!m_tree.activeFormattingElements()->contains(node->element())) { m_tree.openElements()->remove(node->element()); node = 0; continue; } - // 6.3 + // 9.6 if (node == formattingElementRecord) break; - // 6.5 + // 9.7 RefPtr<HTMLStackItem> newItem = m_tree.createElementFromSavedToken(node->stackItem().get()); HTMLFormattingElementList::Entry* nodeEntry = m_tree.activeFormattingElements()->find(node->element()); nodeEntry->replaceElement(newItem); node->replaceElement(newItem.release()); - // 6.4 -- Intentionally out of order to handle the case where node - // was replaced in 6.5. - // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10096 + + // 9.8 if (lastNode == furthestBlock) bookmark.moveToAfter(nodeEntry); - // 6.6 + // 9.9 if (ContainerNode* parent = lastNode->element()->parentNode()) parent->parserRemoveChild(lastNode->element()); node->element()->parserAddChild(lastNode->element()); if (lastNode->element()->parentElement()->attached() && !lastNode->element()->attached()) lastNode->element()->lazyAttach(); - // 6.7 + // 9.10 lastNode = node; } - // 7 + // 10. if (ContainerNode* parent = lastNode->element()->parentNode()) parent->parserRemoveChild(lastNode->element()); if (commonAncestor->causesFosterParenting()) @@ -1499,24 +1506,25 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken* token) if (lastNode->element()->parentNode()->attached() && !lastNode->element()->attached()) lastNode->element()->lazyAttach(); } - // 8 + // 11. RefPtr<HTMLStackItem> newItem = m_tree.createElementFromSavedToken(formattingElementRecord->stackItem().get()); - // 9 + // 12. newItem->element()->takeAllChildrenFrom(furthestBlock->element()); - // 10 + // 13. Element* furthestBlockElement = furthestBlock->element(); // FIXME: All this creation / parserAddChild / attach business should - // be in HTMLConstructionSite. My guess is that steps 8--12 + // be in HTMLConstructionSite. My guess is that steps 11--15 // should all be in some HTMLConstructionSite function. furthestBlockElement->parserAddChild(newItem->element()); + // FIXME: Why is this attach logic necessary? Style resolve should attach us if needed. if (furthestBlockElement->attached() && !newItem->element()->attached()) { // Notice that newItem->element() might already be attached if, for example, one of the reparented // children is a style element, which attaches itself automatically. newItem->element()->attach(); } - // 11 + // 14. m_tree.activeFormattingElements()->swapTo(formattingElement, newItem, bookmark); - // 12 + // 15. m_tree.openElements()->remove(formattingElement); m_tree.openElements()->insertAbove(newItem, furthestBlock); } diff --git a/Source/WebCore/html/shadow/DateTimeEditElement.cpp b/Source/WebCore/html/shadow/DateTimeEditElement.cpp index 11c162072..e9aa858cc 100644 --- a/Source/WebCore/html/shadow/DateTimeEditElement.cpp +++ b/Source/WebCore/html/shadow/DateTimeEditElement.cpp @@ -29,6 +29,7 @@ #include "DateComponents.h" #include "DateTimeFieldElements.h" +#include "DateTimeFieldsState.h" #include "DateTimeFormat.h" #include "DateTimeSymbolicFieldElement.h" #include "EventHandler.h" @@ -36,6 +37,7 @@ #include "KeyboardEvent.h" #include "LocalizedDate.h" #include "LocalizedNumber.h" +#include "Localizer.h" #include "MouseEvent.h" #include "StepRange.h" #include "Text.h" @@ -50,7 +52,7 @@ class DateTimeEditBuilder : private DateTimeFormat::TokenHandler { WTF_MAKE_NONCOPYABLE(DateTimeEditBuilder); public: - DateTimeEditBuilder(DateTimeEditElement&, const StepRange&, const DateComponents&); + DateTimeEditBuilder(DateTimeEditElement&, const StepRange&, const DateComponents&, Localizer&); bool build(const String&); bool needSecondField() const; @@ -69,12 +71,14 @@ private: DateTimeEditElement& m_editElement; const DateComponents& m_dateValue; const StepRange& m_stepRange; + Localizer& m_localizer; }; -DateTimeEditBuilder::DateTimeEditBuilder(DateTimeEditElement& elemnt, const StepRange& stepRange, const DateComponents& dateValue) +DateTimeEditBuilder::DateTimeEditBuilder(DateTimeEditElement& elemnt, const StepRange& stepRange, const DateComponents& dateValue, Localizer& localizer) : m_editElement(elemnt) , m_dateValue(dateValue) , m_stepRange(stepRange) + , m_localizer(localizer) { } @@ -135,7 +139,7 @@ void DateTimeEditBuilder::visitField(DateTimeFormat::FieldType fieldType, int) } case DateTimeFormat::FieldTypePeriod: - m_editElement.addField(DateTimeAMPMFieldElement::create(document, m_editElement, timeAMPMLabels())); + m_editElement.addField(DateTimeAMPMFieldElement::create(document, m_editElement, m_localizer.timeAMPMLabels())); return; case DateTimeFormat::FieldTypeSecond: { @@ -145,7 +149,7 @@ void DateTimeEditBuilder::visitField(DateTimeFormat::FieldType fieldType, int) field->setReadOnly(); if (needMillisecondField()) { - visitLiteral(localizedDecimalSeparator()); + visitLiteral(m_localizer.localizedDecimalSeparator()); visitField(DateTimeFormat::FieldTypeFractionalSecond, 3); } return; @@ -336,14 +340,14 @@ bool DateTimeEditElement::isReadOnly() const return m_editControlOwner && m_editControlOwner->isEditControlOwnerReadOnly(); } -void DateTimeEditElement::layout(const StepRange& stepRange, const DateComponents& dateValue) +void DateTimeEditElement::layout(const StepRange& stepRange, const DateComponents& dateValue, Localizer& localizer) { size_t focusedFieldIndex = this->focusedFieldIndex(); DateTimeFieldElement* const focusedField = fieldAt(focusedFieldIndex); const AtomicString focusedFieldId = focusedField ? focusedField->shadowPseudoId() : nullAtom; - DateTimeEditBuilder builder(*this, stepRange, dateValue); - const String dateTimeFormat = builder.needSecondField() ? localizedTimeFormatText() : localizedShortTimeFormatText(); + DateTimeEditBuilder builder(*this, stepRange, dateValue, localizer); + const String dateTimeFormat = builder.needSecondField() ? localizer.timeFormat() : localizer.shortTimeFormat(); Node* lastChildToBeRemoved = lastChild(); if (!builder.build(dateTimeFormat) || m_fields.isEmpty()) { lastChildToBeRemoved = lastChild(); @@ -403,16 +407,22 @@ void DateTimeEditElement::defaultEventHandler(Event* event) HTMLDivElement::defaultEventHandler(event); } -void DateTimeEditElement::setValueAsDate(const StepRange& stepRange, const DateComponents& date) +void DateTimeEditElement::setValueAsDate(const StepRange& stepRange, const DateComponents& date, Localizer& localizer) { - layout(stepRange, date); + layout(stepRange, date, localizer); for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) m_fields[fieldIndex]->setValueAsDate(date); } -void DateTimeEditElement::setEmptyValue(const StepRange& stepRange, const DateComponents& dateForReadOnlyField) +void DateTimeEditElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState, const DateComponents& dateForReadOnlyField) { - layout(stepRange, dateForReadOnlyField); + for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) + m_fields[fieldIndex]->setValueAsDateTimeFieldsState(dateTimeFieldsState, dateForReadOnlyField); +} + +void DateTimeEditElement::setEmptyValue(const StepRange& stepRange, const DateComponents& dateForReadOnlyField, Localizer& localizer) +{ + layout(stepRange, dateForReadOnlyField, localizer); for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) m_fields[fieldIndex]->setEmptyValue(dateForReadOnlyField, DateTimeFieldElement::DispatchNoEvent); } @@ -451,6 +461,14 @@ void DateTimeEditElement::updateUIState() } } +DateTimeFieldsState DateTimeEditElement::valueAsDateTimeFieldsState() const +{ + DateTimeFieldsState dateTimeFieldsState; + for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) + m_fields[fieldIndex]->populateDateTimeFieldsState(dateTimeFieldsState); + return dateTimeFieldsState; +} + double DateTimeEditElement::valueAsDouble() const { double value = 0; diff --git a/Source/WebCore/html/shadow/DateTimeEditElement.h b/Source/WebCore/html/shadow/DateTimeEditElement.h index 8e6eb11ce..c17bd7a7a 100644 --- a/Source/WebCore/html/shadow/DateTimeEditElement.h +++ b/Source/WebCore/html/shadow/DateTimeEditElement.h @@ -34,7 +34,9 @@ namespace WebCore { class DateComponents; class DateTimeEditLayouter; +class DateTimeFieldsState; class KeyboardEvent; +class Localizer; class MouseEvent; class StepRange; @@ -69,8 +71,10 @@ public: void readOnlyStateChanged(); void removeEditControlOwner() { m_editControlOwner = 0; } void resetFields(); - void setEmptyValue(const StepRange&, const DateComponents& dateForReadOnlyField); - void setValueAsDate(const StepRange&, const DateComponents&); + void setEmptyValue(const StepRange&, const DateComponents& dateForReadOnlyField, Localizer&); + void setValueAsDate(const StepRange&, const DateComponents&, Localizer&); + void setValueAsDateTimeFieldsState(const DateTimeFieldsState&, const DateComponents& dateForReadOnlyField); + DateTimeFieldsState valueAsDateTimeFieldsState() const; double valueAsDouble() const; private: @@ -95,7 +99,7 @@ private: size_t focusedFieldIndex() const; bool isDisabled() const; bool isReadOnly() const; - void layout(const StepRange&, const DateComponents&); + void layout(const StepRange&, const DateComponents&, Localizer&); void updateUIState(); // DateTimeFieldElement::FieldOwner functions. diff --git a/Source/WebCore/html/shadow/DateTimeFieldElement.cpp b/Source/WebCore/html/shadow/DateTimeFieldElement.cpp index b62467d4b..74817570a 100644 --- a/Source/WebCore/html/shadow/DateTimeFieldElement.cpp +++ b/Source/WebCore/html/shadow/DateTimeFieldElement.cpp @@ -30,8 +30,10 @@ #include "DateComponents.h" #include "HTMLNames.h" #include "KeyboardEvent.h" +#include "LocalizedStrings.h" #include "RenderObject.h" #include "Text.h" +#include <wtf/text/WTFString.h> namespace WebCore { @@ -45,6 +47,8 @@ DateTimeFieldElement::DateTimeFieldElement(Document* document, FieldOwner& field : HTMLElement(spanTag, document) , m_fieldOwner(&fieldOwner) { + // On accessibility, DateTimeFieldElement acts like spin button. + setAttribute(roleAttr, "spinbutton"); } void DateTimeFieldElement::defaultEventHandler(Event* event) @@ -129,8 +133,11 @@ void DateTimeFieldElement::focusOnNextField() m_fieldOwner->focusOnNextField(*this); } -void DateTimeFieldElement::initialize(const AtomicString& shadowPseudoId) +void DateTimeFieldElement::initialize(const AtomicString& shadowPseudoId, const String& axHelpText) { + setAttribute(aria_helpAttr, axHelpText); + setAttribute(aria_valueminAttr, String::number(minimum())); + setAttribute(aria_valuemaxAttr, String::number(maximum())); setShadowPseudoId(shadowPseudoId); appendChild(Text::create(document(), visibleValue())); } @@ -172,6 +179,8 @@ void DateTimeFieldElement::updateVisibleValue(EventBehavior eventBehavior) return; textNode->replaceWholeText(newVisibleValue, ASSERT_NO_EXCEPTION); + setAttribute(aria_valuetextAttr, hasValue() ? newVisibleValue : AXDateTimeFieldEmptyValueText()); + setAttribute(aria_valuenowAttr, newVisibleValue); if (eventBehavior == DispatchEvent && m_fieldOwner) m_fieldOwner->fieldValueChanged(); diff --git a/Source/WebCore/html/shadow/DateTimeFieldElement.h b/Source/WebCore/html/shadow/DateTimeFieldElement.h index 0a9bee010..e8d25cf91 100644 --- a/Source/WebCore/html/shadow/DateTimeFieldElement.h +++ b/Source/WebCore/html/shadow/DateTimeFieldElement.h @@ -33,6 +33,7 @@ namespace WebCore { class DateComponents; +class DateTimeFieldsState; // DateTimeFieldElement is base class of date time field element. class DateTimeFieldElement : public HTMLElement { @@ -59,10 +60,12 @@ public: virtual void defaultEventHandler(Event*) OVERRIDE; virtual bool hasValue() const = 0; bool isReadOnly() const; + virtual void populateDateTimeFieldsState(DateTimeFieldsState&) = 0; void removeEventHandler() { m_fieldOwner = 0; } void setReadOnly(); virtual void setEmptyValue(const DateComponents& dateForReadOnlyField, EventBehavior = DispatchNoEvent) = 0; virtual void setValueAsDate(const DateComponents&) = 0; + virtual void setValueAsDateTimeFieldsState(const DateTimeFieldsState&, const DateComponents& dateForReadOnlyField) = 0; virtual void setValueAsInteger(int, EventBehavior = DispatchNoEvent) = 0; virtual void stepDown() = 0; virtual void stepUp() = 0; @@ -77,7 +80,9 @@ protected: virtual void didFocus(); void focusOnNextField(); virtual void handleKeyboardEvent(KeyboardEvent*) = 0; - void initialize(const AtomicString&); + void initialize(const AtomicString& shadowPseudoId, const String& axHelpText); + virtual int maximum() const = 0; + virtual int minimum() const = 0; virtual double unitInMillisecond() const = 0; void updateVisibleValue(EventBehavior); diff --git a/Source/WebCore/html/shadow/DateTimeFieldElements.cpp b/Source/WebCore/html/shadow/DateTimeFieldElements.cpp index d8bc849fd..2016c69a8 100644 --- a/Source/WebCore/html/shadow/DateTimeFieldElements.cpp +++ b/Source/WebCore/html/shadow/DateTimeFieldElements.cpp @@ -28,6 +28,8 @@ #include "DateTimeFieldElements.h" #include "DateComponents.h" +#include "DateTimeFieldsState.h" +#include "LocalizedStrings.h" #include <wtf/DateMath.h> namespace WebCore { @@ -41,15 +43,31 @@ PassRefPtr<DateTimeAMPMFieldElement> DateTimeAMPMFieldElement::create(Document* { DEFINE_STATIC_LOCAL(AtomicString, ampmPsuedoId, ("-webkit-datetime-edit-ampm-field")); RefPtr<DateTimeAMPMFieldElement> field = adoptRef(new DateTimeAMPMFieldElement(document, fieldOwner, ampmLabels)); - field->initialize(ampmPsuedoId); + field->initialize(ampmPsuedoId, AXAMPMFieldText()); return field.release(); } +void DateTimeAMPMFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState) +{ + if (hasValue()) + dateTimeFieldsState.setAMPM(valueAsInteger() ? DateTimeFieldsState::AMPMValuePM : DateTimeFieldsState::AMPMValueAM); + else + dateTimeFieldsState.setAMPM(DateTimeFieldsState::AMPMValueEmpty); +} + void DateTimeAMPMFieldElement::setValueAsDate(const DateComponents& date) { setValueAsInteger(date.hour() >= 12 ? 1 : 0); } +void DateTimeAMPMFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState, const DateComponents& dateForReadOnlyField) +{ + if (dateTimeFieldsState.hasAMPM()) + setValueAsInteger(dateTimeFieldsState.ampm()); + else + setEmptyValue(dateForReadOnlyField); +} + double DateTimeAMPMFieldElement::unitInMillisecond() const { return msPerHour * 12; @@ -68,15 +86,87 @@ PassRefPtr<DateTimeHourFieldElement> DateTimeHourFieldElement::create(Document* { DEFINE_STATIC_LOCAL(AtomicString, hourPsuedoId, ("-webkit-datetime-edit-hour-field")); RefPtr<DateTimeHourFieldElement> field = adoptRef(new DateTimeHourFieldElement(document, fieldOwner, minimum, maximum)); - field->initialize(hourPsuedoId); + field->initialize(hourPsuedoId, AXHourFieldText()); return field.release(); } +void DateTimeHourFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState) +{ + if (!hasValue()) { + dateTimeFieldsState.setHour(DateTimeFieldsState::emptyValue); + return; + } + + const int value = DateTimeNumericFieldElement::valueAsInteger(); + + switch (maximum()) { + case 11: + dateTimeFieldsState.setHour(value ? value : 12); + return; + case 12: + dateTimeFieldsState.setHour(value); + return; + case 23: + dateTimeFieldsState.setHour(value ? value % 12 : 12); + dateTimeFieldsState.setAMPM(value >= 12 ? DateTimeFieldsState::AMPMValuePM : DateTimeFieldsState::AMPMValueAM); + return; + case 24: + if (value == 24) { + dateTimeFieldsState.setHour(12); + dateTimeFieldsState.setHour(DateTimeFieldsState::AMPMValueAM); + return; + } + dateTimeFieldsState.setHour(value == 12 ? 12 : value % 12); + dateTimeFieldsState.setAMPM(value >= 12 ? DateTimeFieldsState::AMPMValuePM : DateTimeFieldsState::AMPMValueAM); + return; + default: + ASSERT_NOT_REACHED(); + } +} + void DateTimeHourFieldElement::setValueAsDate(const DateComponents& date) { setValueAsInteger(date.hour()); } +void DateTimeHourFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState, const DateComponents& dateForReadOnlyField) +{ + if (!dateTimeFieldsState.hasHour()) { + setEmptyValue(dateForReadOnlyField); + return; + } + + const int hour12 = dateTimeFieldsState.hour(); + + if (hour12 < 1 || hour12 > 12) { + setEmptyValue(dateForReadOnlyField); + return; + } + + switch (maximum()) { + case 11: + DateTimeNumericFieldElement::setValueAsInteger(hour12 % 12); + return; + case 12: + DateTimeNumericFieldElement::setValueAsInteger(hour12); + return; + case 23: + if (dateTimeFieldsState.ampm() == DateTimeFieldsState::AMPMValuePM) + DateTimeNumericFieldElement::setValueAsInteger((hour12 + 12) % 24); + else + DateTimeNumericFieldElement::setValueAsInteger(hour12 % 12); + return; + case 24: + if (dateTimeFieldsState.ampm() == DateTimeFieldsState::AMPMValuePM) + DateTimeNumericFieldElement::setValueAsInteger(hour12 == 12 ? 12 : hour12 + 12); + else + DateTimeNumericFieldElement::setValueAsInteger(hour12); + return; + default: + ASSERT_NOT_REACHED(); + } +} + void DateTimeHourFieldElement::setValueAsInteger(int valueAsHour23, EventBehavior eventBehavior) { const int value = Range(0, 23).clampValue(valueAsHour23) % m_alignment; @@ -104,15 +194,36 @@ PassRefPtr<DateTimeMillisecondFieldElement> DateTimeMillisecondFieldElement::cre { DEFINE_STATIC_LOCAL(AtomicString, millisecondPsuedoId, ("-webkit-datetime-edit-millisecond-field")); RefPtr<DateTimeMillisecondFieldElement> field = adoptRef(new DateTimeMillisecondFieldElement(document, fieldOwner)); - field->initialize(millisecondPsuedoId); + field->initialize(millisecondPsuedoId, AXMillisecondFieldText()); return field.release(); } +void DateTimeMillisecondFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState) +{ + dateTimeFieldsState.setMillisecond(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue); +} + void DateTimeMillisecondFieldElement::setValueAsDate(const DateComponents& date) { setValueAsInteger(date.millisecond()); } +void DateTimeMillisecondFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState, const DateComponents& dateForReadOnlyField) +{ + if (!dateTimeFieldsState.hasMillisecond()) { + setEmptyValue(dateForReadOnlyField); + return; + } + + const unsigned value = dateTimeFieldsState.millisecond(); + if (value > static_cast<unsigned>(maximum())) { + setEmptyValue(dateForReadOnlyField); + return; + } + + setValueAsInteger(value); +} + double DateTimeMillisecondFieldElement::unitInMillisecond() const { return 1; @@ -129,15 +240,36 @@ PassRefPtr<DateTimeMinuteFieldElement> DateTimeMinuteFieldElement::create(Docume { DEFINE_STATIC_LOCAL(AtomicString, minutePsuedoId, ("-webkit-datetime-edit-minute-field")); RefPtr<DateTimeMinuteFieldElement> field = adoptRef(new DateTimeMinuteFieldElement(document, fieldOwner)); - field->initialize(minutePsuedoId); + field->initialize(minutePsuedoId, AXMinuteFieldText()); return field.release(); } +void DateTimeMinuteFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState) +{ + dateTimeFieldsState.setMinute(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue); +} + void DateTimeMinuteFieldElement::setValueAsDate(const DateComponents& date) { setValueAsInteger(date.minute()); } +void DateTimeMinuteFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState, const DateComponents& dateForReadOnlyField) +{ + if (!dateTimeFieldsState.hasMinute()) { + setEmptyValue(dateForReadOnlyField); + return; + } + + const unsigned value = dateTimeFieldsState.minute(); + if (value > static_cast<unsigned>(maximum())) { + setEmptyValue(dateForReadOnlyField); + return; + } + + setValueAsInteger(value); +} + double DateTimeMinuteFieldElement::unitInMillisecond() const { return msPerMinute; @@ -154,15 +286,36 @@ PassRefPtr<DateTimeSecondFieldElement> DateTimeSecondFieldElement::create(Docume { DEFINE_STATIC_LOCAL(AtomicString, secondPsuedoId, ("-webkit-datetime-edit-second-field")); RefPtr<DateTimeSecondFieldElement> field = adoptRef(new DateTimeSecondFieldElement(document, fieldOwner)); - field->initialize(secondPsuedoId); + field->initialize(secondPsuedoId, AXSecondFieldText()); return field.release(); } +void DateTimeSecondFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState) +{ + dateTimeFieldsState.setSecond(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue); +} + void DateTimeSecondFieldElement::setValueAsDate(const DateComponents& date) { setValueAsInteger(date.second()); } +void DateTimeSecondFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState, const DateComponents& dateForReadOnlyField) +{ + if (!dateTimeFieldsState.hasSecond()) { + setEmptyValue(dateForReadOnlyField); + return; + } + + const unsigned value = dateTimeFieldsState.second(); + if (value > static_cast<unsigned>(maximum())) { + setEmptyValue(dateForReadOnlyField); + return; + } + + setValueAsInteger(value); +} + double DateTimeSecondFieldElement::unitInMillisecond() const { return msPerSecond; diff --git a/Source/WebCore/html/shadow/DateTimeFieldElements.h b/Source/WebCore/html/shadow/DateTimeFieldElements.h index d7f4d9538..e141f838f 100644 --- a/Source/WebCore/html/shadow/DateTimeFieldElements.h +++ b/Source/WebCore/html/shadow/DateTimeFieldElements.h @@ -42,7 +42,9 @@ private: DateTimeAMPMFieldElement(Document*, FieldOwner&, const Vector<String>&); // DateTimeFieldElement functions. + virtual void populateDateTimeFieldsState(DateTimeFieldsState&) OVERRIDE FINAL; virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL; + virtual void setValueAsDateTimeFieldsState(const DateTimeFieldsState&, const DateComponents& dateForReadOnlyField) OVERRIDE FINAL; virtual double unitInMillisecond() const OVERRIDE FINAL; }; @@ -63,7 +65,9 @@ private: DateTimeHourFieldElement(Document*, FieldOwner&, int minimum, int maximum); // DateTimeFieldElement functions. + virtual void populateDateTimeFieldsState(DateTimeFieldsState&) OVERRIDE FINAL; virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL; + virtual void setValueAsDateTimeFieldsState(const DateTimeFieldsState&, const DateComponents& dateForReadOnlyField) OVERRIDE FINAL; virtual void setValueAsInteger(int, EventBehavior = DispatchNoEvent) OVERRIDE FINAL; virtual double unitInMillisecond() const OVERRIDE FINAL; virtual int valueAsInteger() const OVERRIDE FINAL; @@ -81,7 +85,9 @@ private: DateTimeMillisecondFieldElement(Document*, FieldOwner&); // DateTimeFieldElement functions. + virtual void populateDateTimeFieldsState(DateTimeFieldsState&) OVERRIDE FINAL; virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL; + virtual void setValueAsDateTimeFieldsState(const DateTimeFieldsState&, const DateComponents& dateForReadOnlyField) OVERRIDE FINAL; virtual double unitInMillisecond() const OVERRIDE FINAL; }; @@ -95,7 +101,9 @@ private: DateTimeMinuteFieldElement(Document*, FieldOwner&); // DateTimeFieldElement functions. + virtual void populateDateTimeFieldsState(DateTimeFieldsState&) OVERRIDE FINAL; virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL; + virtual void setValueAsDateTimeFieldsState(const DateTimeFieldsState&, const DateComponents& dateForReadOnlyField) OVERRIDE FINAL; virtual double unitInMillisecond() const OVERRIDE FINAL; }; @@ -109,7 +117,9 @@ private: DateTimeSecondFieldElement(Document*, FieldOwner&); // DateTimeFieldElement functions. + virtual void populateDateTimeFieldsState(DateTimeFieldsState&) OVERRIDE FINAL; virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL; + virtual void setValueAsDateTimeFieldsState(const DateTimeFieldsState&, const DateComponents& dateForReadOnlyField) OVERRIDE FINAL; virtual double unitInMillisecond() const OVERRIDE FINAL; }; diff --git a/Source/WebCore/html/shadow/DateTimeNumericFieldElement.cpp b/Source/WebCore/html/shadow/DateTimeNumericFieldElement.cpp index bf80af942..cf8a4a338 100644 --- a/Source/WebCore/html/shadow/DateTimeNumericFieldElement.cpp +++ b/Source/WebCore/html/shadow/DateTimeNumericFieldElement.cpp @@ -111,6 +111,16 @@ bool DateTimeNumericFieldElement::hasValue() const return m_hasValue; } +int DateTimeNumericFieldElement::maximum() const +{ + return m_range.maximum; +} + +int DateTimeNumericFieldElement::minimum() const +{ + return m_range.minimum; +} + void DateTimeNumericFieldElement::setEmptyValue(const DateComponents& dateForReadOnlyField, EventBehavior eventBehavior) { m_lastDigitCharTime = 0; diff --git a/Source/WebCore/html/shadow/DateTimeNumericFieldElement.h b/Source/WebCore/html/shadow/DateTimeNumericFieldElement.h index 283e60672..28f2b9e49 100644 --- a/Source/WebCore/html/shadow/DateTimeNumericFieldElement.h +++ b/Source/WebCore/html/shadow/DateTimeNumericFieldElement.h @@ -57,6 +57,8 @@ protected: // DateTimeFieldElement functions. virtual bool hasValue() const OVERRIDE FINAL; + virtual int maximum() const OVERRIDE FINAL; + virtual void setEmptyValue(const DateComponents& dateForReadOnlyField, EventBehavior = DispatchNoEvent) OVERRIDE FINAL; virtual void setValueAsInteger(int, EventBehavior = DispatchNoEvent) OVERRIDE; virtual int valueAsInteger() const OVERRIDE; virtual String visibleValue() const OVERRIDE FINAL; @@ -65,7 +67,7 @@ private: // DateTimeFieldElement functions. virtual void didBlur() OVERRIDE FINAL; virtual void handleKeyboardEvent(KeyboardEvent*) OVERRIDE FINAL; - virtual void setEmptyValue(const DateComponents& dateForReadOnlyField, EventBehavior) OVERRIDE FINAL; + virtual int minimum() const OVERRIDE FINAL; virtual void stepDown() OVERRIDE FINAL; virtual void stepUp() OVERRIDE FINAL; virtual String value() const OVERRIDE FINAL; diff --git a/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.cpp b/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.cpp index beadca974..6cb4ec1e2 100644 --- a/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.cpp +++ b/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.cpp @@ -95,6 +95,16 @@ bool DateTimeSymbolicFieldElement::hasValue() const return m_selectedIndex >= 0; } +int DateTimeSymbolicFieldElement::maximum() const +{ + return static_cast<int>(m_symbols.size()); +} + +int DateTimeSymbolicFieldElement::minimum() const +{ + return 1; +} + void DateTimeSymbolicFieldElement::setEmptyValue(const DateComponents&, EventBehavior eventBehavior) { m_selectedIndex = invalidIndex; diff --git a/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.h b/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.h index b21a8e4f3..cb0ac1e7b 100644 --- a/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.h +++ b/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.h @@ -38,7 +38,10 @@ class DateTimeSymbolicFieldElement : public DateTimeFieldElement { protected: DateTimeSymbolicFieldElement(Document*, FieldOwner&, const Vector<String>&); + virtual bool hasValue() const OVERRIDE FINAL; + virtual void setEmptyValue(const DateComponents& dateForReadOnlyField, EventBehavior = DispatchNoEvent) OVERRIDE FINAL; virtual void setValueAsInteger(int, EventBehavior = DispatchNoEvent) OVERRIDE FINAL; + virtual int valueAsInteger() const OVERRIDE FINAL; private: static const int invalidIndex = -1; @@ -48,12 +51,11 @@ private: // DateTimeFieldElement functions. virtual void handleKeyboardEvent(KeyboardEvent*) OVERRIDE FINAL; - virtual bool hasValue() const OVERRIDE FINAL; - virtual void setEmptyValue(const DateComponents& dateForReadOnlyField, EventBehavior = DispatchNoEvent) OVERRIDE FINAL; + virtual int maximum() const OVERRIDE FINAL; + virtual int minimum() const OVERRIDE FINAL; virtual void stepDown() OVERRIDE FINAL; virtual void stepUp() OVERRIDE FINAL; virtual String value() const OVERRIDE FINAL; - virtual int valueAsInteger() const OVERRIDE FINAL; virtual String visibleValue() const OVERRIDE FINAL; const Vector<String> m_symbols; diff --git a/Source/WebCore/html/shadow/MediaControlRootElementChromium.cpp b/Source/WebCore/html/shadow/MediaControlRootElementChromium.cpp index c0cf0a0b1..6b3913bb6 100644 --- a/Source/WebCore/html/shadow/MediaControlRootElementChromium.cpp +++ b/Source/WebCore/html/shadow/MediaControlRootElementChromium.cpp @@ -29,17 +29,13 @@ #if ENABLE(VIDEO) #include "MediaControlRootElementChromium.h" -#include "CSSValueKeywords.h" #include "HTMLDivElement.h" #include "HTMLMediaElement.h" #include "HTMLNames.h" #include "MediaControlElements.h" #include "MouseEvent.h" #include "Page.h" -#include "RenderMedia.h" #include "RenderTheme.h" -#include "RenderView.h" -#include "StyleResolver.h" #include "Text.h" #if ENABLE(VIDEO_TRACK) @@ -63,69 +59,6 @@ MediaControlElementType MediaControlChromiumEnclosureElement::displayType() cons return MediaControlsPanel; } - -class RenderMediaControlPanelEnclosureElement : public RenderBlock { -public: - RenderMediaControlPanelEnclosureElement(Node*); - -private: - virtual void layout() OVERRIDE; -}; - -RenderMediaControlPanelEnclosureElement::RenderMediaControlPanelEnclosureElement(Node* node) - : RenderBlock(node) -{ -} - -static const int hideTimeDisplayWidth = 350; -static const int hideVolumeDisplayWidth = 275; -static const int hideMuteButtonWidth = 210; -static const int hideFullscreenButtonWidth = 150; -static const int hideTimelineWidth = 100; - -void RenderMediaControlPanelEnclosureElement::layout() -{ - HTMLMediaElement* mediaElement = toParentMediaElement(this); - if (!mediaElement || !mediaElement->renderer()) - return; - - float mediaWidthFloat = toRenderMedia(mediaElement->renderer())->contentBoxRect().width().toFloat(); - int mediaWidth = round(adjustFloatForAbsoluteZoom(mediaWidthFloat, style())); - - MediaControlRootElementChromium* elementShadow = (MediaControlRootElementChromium *) mediaElement->mediaControls(); - - if (mediaWidth < hideTimeDisplayWidth) - elementShadow->hideTimeDisplay(); - else - elementShadow->showTimeDisplay(); - - if (mediaWidth < hideVolumeDisplayWidth) - elementShadow->hideVolumeSlider(); - else - elementShadow->showVolumeSlider(); - - if (mediaWidth < hideMuteButtonWidth) - elementShadow->hideMuteButton(); - else - elementShadow->showMuteButton(); - - if (mediaWidth < hideFullscreenButtonWidth) - elementShadow->hideFullscreenButton(); - else - elementShadow->showFullscreenButton(); - - if (mediaWidth < hideTimelineWidth) - elementShadow->hideTimeline(); - else - elementShadow->showTimeline(); - - if (mediaElement->renderer()->isVideo()) - // Update padding according to video width. - static_cast<MediaControlPanelEnclosureElement*>(node())->updatePadding(mediaWidth); - - RenderBlock::layout(); -} - MediaControlPanelEnclosureElement::MediaControlPanelEnclosureElement(Document* document) : MediaControlChromiumEnclosureElement(document) { @@ -136,39 +69,12 @@ PassRefPtr<MediaControlPanelEnclosureElement> MediaControlPanelEnclosureElement: return adoptRef(new MediaControlPanelEnclosureElement(document)); } -RenderObject* MediaControlPanelEnclosureElement::createRenderer(RenderArena* arena, RenderStyle*) -{ - return new (arena) RenderMediaControlPanelEnclosureElement(this); -} - const AtomicString& MediaControlPanelEnclosureElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-enclosure")); return id; } -// Make sure to keep these values in sync with the ones in mediaControlsChromium.css. -static const int videoControlsHeight = 30; -static const int maxPadding = 5; -static const int minPadding = 0; -static const int minPaddingAtWidth = 160; -static const int decreaseStep = 60; - -void MediaControlPanelEnclosureElement::updatePadding(int mediaWidth) -{ - // Scale padding linearly between minPadding and maxPadding depending on mediaWidth. - float padding = round((mediaWidth - minPaddingAtWidth) / decreaseStep); - if (padding < minPadding) - padding = minPadding; - else if (padding > maxPadding) - padding = maxPadding; - - setInlineStyleProperty(CSSPropertyPaddingRight, padding, CSSPrimitiveValue::CSS_PX); - setInlineStyleProperty(CSSPropertyPaddingBottom, padding, CSSPrimitiveValue::CSS_PX); - setInlineStyleProperty(CSSPropertyPaddingLeft, padding, CSSPrimitiveValue::CSS_PX); - setInlineStyleProperty(CSSPropertyHeight, padding + videoControlsHeight, CSSPrimitiveValue::CSS_PX); -} - MediaControlRootElementChromium::MediaControlRootElementChromium(Document* document) : MediaControls(document) , m_mediaController(0) @@ -188,7 +94,6 @@ MediaControlRootElementChromium::MediaControlRootElementChromium(Document* docum , m_hideFullscreenControlsTimer(this, &MediaControlRootElementChromium::hideFullscreenControlsTimerFired) , m_isMouseOverControls(false) , m_isFullscreen(false) - , m_hiddenTimeDisplay(false) { } @@ -352,12 +257,16 @@ void MediaControlRootElementChromium::reset() float duration = m_mediaController->duration(); m_timeline->setDuration(duration); + m_timeline->show(); m_durationDisplay->setInnerText(page->theme()->formatMediaControlsTime(duration), ASSERT_NO_EXCEPTION); m_durationDisplay->setCurrentValue(duration); + m_timeline->setPosition(m_mediaController->currentTime()); updateTimeDisplay(); + m_panelMuteButton->show(); + if (m_volumeSlider) { if (!m_mediaController->hasAudio()) m_volumeSlider->hide(); @@ -374,14 +283,19 @@ void MediaControlRootElementChromium::reset() m_toggleClosedCaptionsButton->hide(); } - showFullscreenButton(); - + if (m_mediaController->supportsFullscreen() && m_mediaController->hasVideo()) + m_fullscreenButton->show(); + else + m_fullscreenButton->hide(); makeOpaque(); } void MediaControlRootElementChromium::playbackStarted() { m_playButton->updateDisplayType(); + m_timeline->setPosition(m_mediaController->currentTime()); + m_currentTimeDisplay->show(); + m_durationDisplay->hide(); updateTimeDisplay(); if (m_isFullscreen) @@ -390,6 +304,7 @@ void MediaControlRootElementChromium::playbackStarted() void MediaControlRootElementChromium::playbackProgressed() { + m_timeline->setPosition(m_mediaController->currentTime()); updateTimeDisplay(); if (!m_isMouseOverControls && m_mediaController->hasVideo()) @@ -399,6 +314,7 @@ void MediaControlRootElementChromium::playbackProgressed() void MediaControlRootElementChromium::playbackStopped() { m_playButton->updateDisplayType(); + m_timeline->setPosition(m_mediaController->currentTime()); updateTimeDisplay(); makeOpaque(); @@ -414,8 +330,8 @@ void MediaControlRootElementChromium::updateTimeDisplay() if (!page) return; - // After seek or playback start, hide duration display and show current time. - if (!m_hiddenTimeDisplay && now > 0) { + // After seek, hide duration display and show current time. + if (now > 0) { m_currentTimeDisplay->show(); m_durationDisplay->hide(); } @@ -424,8 +340,6 @@ void MediaControlRootElementChromium::updateTimeDisplay() ExceptionCode ec; m_currentTimeDisplay->setInnerText(page->theme()->formatMediaControlsCurrentTime(now, duration), ec); m_currentTimeDisplay->setCurrentValue(now); - - m_timeline->setPosition(m_mediaController->currentTime()); } void MediaControlRootElementChromium::reportedError() @@ -564,61 +478,6 @@ void MediaControlRootElementChromium::showVolumeSlider() m_volumeSlider->show(); } -void MediaControlRootElementChromium::hideVolumeSlider() -{ - m_volumeSlider->hide(); -} - -void MediaControlRootElementChromium::showTimeDisplay() -{ - m_hiddenTimeDisplay = false; - m_durationDisplay->show(); - updateTimeDisplay(); -} - -void MediaControlRootElementChromium::hideTimeDisplay() -{ - m_hiddenTimeDisplay = true; - m_durationDisplay->hide(); - m_currentTimeDisplay->hide(); -} - -void MediaControlRootElementChromium::showMuteButton() -{ - if (!m_mediaController->hasAudio()) - return; - - m_panelMuteButton->show(); -} - -void MediaControlRootElementChromium::hideMuteButton() -{ - m_panelMuteButton->hide(); -} - -void MediaControlRootElementChromium::showFullscreenButton() -{ - if (!m_mediaController->supportsFullscreen() || !m_mediaController->hasVideo()) - return; - - m_fullscreenButton->show(); -} - -void MediaControlRootElementChromium::hideFullscreenButton() -{ - m_fullscreenButton->hide(); -} - -void MediaControlRootElementChromium::showTimeline() -{ - m_timeline->show(); -} - -void MediaControlRootElementChromium::hideTimeline() -{ - m_timeline->hide(); -} - #if ENABLE(VIDEO_TRACK) void MediaControlRootElementChromium::createTextTrackDisplay() { diff --git a/Source/WebCore/html/shadow/MediaControlRootElementChromium.h b/Source/WebCore/html/shadow/MediaControlRootElementChromium.h index 6879dcbf9..8c2061233 100644 --- a/Source/WebCore/html/shadow/MediaControlRootElementChromium.h +++ b/Source/WebCore/html/shadow/MediaControlRootElementChromium.h @@ -74,8 +74,6 @@ private: class MediaControlPanelEnclosureElement : public MediaControlChromiumEnclosureElement { public: static PassRefPtr<MediaControlPanelEnclosureElement> create(Document*); - virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) OVERRIDE; - void updatePadding(int mediaWidth); private: explicit MediaControlPanelEnclosureElement(Document*); @@ -111,16 +109,6 @@ public: void changedClosedCaptionsVisibility(); void showVolumeSlider(); - void hideVolumeSlider(); - void showTimeDisplay(); - void hideTimeDisplay(); - void showMuteButton(); - void hideMuteButton(); - void showFullscreenButton(); - void hideFullscreenButton(); - void showTimeline(); - void hideTimeline(); - void updateTimeDisplay(); void updateStatusDisplay(); @@ -171,7 +159,6 @@ private: Timer<MediaControlRootElementChromium> m_hideFullscreenControlsTimer; bool m_isMouseOverControls; bool m_isFullscreen; - bool m_hiddenTimeDisplay; }; } |