diff options
Diffstat (limited to 'Source/WebCore/html')
110 files changed, 2414 insertions, 584 deletions
diff --git a/Source/WebCore/html/ClassList.cpp b/Source/WebCore/html/ClassList.cpp index 2ea838202..a325a1226 100644 --- a/Source/WebCore/html/ClassList.cpp +++ b/Source/WebCore/html/ClassList.cpp @@ -131,14 +131,14 @@ String ClassList::toString() const void ClassList::reset(const String& newClassName) { - if (!m_classNamesForQuirksMode.isNull()) + if (m_element->document()->inQuirksMode()) m_classNamesForQuirksMode.set(newClassName, false); } const SpaceSplitString& ClassList::classNames() const { ASSERT(m_element->hasClass()); - if (!m_classNamesForQuirksMode.isNull()) + if (m_element->document()->inQuirksMode()) return m_classNamesForQuirksMode; return m_element->attributeData()->classNames(); } diff --git a/Source/WebCore/html/ColorInputType.cpp b/Source/WebCore/html/ColorInputType.cpp index 3e75c6e65..c4eb524e5 100644 --- a/Source/WebCore/html/ColorInputType.cpp +++ b/Source/WebCore/html/ColorInputType.cpp @@ -168,7 +168,7 @@ bool ColorInputType::shouldRespectListAttribute() bool ColorInputType::typeMismatchFor(const String& value) const { - return isValidColorString(value); + return !isValidColorString(value); } void ColorInputType::didChooseColor(const Color& color) diff --git a/Source/WebCore/html/DOMTokenList.cpp b/Source/WebCore/html/DOMTokenList.cpp index 5c41f74b5..7132b1169 100644 --- a/Source/WebCore/html/DOMTokenList.cpp +++ b/Source/WebCore/html/DOMTokenList.cpp @@ -56,8 +56,9 @@ String DOMTokenList::addToken(const AtomicString& input, const AtomicString& tok StringBuilder builder; builder.append(input); - if (input[input.length()-1] != ' ') + if (!isHTMLSpace(input[input.length() - 1])) builder.append(' '); + builder.append(token); return builder.toString(); } diff --git a/Source/WebCore/html/DOMURL.cpp b/Source/WebCore/html/DOMURL.cpp index 4f9780dcd..f6586264f 100644 --- a/Source/WebCore/html/DOMURL.cpp +++ b/Source/WebCore/html/DOMURL.cpp @@ -42,6 +42,11 @@ #include <wtf/PassOwnPtr.h> #include <wtf/MainThread.h> +#if ENABLE(MEDIA_SOURCE) +#include "MediaSource.h" +#include "MediaSourceRegistry.h" +#endif + #if ENABLE(MEDIA_STREAM) #include "MediaStream.h" #include "MediaStreamRegistry.h" @@ -49,6 +54,26 @@ namespace WebCore { +#if ENABLE(MEDIA_SOURCE) +String DOMURL::createObjectURL(ScriptExecutionContext* scriptExecutionContext, MediaSource* source) +{ + // Since WebWorkers cannot obtain MediaSource objects, we should be on the main thread. + ASSERT(isMainThread()); + + if (!scriptExecutionContext || !source) + return String(); + + KURL publicURL = BlobURL::createPublicURL(scriptExecutionContext->securityOrigin()); + if (publicURL.isEmpty()) + return String(); + + MediaSourceRegistry::registry().registerMediaSourceURL(publicURL, source); + scriptExecutionContext->publicURLManager().sourceURLs().add(publicURL.string()); + + return publicURL.string(); +} +#endif + #if ENABLE(MEDIA_STREAM) String DOMURL::createObjectURL(ScriptExecutionContext* scriptExecutionContext, MediaStream* stream) { @@ -98,6 +123,13 @@ void DOMURL::revokeObjectURL(ScriptExecutionContext* scriptExecutionContext, con blobURLs.remove(url.string()); } +#if ENABLE(MEDIA_SOURCE) + HashSet<String>& sourceURLs = scriptExecutionContext->publicURLManager().sourceURLs(); + if (sourceURLs.contains(url.string())) { + MediaSourceRegistry::registry().unregisterMediaSourceURL(url); + sourceURLs.remove(url.string()); + } +#endif #if ENABLE(MEDIA_STREAM) HashSet<String>& streamURLs = scriptExecutionContext->publicURLManager().streamURLs(); if (streamURLs.contains(url.string())) { diff --git a/Source/WebCore/html/DOMURL.h b/Source/WebCore/html/DOMURL.h index 25ae013eb..d71fb93f3 100644 --- a/Source/WebCore/html/DOMURL.h +++ b/Source/WebCore/html/DOMURL.h @@ -36,6 +36,7 @@ namespace WebCore { class Blob; +class MediaSource; class MediaStream; class ScriptExecutionContext; @@ -49,6 +50,9 @@ public: static String createObjectURL(ScriptExecutionContext*, Blob*); static void revokeObjectURL(ScriptExecutionContext*, const String&); +#if ENABLE(MEDIA_SOURCE) + static String createObjectURL(ScriptExecutionContext*, MediaSource*); +#endif #if ENABLE(MEDIA_STREAM) static String createObjectURL(ScriptExecutionContext*, MediaStream*); #endif diff --git a/Source/WebCore/html/DOMURL.idl b/Source/WebCore/html/DOMURL.idl index ed04c23d5..b36e8f7ce 100644 --- a/Source/WebCore/html/DOMURL.idl +++ b/Source/WebCore/html/DOMURL.idl @@ -33,6 +33,9 @@ module html { JSNoStaticTables, InterfaceName=URL ] DOMURL { +#if defined(ENABLE_MEDIA_SOURCE) && ENABLE_MEDIA_SOURCE + [CallWith=ScriptExecutionContext,TreatReturnedNullStringAs=Null] static DOMString createObjectURL(in MediaSource? source); +#endif #if defined(ENABLE_MEDIA_STREAM) && ENABLE_MEDIA_STREAM [CallWith=ScriptExecutionContext,TreatReturnedNullStringAs=Null] static DOMString createObjectURL(in MediaStream? stream); #endif diff --git a/Source/WebCore/html/FTPDirectoryDocument.cpp b/Source/WebCore/html/FTPDirectoryDocument.cpp index 18689c97f..8fefc201e 100644 --- a/Source/WebCore/html/FTPDirectoryDocument.cpp +++ b/Source/WebCore/html/FTPDirectoryDocument.cpp @@ -36,10 +36,11 @@ #include "Settings.h" #include "SharedBuffer.h" #include "Text.h" -#include <wtf/text/CString.h> -#include <wtf/text/WTFString.h> #include <wtf/CurrentTime.h> +#include <wtf/GregorianDateTime.h> #include <wtf/StdLibExtras.h> +#include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> #include <wtf/unicode/CharacterNames.h> using namespace std; @@ -219,26 +220,23 @@ static String processFileDateString(const FTPTime& fileTime) } // If it was today or yesterday, lets just do that - but we have to compare to the current time - struct tm now; - getCurrentLocalTime(&now); - - // localtime does "year = current year - 1900", compensate for that for readability and comparison purposes - now.tm_year += 1900; + GregorianDateTime now; + now.setToCurrentLocalTime(); - if (fileTime.tm_year == now.tm_year) { - if (fileTime.tm_mon == now.tm_mon) { - if (fileTime.tm_mday == now.tm_mday) + if (fileTime.tm_year == now.year()) { + if (fileTime.tm_mon == now.month()) { + if (fileTime.tm_mday == now.monthDay()) return "Today" + timeOfDay; - if (fileTime.tm_mday == now.tm_mday - 1) + if (fileTime.tm_mday == now.monthDay() - 1) return "Yesterday" + timeOfDay; } - if (now.tm_mday == 1 && (now.tm_mon == fileTime.tm_mon + 1 || (now.tm_mon == 0 && fileTime.tm_mon == 11)) && + if (now.monthDay() == 1 && (now.month() == fileTime.tm_mon + 1 || (now.month() == 0 && fileTime.tm_mon == 11)) && wasLastDayOfMonth(fileTime.tm_year, fileTime.tm_mon, fileTime.tm_mday)) return "Yesterday" + timeOfDay; } - if (fileTime.tm_year == now.tm_year - 1 && fileTime.tm_mon == 12 && fileTime.tm_mday == 31 && now.tm_mon == 1 && now.tm_mday == 1) + if (fileTime.tm_year == now.year() - 1 && fileTime.tm_mon == 12 && fileTime.tm_mday == 31 && now.month() == 1 && now.monthDay() == 1) return "Yesterday" + timeOfDay; static const char* months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???" }; @@ -252,7 +250,7 @@ static String processFileDateString(const FTPTime& fileTime) if (fileTime.tm_year > -1) dateString = String(months[month]) + " " + String::number(fileTime.tm_mday) + ", " + String::number(fileTime.tm_year); else - dateString = String(months[month]) + " " + String::number(fileTime.tm_mday) + ", " + String::number(now.tm_year); + dateString = String(months[month]) + " " + String::number(fileTime.tm_mday) + ", " + String::number(now.year()); return dateString + timeOfDay; } @@ -368,7 +366,7 @@ void FTPDirectoryDocumentParser::append(const SegmentedString& source) m_dest = m_buffer; SegmentedString str = source; while (!str.isEmpty()) { - UChar c = *str; + UChar c = str.currentChar(); if (c == '\r') { *m_dest++ = '\n'; diff --git a/Source/WebCore/html/HTMLAnchorElement.cpp b/Source/WebCore/html/HTMLAnchorElement.cpp index d31188f12..9f50c7feb 100644 --- a/Source/WebCore/html/HTMLAnchorElement.cpp +++ b/Source/WebCore/html/HTMLAnchorElement.cpp @@ -569,24 +569,14 @@ bool isEnterKeyKeydownEvent(Event* event) return event->type() == eventNames().keydownEvent && event->isKeyboardEvent() && static_cast<KeyboardEvent*>(event)->keyIdentifier() == "Enter"; } -bool isMiddleMouseButtonEvent(Event* event) -{ - return event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == MiddleButton; -} - bool isLinkClick(Event* event) { return event->type() == eventNames().clickEvent && (!event->isMouseEvent() || static_cast<MouseEvent*>(event)->button() != RightButton); } -void handleLinkClick(Event* event, Document* document, const String& url, const String& target, bool hideReferrer) +bool HTMLAnchorElement::willRespondToMouseClickEvents() { - event->setDefaultHandled(); - - Frame* frame = document->frame(); - if (!frame) - return; - frame->loader()->urlSelected(document->completeURL(url), target, event, false, false, hideReferrer ? NeverSendReferrer : MaybeSendReferrer); + return isLink() || HTMLElement::willRespondToMouseClickEvents(); } #if ENABLE(MICRODATA) diff --git a/Source/WebCore/html/HTMLAnchorElement.h b/Source/WebCore/html/HTMLAnchorElement.h index 9a875c25b..6afe5a5c5 100644 --- a/Source/WebCore/html/HTMLAnchorElement.h +++ b/Source/WebCore/html/HTMLAnchorElement.h @@ -94,6 +94,8 @@ public: bool isLiveLink() const; + virtual bool willRespondToMouseClickEvents() OVERRIDE; + bool hasRel(uint32_t relation) const; void setRel(const String&); @@ -155,9 +157,7 @@ inline LinkHash HTMLAnchorElement::visitedLinkHash() const // Functions shared with the other anchor elements (i.e., SVG). bool isEnterKeyKeydownEvent(Event*); -bool isMiddleMouseButtonEvent(Event*); bool isLinkClick(Event*); -void handleLinkClick(Event*, Document*, const String& url, const String& target, bool hideReferrer = false); } // namespace WebCore diff --git a/Source/WebCore/html/HTMLAppletElement.cpp b/Source/WebCore/html/HTMLAppletElement.cpp index 5bd5fd5aa..afc7268dd 100644 --- a/Source/WebCore/html/HTMLAppletElement.cpp +++ b/Source/WebCore/html/HTMLAppletElement.cpp @@ -81,7 +81,7 @@ RenderObject* HTMLAppletElement::createRenderer(RenderArena*, RenderStyle* style return new (document()->renderArena()) RenderApplet(this); } -RenderWidget* HTMLAppletElement::renderWidgetForJSBindings() +RenderWidget* HTMLAppletElement::renderWidgetForJSBindings() const { if (!canEmbedJava()) return 0; diff --git a/Source/WebCore/html/HTMLAppletElement.h b/Source/WebCore/html/HTMLAppletElement.h index ee4e30cf0..4c7275c72 100644 --- a/Source/WebCore/html/HTMLAppletElement.h +++ b/Source/WebCore/html/HTMLAppletElement.h @@ -39,7 +39,7 @@ private: virtual bool rendererIsNeeded(const NodeRenderingContext&) OVERRIDE; virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) OVERRIDE; - virtual RenderWidget* renderWidgetForJSBindings(); + virtual RenderWidget* renderWidgetForJSBindings() const; virtual void updateWidget(PluginCreationOption) OVERRIDE; bool canEmbedJava() const; diff --git a/Source/WebCore/html/HTMLButtonElement.cpp b/Source/WebCore/html/HTMLButtonElement.cpp index d82a1a737..ecb4a21ba 100644 --- a/Source/WebCore/html/HTMLButtonElement.cpp +++ b/Source/WebCore/html/HTMLButtonElement.cpp @@ -153,6 +153,13 @@ void HTMLButtonElement::defaultEventHandler(Event* event) HTMLFormControlElement::defaultEventHandler(event); } +bool HTMLButtonElement::willRespondToMouseClickEvents() +{ + if (!disabled() && form() && (m_type == SUBMIT || m_type == RESET)) + return true; + return HTMLFormControlElement::willRespondToMouseClickEvents(); +} + bool HTMLButtonElement::isSuccessfulSubmitButton() const { // HTML spec says that buttons must have names to be considered successful. diff --git a/Source/WebCore/html/HTMLButtonElement.h b/Source/WebCore/html/HTMLButtonElement.h index 7bf99b7b8..92ca0a3f6 100644 --- a/Source/WebCore/html/HTMLButtonElement.h +++ b/Source/WebCore/html/HTMLButtonElement.h @@ -36,6 +36,8 @@ public: String value() const; + virtual bool willRespondToMouseClickEvents() OVERRIDE; + private: HTMLButtonElement(const QualifiedName& tagName, Document*, HTMLFormElement*); @@ -48,6 +50,7 @@ private: virtual void parseAttribute(const Attribute&) OVERRIDE; virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE; virtual void defaultEventHandler(Event*); + virtual bool appendFormData(FormDataList&, bool); virtual bool isEnumeratable() const { return true; } diff --git a/Source/WebCore/html/HTMLElement.cpp b/Source/WebCore/html/HTMLElement.cpp index d873d9b7f..b707ef234 100644 --- a/Source/WebCore/html/HTMLElement.cpp +++ b/Source/WebCore/html/HTMLElement.cpp @@ -1010,16 +1010,24 @@ void HTMLElement::getItemRefElements(Vector<HTMLElement*>& itemRefElements) if (!fastHasAttribute(itemscopeAttr)) return; - if (!fastHasAttribute(itemrefAttr)) { + if (!fastHasAttribute(itemrefAttr) || !itemRef()->length()) { itemRefElements.append(this); return; } DOMSettableTokenList* itemRefs = itemRef(); RefPtr<DOMSettableTokenList> processedItemRef = DOMSettableTokenList::create(); - Node* rootNode = treeScope()->rootNode(); - for (Node* current = rootNode->firstChild(); current; current = current->traverseNextNode(rootNode)) { + Node* rootNode; + if (inDocument()) + rootNode = document(); + else { + rootNode = this; + while (Node* parent = rootNode->parentNode()) + rootNode = parent; + } + + for (Node* current = rootNode; current; current = current->traverseNextNode(rootNode)) { if (!current->isHTMLElement()) continue; HTMLElement* element = toHTMLElement(current); diff --git a/Source/WebCore/html/HTMLElement.idl b/Source/WebCore/html/HTMLElement.idl index 4f5f236f6..9501d3a6a 100644 --- a/Source/WebCore/html/HTMLElement.idl +++ b/Source/WebCore/html/HTMLElement.idl @@ -32,8 +32,6 @@ module html { attribute [Reflect] DOMString lang; attribute boolean translate; attribute [Reflect] DOMString dir; - attribute [Reflect=class] DOMString className; - readonly attribute DOMTokenList classList; attribute long tabIndex; attribute boolean draggable; diff --git a/Source/WebCore/html/HTMLEmbedElement.cpp b/Source/WebCore/html/HTMLEmbedElement.cpp index 15e32eef7..3bc2d933d 100644 --- a/Source/WebCore/html/HTMLEmbedElement.cpp +++ b/Source/WebCore/html/HTMLEmbedElement.cpp @@ -68,7 +68,7 @@ static inline RenderWidget* findWidgetRenderer(const Node* n) return 0; } -RenderWidget* HTMLEmbedElement::renderWidgetForJSBindings() +RenderWidget* HTMLEmbedElement::renderWidgetForJSBindings() const { document()->updateLayoutIgnorePendingStylesheets(); return findWidgetRenderer(this); diff --git a/Source/WebCore/html/HTMLEmbedElement.h b/Source/WebCore/html/HTMLEmbedElement.h index ba828a172..bda2e9149 100644 --- a/Source/WebCore/html/HTMLEmbedElement.h +++ b/Source/WebCore/html/HTMLEmbedElement.h @@ -43,7 +43,7 @@ private: virtual bool isURLAttribute(const Attribute&) const OVERRIDE; virtual const QualifiedName& imageSourceAttributeName() const; - virtual RenderWidget* renderWidgetForJSBindings(); + virtual RenderWidget* renderWidgetForJSBindings() const; virtual void updateWidget(PluginCreationOption); diff --git a/Source/WebCore/html/HTMLFormControlElement.cpp b/Source/WebCore/html/HTMLFormControlElement.cpp index d52d0ba85..2d47ac8c4 100644 --- a/Source/WebCore/html/HTMLFormControlElement.cpp +++ b/Source/WebCore/html/HTMLFormControlElement.cpp @@ -482,6 +482,16 @@ void HTMLFormControlElement::setCustomValidity(const String& error) setNeedsValidityCheck(); } +bool HTMLFormControlElement::shouldMatchReadOnlySelector() const +{ + return readOnly(); +} + +bool HTMLFormControlElement::shouldMatchReadWriteSelector() const +{ + return !readOnly(); +} + bool HTMLFormControlElement::validationMessageShadowTreeContains(Node* node) const { return m_validationMessage && m_validationMessage->shadowTreeContains(node); diff --git a/Source/WebCore/html/HTMLFormControlElement.h b/Source/WebCore/html/HTMLFormControlElement.h index b132cbe0b..d129bc2c2 100644 --- a/Source/WebCore/html/HTMLFormControlElement.h +++ b/Source/WebCore/html/HTMLFormControlElement.h @@ -81,7 +81,8 @@ public: virtual const AtomicString& formControlType() const OVERRIDE = 0; virtual bool isEnabledFormControl() const { return !disabled(); } - virtual bool isReadOnlyFormControl() const { return readOnly(); } + virtual bool shouldMatchReadOnlySelector() const OVERRIDE; + virtual bool shouldMatchReadWriteSelector() const OVERRIDE; virtual bool canTriggerImplicitSubmission() const { return false; } diff --git a/Source/WebCore/html/HTMLInputElement.cpp b/Source/WebCore/html/HTMLInputElement.cpp index 59c6205a8..e07067c66 100644 --- a/Source/WebCore/html/HTMLInputElement.cpp +++ b/Source/WebCore/html/HTMLInputElement.cpp @@ -313,6 +313,13 @@ StepRange HTMLInputElement::createStepRange(AnyStepHandling anyStepHandling) con return m_inputType->createStepRange(anyStepHandling); } +#if ENABLE(DATALIST_ELEMENT) +Decimal HTMLInputElement::findClosestTickMarkValue(const Decimal& value) +{ + return m_inputType->findClosestTickMarkValue(value); +} +#endif + void HTMLInputElement::stepUp(int n, ExceptionCode& ec) { m_inputType->stepUp(n, ec); @@ -619,6 +626,12 @@ void HTMLInputElement::parseAttribute(const Attribute& attribute) } else if (attribute.name() == typeAttr) { updateType(); } else if (attribute.name() == valueAttr) { + // Changes to the value attribute may change whether or not this element has a default value. + // If this field is autocomplete=off that might affect the return value of needsSuspensionCallback. + if (m_autocomplete == Off) { + unregisterForSuspensionCallbackIfNeeded(); + registerForSuspensionCallbackIfNeeded(); + } // We only need to setChanged if the form is looking at the default value right now. if (!hasDirtyValue()) { updatePlaceholderVisibility(false); @@ -1160,6 +1173,15 @@ void HTMLInputElement::defaultEventHandler(Event* evt) HTMLTextFormControlElement::defaultEventHandler(evt); } +bool HTMLInputElement::willRespondToMouseClickEvents() +{ + // FIXME: Consider implementing willRespondToMouseClickEvents() in InputType if more accurate results are necessary. + if (!disabled()) + return true; + + return HTMLTextFormControlElement::willRespondToMouseClickEvents(); +} + bool HTMLInputElement::isURLAttribute(const Attribute& attribute) const { return attribute.name() == srcAttr || attribute.name() == formactionAttr || HTMLTextFormControlElement::isURLAttribute(attribute); @@ -1363,7 +1385,17 @@ bool HTMLInputElement::isOutOfRange() const bool HTMLInputElement::needsSuspensionCallback() { - return m_autocomplete == Off || m_inputType->shouldResetOnDocumentActivation(); + if (m_inputType->shouldResetOnDocumentActivation()) + return true; + + // Sensitive input elements are marked with autocomplete=off, and we want to wipe them out + // when going back; returning true here arranges for us to call reset at the time + // the page is restored. Non-empty textual default values indicate that the field + // is not really sensitive -- there's no default value for an account number -- + // and we would see unexpected results if we reset to something other than blank. + bool isSensitive = m_autocomplete == Off && !(m_inputType->isTextType() && !defaultValue().isEmpty()); + + return isSensitive; } void HTMLInputElement::registerForSuspensionCallbackIfNeeded() diff --git a/Source/WebCore/html/HTMLInputElement.h b/Source/WebCore/html/HTMLInputElement.h index fa4aa9153..dc32159f2 100644 --- a/Source/WebCore/html/HTMLInputElement.h +++ b/Source/WebCore/html/HTMLInputElement.h @@ -72,6 +72,10 @@ public: bool getAllowedValueStep(Decimal*) const; StepRange createStepRange(AnyStepHandling) const; +#if ENABLE(DATALIST_ELEMENT) + Decimal findClosestTickMarkValue(const Decimal&); +#endif + // Implementations of HTMLInputElement::stepUp() and stepDown(). void stepUp(int, ExceptionCode&); void stepDown(int, ExceptionCode&); @@ -232,6 +236,8 @@ public: void addSearchResult(); void onSearch(); + virtual bool willRespondToMouseClickEvents() OVERRIDE; + #if ENABLE(DATALIST_ELEMENT) HTMLElement* list() const; HTMLDataListElement* dataList() const; @@ -400,5 +406,11 @@ private: #endif }; +inline bool isHTMLInputElement(Node* node) +{ + ASSERT(node); + return node->hasTagName(HTMLNames::inputTag); +} + } //namespace #endif diff --git a/Source/WebCore/html/HTMLLabelElement.cpp b/Source/WebCore/html/HTMLLabelElement.cpp index c1021b358..242fb0cbd 100644 --- a/Source/WebCore/html/HTMLLabelElement.cpp +++ b/Source/WebCore/html/HTMLLabelElement.cpp @@ -147,6 +147,14 @@ void HTMLLabelElement::defaultEventHandler(Event* evt) HTMLElement::defaultEventHandler(evt); } +bool HTMLLabelElement::willRespondToMouseClickEvents() +{ + if (control() && control()->willRespondToMouseClickEvents()) + return true; + + return HTMLElement::willRespondToMouseClickEvents(); +} + void HTMLLabelElement::focus(bool) { // to match other browsers, always restore previous selection diff --git a/Source/WebCore/html/HTMLLabelElement.h b/Source/WebCore/html/HTMLLabelElement.h index a821b2507..f48c6805e 100644 --- a/Source/WebCore/html/HTMLLabelElement.h +++ b/Source/WebCore/html/HTMLLabelElement.h @@ -36,6 +36,8 @@ public: LabelableElement* control(); HTMLFormElement* form() const; + virtual bool willRespondToMouseClickEvents() OVERRIDE; + private: HTMLLabelElement(const QualifiedName&, Document*); diff --git a/Source/WebCore/html/HTMLMediaElement.cpp b/Source/WebCore/html/HTMLMediaElement.cpp index cc025c12b..fadcfe7c6 100644 --- a/Source/WebCore/html/HTMLMediaElement.cpp +++ b/Source/WebCore/html/HTMLMediaElement.cpp @@ -111,6 +111,11 @@ #include "DisplaySleepDisabler.h" #endif +#if ENABLE(MEDIA_SOURCE) +#include "MediaSource.h" +#include "MediaSourceRegistry.h" +#endif + using namespace std; namespace WebCore { @@ -145,7 +150,7 @@ static const char* boolString(bool val) #if ENABLE(MEDIA_SOURCE) // URL protocol used to signal that the media source API is being used. -static const char* mediaSourceURLProtocol = "x-media-source"; +static const char* mediaSourceBlobProtocol = "blob"; #endif using namespace HTMLNames; @@ -219,9 +224,6 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* docum , m_preload(MediaPlayer::Auto) , m_displayMode(Unknown) , m_processingMediaPlayerCallback(0) -#if ENABLE(MEDIA_SOURCE) - , m_sourceState(SOURCE_CLOSED) -#endif , m_cachedTime(MediaPlayer::invalidTime()) , m_cachedTimeWallClockUpdateTime(0) , m_minimumWallClockTimeToCacheMediaTime(0) @@ -272,7 +274,7 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* docum } #if ENABLE(MEDIA_SOURCE) - m_mediaSourceURL.setProtocol(mediaSourceURLProtocol); + m_mediaSourceURL.setProtocol(mediaSourceBlobProtocol); m_mediaSourceURL.setPath(createCanonicalUUIDString()); #endif @@ -421,14 +423,6 @@ void HTMLMediaElement::parseAttribute(const Attribute& attribute) setAttributeEventListener(eventNames().webkitbeginfullscreenEvent, createAttributeEventListener(this, attribute)); else if (attribute.name() == onwebkitendfullscreenAttr) setAttributeEventListener(eventNames().webkitendfullscreenEvent, createAttributeEventListener(this, attribute)); -#if ENABLE(MEDIA_SOURCE) - else if (attribute.name() == onwebkitsourcecloseAttr) - setAttributeEventListener(eventNames().webkitsourcecloseEvent, createAttributeEventListener(this, attribute)); - else if (attribute.name() == onwebkitsourceendedAttr) - setAttributeEventListener(eventNames().webkitsourceendedEvent, createAttributeEventListener(this, attribute)); - else if (attribute.name() == onwebkitsourceopenAttr) - setAttributeEventListener(eventNames().webkitsourceopenEvent, createAttributeEventListener(this, attribute)); -#endif else HTMLElement::parseAttribute(attribute); } @@ -693,6 +687,10 @@ void HTMLMediaElement::prepareForLoad() if (m_networkState == NETWORK_LOADING || m_networkState == NETWORK_IDLE) scheduleEvent(eventNames().abortEvent); +#if ENABLE(MEDIA_SOURCE) + setSourceState(MediaSource::closedKeyword()); +#endif + #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO) createMediaPlayer(); #else @@ -702,11 +700,6 @@ void HTMLMediaElement::prepareForLoad() createMediaPlayerProxy(); #endif -#if ENABLE(MEDIA_SOURCE) - if (m_sourceState != SOURCE_CLOSED) - setSourceState(SOURCE_CLOSED); -#endif - // 4 - If the media element's networkState is not set to NETWORK_EMPTY, then run these substeps if (m_networkState != NETWORK_EMPTY) { m_networkState = NETWORK_EMPTY; @@ -927,10 +920,16 @@ void HTMLMediaElement::loadResource(const KURL& initialURL, ContentType& content } #if ENABLE(MEDIA_SOURCE) - // If this is a media source URL, make sure it is the one for this media element. - if (url.protocolIs(mediaSourceURLProtocol) && url != m_mediaSourceURL) { - mediaLoadingFailed(MediaPlayer::FormatError); - return; + if (url.protocolIs(mediaSourceBlobProtocol)) { + if (m_mediaSource) + m_mediaSource->setReadyState(MediaSource::closedKeyword()); + + m_mediaSource = MediaSourceRegistry::registry().lookupMediaSource(url.string()); + + if (m_mediaSource) { + m_mediaSource->setMediaPlayer(m_player.get()); + m_mediaSourceURL = url; + } } #endif @@ -1432,8 +1431,7 @@ void HTMLMediaElement::noneSupported() scheduleEvent(eventNames().errorEvent); #if ENABLE(MEDIA_SOURCE) - if (m_sourceState != SOURCE_CLOSED) - setSourceState(SOURCE_CLOSED); + setSourceState(MediaSource::closedKeyword()); #endif // 8 - Set the element's delaying-the-load-event flag to false. This stops delaying the load event. @@ -1464,8 +1462,7 @@ void HTMLMediaElement::mediaEngineError(PassRefPtr<MediaError> err) scheduleEvent(eventNames().errorEvent); #if ENABLE(MEDIA_SOURCE) - if (m_sourceState != SOURCE_CLOSED) - setSourceState(SOURCE_CLOSED); + setSourceState(MediaSource::closedKeyword()); #endif // 4 - Set the element's networkState attribute to the NETWORK_EMPTY value and queue a @@ -1581,7 +1578,6 @@ void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state) if (state == MediaPlayer::Idle) { if (m_networkState > NETWORK_IDLE) { changeNetworkStateFromLoadingToIdle(); - scheduleEvent(eventNames().suspendEvent); setShouldDelayLoadEvent(false); } else { m_networkState = NETWORK_IDLE; @@ -1613,6 +1609,7 @@ void HTMLMediaElement::changeNetworkStateFromLoadingToIdle() // Schedule one last progress event so we guarantee that at least one is fired // for files that load very quickly. scheduleEvent(eventNames().progressEvent); + scheduleEvent(eventNames().suspendEvent); m_networkState = NETWORK_IDLE; } @@ -1750,7 +1747,7 @@ void HTMLMediaElement::mediaPlayerSourceOpened() { beginProcessingMediaPlayerCallback(); - setSourceState(SOURCE_OPEN); + setSourceState(MediaSource::openKeyword()); endProcessingMediaPlayerCallback(); } @@ -1759,22 +1756,6 @@ String HTMLMediaElement::mediaPlayerSourceURL() const { return m_mediaSourceURL.string(); } - -bool HTMLMediaElement::isValidSourceId(const String& id, ExceptionCode& ec) const -{ - if (id.isNull() || id.isEmpty()) { - ec = INVALID_ACCESS_ERR; - return false; - } - - if (!m_sourceIDs.contains(id)) { - ec = SYNTAX_ERR; - return false; - } - - return true; -} - #endif #if ENABLE(ENCRYPTED_MEDIA) @@ -1998,8 +1979,8 @@ void HTMLMediaElement::seek(float time, ExceptionCode& ec) #if ENABLE(MEDIA_SOURCE) // Always notify the media engine of a seek if the source is not closed. This ensures that the source is // always in a flushed state when the 'seeking' event fires. - if (m_sourceState != SOURCE_CLOSED) - noSeekRequired = false; + if (m_mediaSource && m_mediaSource->readyState() != MediaSource::closedKeyword()) + noSeekRequired = false; #endif if (noSeekRequired) { @@ -2021,8 +2002,8 @@ void HTMLMediaElement::seek(float time, ExceptionCode& ec) m_sentEndEvent = false; #if ENABLE(MEDIA_SOURCE) - if (m_sourceState == SOURCE_ENDED) - setSourceState(SOURCE_OPEN); + if (m_mediaSource && m_mediaSource->readyState() == MediaSource::endedKeyword()) + setSourceState(MediaSource::openKeyword()); #endif // 8 - Set the current playback position to the given new playback position @@ -2370,175 +2351,12 @@ void HTMLMediaElement::pauseInternal() } #if ENABLE(MEDIA_SOURCE) - -void HTMLMediaElement::webkitSourceAddId(const String& id, const String& type, ExceptionCode& ec) -{ - if (id.isNull() || id.isEmpty()) { - ec = INVALID_ACCESS_ERR; - return; - } - - if (m_sourceIDs.contains(id)) { - ec = INVALID_STATE_ERR; - return; - } - - if (type.isNull() || type.isEmpty()) { - ec = INVALID_ACCESS_ERR; - return; - } - - if (!m_player || m_currentSrc != m_mediaSourceURL || m_sourceState != SOURCE_OPEN) { - ec = INVALID_STATE_ERR; - return; - } - - ContentType contentType(type); - Vector<String> codecs = contentType.codecs(); - - if (!codecs.size()) { - ec = NOT_SUPPORTED_ERR; - return; - } - - switch (m_player->sourceAddId(id, contentType.type(), codecs)) { - case MediaPlayer::Ok: - m_sourceIDs.add(id); - return; - case MediaPlayer::NotSupported: - ec = NOT_SUPPORTED_ERR; - return; - case MediaPlayer::ReachedIdLimit: - ec = QUOTA_EXCEEDED_ERR; - return; - } - - ASSERT_NOT_REACHED(); -} - -void HTMLMediaElement::webkitSourceRemoveId(const String& id, ExceptionCode& ec) -{ - if (!isValidSourceId(id, ec)) - return; - - if (!m_player || m_currentSrc != m_mediaSourceURL || m_sourceState == SOURCE_CLOSED) { - ec = INVALID_STATE_ERR; - return; - } - - if (!m_player->sourceRemoveId(id)) - ASSERT_NOT_REACHED(); - - m_sourceIDs.remove(id); -} - -PassRefPtr<TimeRanges> HTMLMediaElement::webkitSourceBuffered(const String& id, ExceptionCode& ec) -{ - if (!isValidSourceId(id, ec)) - return 0; - - if (!m_player || m_currentSrc != m_mediaSourceURL || m_sourceState == SOURCE_CLOSED) { - ec = INVALID_STATE_ERR; - return 0; - } - - return m_player->sourceBuffered(id); -} - -void HTMLMediaElement::webkitSourceAppend(const String& id, PassRefPtr<Uint8Array> data, ExceptionCode& ec) -{ - if (!isValidSourceId(id, ec)) - return; - - if (!m_player || m_currentSrc != m_mediaSourceURL || m_sourceState != SOURCE_OPEN) { - ec = INVALID_STATE_ERR; - return; - } - - if (!data.get()) { - ec = INVALID_ACCESS_ERR; - return; - } - - if (!data->length()) - return; - - if (!m_player->sourceAppend(id, data->data(), data->length())) { - ec = SYNTAX_ERR; - return; - } -} - -void HTMLMediaElement::webkitSourceAbort(const String& id, ExceptionCode& ec) -{ - if (!isValidSourceId(id, ec)) - return; - - if (!m_player || m_currentSrc != m_mediaSourceURL || m_sourceState != SOURCE_OPEN) { - ec = INVALID_STATE_ERR; - return; - } - - if (!m_player->sourceAbort(id)) - ASSERT_NOT_REACHED(); -} - -void HTMLMediaElement::webkitSourceEndOfStream(unsigned short status, ExceptionCode& ec) -{ - if (!m_player || m_currentSrc != m_mediaSourceURL || m_sourceState != SOURCE_OPEN) { - ec = INVALID_STATE_ERR; - return; - } - - MediaPlayer::EndOfStreamStatus eosStatus = MediaPlayer::EosNoError; - - switch (status) { - case EOS_NO_ERROR: - eosStatus = MediaPlayer::EosNoError; - break; - case EOS_NETWORK_ERR: - eosStatus = MediaPlayer::EosNetworkError; - break; - case EOS_DECODE_ERR: - eosStatus = MediaPlayer::EosDecodeError; - break; - default: - ec = SYNTAX_ERR; - return; - } - - setSourceState(SOURCE_ENDED); - m_player->sourceEndOfStream(eosStatus); -} - -HTMLMediaElement::SourceState HTMLMediaElement::webkitSourceState() const +void HTMLMediaElement::setSourceState(const String& state) { - return m_sourceState; -} + if (!m_mediaSource) + return; -void HTMLMediaElement::setSourceState(SourceState state) -{ - SourceState oldState = m_sourceState; - m_sourceState = static_cast<SourceState>(state); - - if (m_sourceState == oldState) - return; - - if (m_sourceState == SOURCE_CLOSED) { - m_sourceIDs.clear(); - scheduleEvent(eventNames().webkitsourcecloseEvent); - return; - } - - if (oldState == SOURCE_OPEN && m_sourceState == SOURCE_ENDED) { - scheduleEvent(eventNames().webkitsourceendedEvent); - return; - } - - if (m_sourceState == SOURCE_OPEN) { - scheduleEvent(eventNames().webkitsourceopenEvent); - return; - } + m_mediaSource->setReadyState(state); } #endif @@ -3351,7 +3169,7 @@ void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*) invalidateCachedTime(); // 4.8.10.9 step 14 & 15. Needed if no ReadyState change is associated with the seek. - if (m_seeking && m_readyState >= HAVE_CURRENT_DATA) + if (m_seeking && m_readyState >= HAVE_CURRENT_DATA && !m_player->seeking()) finishSeek(); // Always call scheduleTimeupdateEvent when the media engine reports a time discontinuity, @@ -3793,8 +3611,7 @@ void HTMLMediaElement::userCancelledLoad() scheduleEvent(eventNames().abortEvent); #if ENABLE(MEDIA_SOURCE) - if (m_sourceState != SOURCE_CLOSED) - setSourceState(SOURCE_CLOSED); + setSourceState(MediaSource::closedKeyword()); #endif // 4 - If the media element's readyState attribute has a value equal to HAVE_NOTHING, set the @@ -3910,6 +3727,15 @@ void HTMLMediaElement::defaultEventHandler(Event* event) #endif } +bool HTMLMediaElement::willRespondToMouseClickEvents() +{ +#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) + return true; +#else + return HTMLElement::willRespondToMouseClickEvents(); +#endif +} + #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) void HTMLMediaElement::ensureMediaPlayer() @@ -4298,6 +4124,11 @@ void HTMLMediaElement::createMediaPlayer() m_player = MediaPlayer::create(this); +#if ENABLE(MEDIA_SOURCE) + if (m_mediaSource) + m_mediaSource->setMediaPlayer(m_player.get()); +#endif + #if ENABLE(WEB_AUDIO) if (m_audioSourceNode) { // When creating the player, make sure its AudioSourceProvider knows about the MediaElementAudioSourceNode. diff --git a/Source/WebCore/html/HTMLMediaElement.h b/Source/WebCore/html/HTMLMediaElement.h index 335bfbd36..bdc614989 100644 --- a/Source/WebCore/html/HTMLMediaElement.h +++ b/Source/WebCore/html/HTMLMediaElement.h @@ -175,20 +175,7 @@ public: #if ENABLE(MEDIA_SOURCE) // Media Source. const KURL& webkitMediaSourceURL() const { return m_mediaSourceURL; } - void webkitSourceAddId(const String&, const String&, ExceptionCode&); - void webkitSourceRemoveId(const String&, ExceptionCode&); - PassRefPtr<TimeRanges> webkitSourceBuffered(const String&, ExceptionCode&); - void webkitSourceAppend(const String&, PassRefPtr<Uint8Array> data, ExceptionCode&); - void webkitSourceAbort(const String&, ExceptionCode&); - enum EndOfStreamStatus { EOS_NO_ERROR, EOS_NETWORK_ERR, EOS_DECODE_ERR }; - void webkitSourceEndOfStream(unsigned short, ExceptionCode&); - enum SourceState { SOURCE_CLOSED, SOURCE_OPEN, SOURCE_ENDED }; - SourceState webkitSourceState() const; - void setSourceState(SourceState); - - DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitsourceopen); - DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitsourceended); - DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitsourceclose); + void setSourceState(const String&); #endif #if ENABLE(ENCRYPTED_MEDIA) @@ -328,6 +315,8 @@ public: virtual bool dispatchEvent(PassRefPtr<Event>); + virtual bool willRespondToMouseClickEvents() OVERRIDE; + protected: HTMLMediaElement(const QualifiedName&, Document*, bool); virtual ~HTMLMediaElement(); @@ -418,7 +407,6 @@ private: #if ENABLE(MEDIA_SOURCE) virtual void mediaPlayerSourceOpened(); virtual String mediaPlayerSourceURL() const; - bool isValidSourceId(const String&, ExceptionCode&) const; #endif #if ENABLE(ENCRYPTED_MEDIA) @@ -596,8 +584,7 @@ private: #if ENABLE(MEDIA_SOURCE) KURL m_mediaSourceURL; - SourceState m_sourceState; - HashSet<String> m_sourceIDs; + RefPtr<MediaSource> m_mediaSource; #endif mutable float m_cachedTime; diff --git a/Source/WebCore/html/HTMLMediaElement.idl b/Source/WebCore/html/HTMLMediaElement.idl index ac0fa467b..9d0ae8a77 100644 --- a/Source/WebCore/html/HTMLMediaElement.idl +++ b/Source/WebCore/html/HTMLMediaElement.idl @@ -98,35 +98,6 @@ module html { #if defined(ENABLE_MEDIA_SOURCE) && ENABLE_MEDIA_SOURCE // URL passed to src attribute to enable the media source logic. readonly attribute [V8EnabledAtRuntime=mediaSource, URL] DOMString webkitMediaSourceURL; - - // Manages IDs for appending media to the source. - [V8EnabledAtRuntime=mediaSource] void webkitSourceAddId(in DOMString id, in DOMString type) raises (DOMException); - [V8EnabledAtRuntime=mediaSource] void webkitSourceRemoveId(in DOMString id) raises (DOMException); - - // Returns the time ranges buffered for a specific source ID. - [V8EnabledAtRuntime=mediaSource] TimeRanges webkitSourceBuffered(in DOMString id) raises (DOMException); - - // Appends segment data. - [V8EnabledAtRuntime=mediaSource] void webkitSourceAppend(in DOMString id, in Uint8Array data) raises (DOMException); - - // Aborts the current segment. - [V8EnabledAtRuntime=mediaSource] void webkitSourceAbort(in DOMString id) raises (DOMException); - - // Signals the end of stream. - [V8EnabledAtRuntime=mediaSource] const unsigned short EOS_NO_ERROR = 0; // End of stream reached w/o error. - [V8EnabledAtRuntime=mediaSource] const unsigned short EOS_NETWORK_ERR = 1; // A network error triggered end of stream. - [V8EnabledAtRuntime=mediaSource] const unsigned short EOS_DECODE_ERR = 2; // A decode error triggered end of stream. - [V8EnabledAtRuntime=mediaSource] void webkitSourceEndOfStream(in unsigned short status) raises (DOMException); - - // Indicates the current state of the media source. - [V8EnabledAtRuntime=mediaSource] const unsigned short SOURCE_CLOSED = 0; - [V8EnabledAtRuntime=mediaSource] const unsigned short SOURCE_OPEN = 1; - [V8EnabledAtRuntime=mediaSource] const unsigned short SOURCE_ENDED = 2; - readonly attribute [V8EnabledAtRuntime=mediaSource] unsigned short webkitSourceState; - - attribute [V8EnabledAtRuntime=mediaSource] EventListener onwebkitsourceopen; - attribute [V8EnabledAtRuntime=mediaSource] EventListener onwebkitsourceended; - attribute [V8EnabledAtRuntime=mediaSource] EventListener onwebkitsourceclose; #endif #if defined(ENABLE_ENCRYPTED_MEDIA) && ENABLE_ENCRYPTED_MEDIA diff --git a/Source/WebCore/html/HTMLObjectElement.cpp b/Source/WebCore/html/HTMLObjectElement.cpp index 5715d2382..cf185a8d3 100644 --- a/Source/WebCore/html/HTMLObjectElement.cpp +++ b/Source/WebCore/html/HTMLObjectElement.cpp @@ -73,7 +73,7 @@ PassRefPtr<HTMLObjectElement> HTMLObjectElement::create(const QualifiedName& tag return adoptRef(new HTMLObjectElement(tagName, document, form, createdByParser)); } -RenderWidget* HTMLObjectElement::renderWidgetForJSBindings() +RenderWidget* HTMLObjectElement::renderWidgetForJSBindings() const { document()->updateLayoutIgnorePendingStylesheets(); return renderPart(); // This will return 0 if the renderer is not a RenderPart. diff --git a/Source/WebCore/html/HTMLObjectElement.h b/Source/WebCore/html/HTMLObjectElement.h index e12785d10..e3b49b4bd 100644 --- a/Source/WebCore/html/HTMLObjectElement.h +++ b/Source/WebCore/html/HTMLObjectElement.h @@ -82,7 +82,7 @@ private: virtual bool isURLAttribute(const Attribute&) const OVERRIDE; virtual const QualifiedName& imageSourceAttributeName() const; - virtual RenderWidget* renderWidgetForJSBindings(); + virtual RenderWidget* renderWidgetForJSBindings() const; virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const; diff --git a/Source/WebCore/html/HTMLOptionElement.cpp b/Source/WebCore/html/HTMLOptionElement.cpp index bb68a9d32..8fcc22c27 100644 --- a/Source/WebCore/html/HTMLOptionElement.cpp +++ b/Source/WebCore/html/HTMLOptionElement.cpp @@ -329,7 +329,14 @@ String HTMLOptionElement::textIndentedToRespectGroupLabel() const bool HTMLOptionElement::disabled() const { - return ownElementDisabled() || (parentNode() && parentNode()->isHTMLElement() && static_cast<HTMLElement*>(parentNode())->disabled()); + if (ownElementDisabled()) + return true; + + if (!parentNode() || !parentNode()->isHTMLElement()) + return false; + + HTMLElement* parentElement = static_cast<HTMLElement*>(parentNode()); + return parentElement->hasTagName(optgroupTag) && parentElement->disabled(); } Node::InsertionNotificationRequest HTMLOptionElement::insertedInto(ContainerNode* insertionPoint) diff --git a/Source/WebCore/html/HTMLPlugInElement.cpp b/Source/WebCore/html/HTMLPlugInElement.cpp index 5bdf60d44..1b5843483 100644 --- a/Source/WebCore/html/HTMLPlugInElement.cpp +++ b/Source/WebCore/html/HTMLPlugInElement.cpp @@ -33,10 +33,12 @@ #include "FrameTree.h" #include "HTMLNames.h" #include "Page.h" +#include "PluginViewBase.h" #include "RenderEmbeddedObject.h" #include "RenderWidget.h" #include "Settings.h" #include "Widget.h" +#include <wtf/UnusedParam.h> #if ENABLE(NETSCAPE_PLUGIN_API) #include "npruntime_impl.h" @@ -125,7 +127,7 @@ bool HTMLPlugInElement::guardedDispatchBeforeLoadEvent(const String& sourceURL) return beforeLoadAllowedLoad; } -Widget* HTMLPlugInElement::pluginWidget() +Widget* HTMLPlugInElement::pluginWidget() const { if (m_inBeforeLoadEventHandler) { // The plug-in hasn't loaded yet, and it makes no sense to try to load if beforeload handler happened to touch the plug-in element. @@ -190,6 +192,24 @@ void HTMLPlugInElement::defaultEventHandler(Event* event) HTMLFrameOwnerElement::defaultEventHandler(event); } +bool HTMLPlugInElement::isKeyboardFocusable(KeyboardEvent* event) const +{ + UNUSED_PARAM(event); + if (!document()->page()) + return false; + + const PluginViewBase* plugin = pluginWidget() && pluginWidget()->isPluginViewBase() ? static_cast<const PluginViewBase*>(pluginWidget()) : 0; + if (plugin) + return plugin->supportsKeyboardFocus(); + + return false; +} + +bool HTMLPlugInElement::isPluginElement() const +{ + return true; +} + #if ENABLE(NETSCAPE_PLUGIN_API) NPObject* HTMLPlugInElement::getNPObject() diff --git a/Source/WebCore/html/HTMLPlugInElement.h b/Source/WebCore/html/HTMLPlugInElement.h index 067e9aef9..94887748d 100644 --- a/Source/WebCore/html/HTMLPlugInElement.h +++ b/Source/WebCore/html/HTMLPlugInElement.h @@ -45,7 +45,7 @@ public: PassScriptInstance getInstance(); - Widget* pluginWidget(); + Widget* pluginWidget() const; #if ENABLE(NETSCAPE_PLUGIN_API) NPObject* getNPObject(); @@ -72,7 +72,10 @@ private: virtual void defaultEventHandler(Event*); - virtual RenderWidget* renderWidgetForJSBindings() = 0; + virtual RenderWidget* renderWidgetForJSBindings() const = 0; + + virtual bool isKeyboardFocusable(KeyboardEvent*) const; + virtual bool isPluginElement() const; private: mutable ScriptInstance m_instance; diff --git a/Source/WebCore/html/HTMLProgressElement.cpp b/Source/WebCore/html/HTMLProgressElement.cpp index 742b09ffa..48b5b886e 100644 --- a/Source/WebCore/html/HTMLProgressElement.cpp +++ b/Source/WebCore/html/HTMLProgressElement.cpp @@ -43,6 +43,7 @@ const double HTMLProgressElement::InvalidPosition = -2; HTMLProgressElement::HTMLProgressElement(const QualifiedName& tagName, Document* document) : LabelableElement(tagName, document) + , m_hasAuthorShadowRoot(false) { ASSERT(hasTagName(progressTag)); } @@ -58,8 +59,11 @@ PassRefPtr<HTMLProgressElement> HTMLProgressElement::create(const QualifiedName& return progress; } -RenderObject* HTMLProgressElement::createRenderer(RenderArena* arena, RenderStyle*) +RenderObject* HTMLProgressElement::createRenderer(RenderArena* arena, RenderStyle* style) { + if (!style->hasAppearance() || hasAuthorShadowRoot()) + return RenderObject::createObject(this, style); + return new (arena) RenderProgress(this); } @@ -68,6 +72,21 @@ bool HTMLProgressElement::childShouldCreateRenderer(const NodeRenderingContext& return childContext.isOnUpperEncapsulationBoundary() && HTMLElement::childShouldCreateRenderer(childContext); } +RenderProgress* HTMLProgressElement::renderProgress() const +{ + if (renderer() && renderer()->isProgress()) + return static_cast<RenderProgress*>(renderer()); + + RenderObject* renderObject = userAgentShadowRoot()->firstChild()->renderer(); + ASSERT(!renderObject || renderObject->isProgress()); + return static_cast<RenderProgress*>(renderObject); +} + +void HTMLProgressElement::willAddAuthorShadowRoot() +{ + m_hasAuthorShadowRoot = true; +} + bool HTMLProgressElement::supportsFocus() const { return Node::supportsFocus() && !disabled(); @@ -134,10 +153,9 @@ bool HTMLProgressElement::isDeterminate() const void HTMLProgressElement::didElementStateChange() { m_value->setWidthPercentage(position() * 100); - if (renderer() && renderer()->isProgress()) { - RenderProgress* render = toRenderProgress(renderer()); + if (RenderProgress* render = renderProgress()) { bool wasDeterminate = render->isDeterminate(); - renderer()->updateFromElement(); + render->updateFromElement(); if (wasDeterminate != isDeterminate()) setNeedsStyleRecalc(); } @@ -145,14 +163,18 @@ void HTMLProgressElement::didElementStateChange() void HTMLProgressElement::createShadowSubtree() { - ASSERT(!shadow()); + ASSERT(!userAgentShadowRoot()); + + RefPtr<ShadowRoot> root = ShadowRoot::create(this, ShadowRoot::UserAgentShadowRoot, ASSERT_NO_EXCEPTION); + + RefPtr<ProgressInnerElement> inner = ProgressInnerElement::create(document()); + root->appendChild(inner); RefPtr<ProgressBarElement> bar = ProgressBarElement::create(document()); m_value = ProgressValueElement::create(document()); bar->appendChild(m_value, ASSERT_NO_EXCEPTION); - RefPtr<ShadowRoot> root = ShadowRoot::create(this, ShadowRoot::UserAgentShadowRoot, ASSERT_NO_EXCEPTION); - root->appendChild(bar, ASSERT_NO_EXCEPTION); + inner->appendChild(bar, ASSERT_NO_EXCEPTION); } } // namespace diff --git a/Source/WebCore/html/HTMLProgressElement.h b/Source/WebCore/html/HTMLProgressElement.h index 72180b93d..6660d9d85 100644 --- a/Source/WebCore/html/HTMLProgressElement.h +++ b/Source/WebCore/html/HTMLProgressElement.h @@ -27,6 +27,7 @@ namespace WebCore { class ProgressValueElement; +class RenderProgress; class HTMLProgressElement : public LabelableElement { public: @@ -35,6 +36,8 @@ public: static PassRefPtr<HTMLProgressElement> create(const QualifiedName&, Document*); + bool hasAuthorShadowRoot() const { return m_hasAuthorShadowRoot; } + double value() const; void setValue(double, ExceptionCode&); @@ -51,12 +54,15 @@ private: HTMLProgressElement(const QualifiedName&, Document*); virtual ~HTMLProgressElement(); + virtual void willAddAuthorShadowRoot() OVERRIDE; + virtual bool supportLabels() const OVERRIDE { return true; } virtual bool supportsFocus() const; virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const OVERRIDE; + RenderProgress* renderProgress() const; virtual void parseAttribute(const Attribute&) OVERRIDE; @@ -66,8 +72,21 @@ private: void createShadowSubtree(); RefPtr<ProgressValueElement> m_value; + bool m_hasAuthorShadowRoot; }; +inline bool isHTMLProgressElement(Node* node) +{ + ASSERT(node); + return node->hasTagName(HTMLNames::progressTag); +} + +inline HTMLProgressElement* toHTMLProgressElement(Node* node) +{ + ASSERT(!node || isHTMLProgressElement(node)); + return static_cast<HTMLProgressElement*>(node); +} + } // namespace #endif diff --git a/Source/WebCore/html/HTMLPropertiesCollection.cpp b/Source/WebCore/html/HTMLPropertiesCollection.cpp index b67c4c16a..7e81766db 100644 --- a/Source/WebCore/html/HTMLPropertiesCollection.cpp +++ b/Source/WebCore/html/HTMLPropertiesCollection.cpp @@ -69,14 +69,14 @@ void HTMLPropertiesCollection::updateRefElements() const toHTMLElement(base())->getItemRefElements(m_itemRefElements); } -static Node* nextNodeWithProperty(Node* base, Node* node) +static Node* nextNodeWithProperty(Node* rootNode, Node* previous, Node* ownerNode) { // An Microdata item may contain properties which in turn are items themselves. Properties can // also themselves be groups of name-value pairs, by putting the itemscope attribute on the element // that declares the property. If the property has an itemscope attribute specified then we need // to traverse the next sibling. - return node == base || (node->isHTMLElement() && !toHTMLElement(node)->fastHasAttribute(itemscopeAttr)) - ? node->traverseNextNode(base) : node->traverseNextSibling(base); + return previous == ownerNode || (previous->isHTMLElement() && !toHTMLElement(previous)->fastHasAttribute(itemscopeAttr)) + ? previous->traverseNextNode(rootNode) : previous->traverseNextSibling(rootNode); } Element* HTMLPropertiesCollection::virtualItemAfter(unsigned& offsetInArray, Element* previousItem) const @@ -90,13 +90,14 @@ Element* HTMLPropertiesCollection::virtualItemAfter(unsigned& offsetInArray, Ele return 0; } -HTMLElement* HTMLPropertiesCollection::virtualItemAfter(HTMLElement* base, Element* previous) const +HTMLElement* HTMLPropertiesCollection::virtualItemAfter(HTMLElement* rootNode, Element* previous) const { Node* current; - current = previous ? nextNodeWithProperty(base, previous) : base; + Node* ownerNode = this->ownerNode(); + current = previous ? nextNodeWithProperty(rootNode, previous, ownerNode) : rootNode; - for (; current; current = nextNodeWithProperty(base, current)) { - if (!current->isHTMLElement()) + for (; current; current = nextNodeWithProperty(rootNode, current, ownerNode)) { + if (current == ownerNode || !current->isHTMLElement()) continue; HTMLElement* element = toHTMLElement(current); if (element->fastHasAttribute(itempropAttr) && element->itemProp()->length()) { diff --git a/Source/WebCore/html/HTMLSelectElement.cpp b/Source/WebCore/html/HTMLSelectElement.cpp index 83ccec5c3..98c99b830 100644 --- a/Source/WebCore/html/HTMLSelectElement.cpp +++ b/Source/WebCore/html/HTMLSelectElement.cpp @@ -1292,11 +1292,13 @@ void HTMLSelectElement::listBoxDefaultEventHandler(Event* event) IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(mouseEvent->absoluteLocation(), false, true)); int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toSize(localOffset)); if (listIndex >= 0) { + if (!disabled()) { #if PLATFORM(MAC) || (PLATFORM(CHROMIUM) && OS(DARWIN)) - updateSelectedState(listIndex, mouseEvent->metaKey(), mouseEvent->shiftKey()); + updateSelectedState(listIndex, mouseEvent->metaKey(), mouseEvent->shiftKey()); #else - updateSelectedState(listIndex, mouseEvent->ctrlKey(), mouseEvent->shiftKey()); + updateSelectedState(listIndex, mouseEvent->ctrlKey(), mouseEvent->shiftKey()); #endif + } if (Frame* frame = document()->frame()) frame->eventHandler()->setMouseDownMayStartAutoscroll(); @@ -1310,13 +1312,15 @@ void HTMLSelectElement::listBoxDefaultEventHandler(Event* event) IntPoint localOffset = roundedIntPoint(renderer()->absoluteToLocal(mouseEvent->absoluteLocation(), false, true)); int listIndex = toRenderListBox(renderer())->listIndexAtOffset(toSize(localOffset)); if (listIndex >= 0) { - if (m_multiple) { - setActiveSelectionEndIndex(listIndex); - updateListBoxSelection(false); - } else { - setActiveSelectionAnchorIndex(listIndex); - setActiveSelectionEndIndex(listIndex); - updateListBoxSelection(true); + if (!disabled()) { + if (m_multiple) { + setActiveSelectionEndIndex(listIndex); + updateListBoxSelection(false); + } else { + setActiveSelectionAnchorIndex(listIndex); + setActiveSelectionEndIndex(listIndex); + updateListBoxSelection(true); + } } event->setDefaultHandled(); } diff --git a/Source/WebCore/html/HTMLSummaryElement.cpp b/Source/WebCore/html/HTMLSummaryElement.cpp index 74ff5e6d7..e3b37b505 100644 --- a/Source/WebCore/html/HTMLSummaryElement.cpp +++ b/Source/WebCore/html/HTMLSummaryElement.cpp @@ -157,6 +157,14 @@ void HTMLSummaryElement::defaultEventHandler(Event* event) HTMLElement::defaultEventHandler(event); } +bool HTMLSummaryElement::willRespondToMouseClickEvents() +{ + if (isMainSummary() && renderer()) + return true; + + return HTMLElement::willRespondToMouseClickEvents(); +} + } #endif diff --git a/Source/WebCore/html/HTMLSummaryElement.h b/Source/WebCore/html/HTMLSummaryElement.h index 49a2d0bac..2c8a93fb5 100644 --- a/Source/WebCore/html/HTMLSummaryElement.h +++ b/Source/WebCore/html/HTMLSummaryElement.h @@ -31,6 +31,7 @@ class HTMLSummaryElement : public HTMLElement { public: static PassRefPtr<HTMLSummaryElement> create(const QualifiedName&, Document*); bool isMainSummary() const; + virtual bool willRespondToMouseClickEvents() OVERRIDE; private: HTMLSummaryElement(const QualifiedName&, Document*); diff --git a/Source/WebCore/html/HTMLTableCellElement.cpp b/Source/WebCore/html/HTMLTableCellElement.cpp index c75ecc8a1..294607d77 100644 --- a/Source/WebCore/html/HTMLTableCellElement.cpp +++ b/Source/WebCore/html/HTMLTableCellElement.cpp @@ -114,7 +114,7 @@ void HTMLTableCellElement::parseAttribute(const Attribute& attribute) HTMLTablePartElement::parseAttribute(attribute); } -StylePropertySet* HTMLTableCellElement::additionalAttributeStyle() +const StylePropertySet* HTMLTableCellElement::additionalAttributeStyle() { if (HTMLTableElement* table = findParentTable()) return table->additionalCellStyle(); diff --git a/Source/WebCore/html/HTMLTableCellElement.h b/Source/WebCore/html/HTMLTableCellElement.h index 5213e1c16..1850974cf 100644 --- a/Source/WebCore/html/HTMLTableCellElement.h +++ b/Source/WebCore/html/HTMLTableCellElement.h @@ -57,7 +57,7 @@ private: virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE; virtual void collectStyleForAttribute(const Attribute&, StylePropertySet*) OVERRIDE; - virtual StylePropertySet* additionalAttributeStyle() OVERRIDE; + virtual const StylePropertySet* additionalAttributeStyle() OVERRIDE; virtual bool isURLAttribute(const Attribute&) const OVERRIDE; diff --git a/Source/WebCore/html/HTMLTableColElement.cpp b/Source/WebCore/html/HTMLTableColElement.cpp index 651a3bc71..2830dfa48 100644 --- a/Source/WebCore/html/HTMLTableColElement.cpp +++ b/Source/WebCore/html/HTMLTableColElement.cpp @@ -81,7 +81,7 @@ void HTMLTableColElement::parseAttribute(const Attribute& attribute) HTMLTablePartElement::parseAttribute(attribute); } -StylePropertySet* HTMLTableColElement::additionalAttributeStyle() +const StylePropertySet* HTMLTableColElement::additionalAttributeStyle() { if (!hasLocalName(colgroupTag)) return 0; diff --git a/Source/WebCore/html/HTMLTableColElement.h b/Source/WebCore/html/HTMLTableColElement.h index 1916d250a..64069d9e1 100644 --- a/Source/WebCore/html/HTMLTableColElement.h +++ b/Source/WebCore/html/HTMLTableColElement.h @@ -45,7 +45,7 @@ private: virtual void parseAttribute(const Attribute&) OVERRIDE; virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE; virtual void collectStyleForAttribute(const Attribute&, StylePropertySet*) OVERRIDE; - virtual StylePropertySet* additionalAttributeStyle() OVERRIDE; + virtual const StylePropertySet* additionalAttributeStyle() OVERRIDE; int m_span; }; diff --git a/Source/WebCore/html/HTMLTableElement.cpp b/Source/WebCore/html/HTMLTableElement.cpp index 6232609fe..283786b72 100644 --- a/Source/WebCore/html/HTMLTableElement.cpp +++ b/Source/WebCore/html/HTMLTableElement.cpp @@ -432,7 +432,7 @@ static StylePropertySet* leakBorderStyle(int value) return style.release().leakRef(); } -StylePropertySet* HTMLTableElement::additionalAttributeStyle() +const StylePropertySet* HTMLTableElement::additionalAttributeStyle() { if (m_frameAttr) return 0; @@ -518,7 +518,7 @@ PassRefPtr<StylePropertySet> HTMLTableElement::createSharedCellStyle() return style.release(); } -StylePropertySet* HTMLTableElement::additionalCellStyle() +const StylePropertySet* HTMLTableElement::additionalCellStyle() { if (!m_sharedCellStyle) m_sharedCellStyle = createSharedCellStyle(); @@ -542,7 +542,7 @@ static StylePropertySet* leakGroupBorderStyle(int rows) return style.release().leakRef(); } -StylePropertySet* HTMLTableElement::additionalGroupStyle(bool rows) +const StylePropertySet* HTMLTableElement::additionalGroupStyle(bool rows) { if (m_rulesAttr != GroupsRules) return 0; diff --git a/Source/WebCore/html/HTMLTableElement.h b/Source/WebCore/html/HTMLTableElement.h index 2b05053ad..f11c467a8 100644 --- a/Source/WebCore/html/HTMLTableElement.h +++ b/Source/WebCore/html/HTMLTableElement.h @@ -65,8 +65,8 @@ public: String rules() const; String summary() const; - StylePropertySet* additionalCellStyle(); - StylePropertySet* additionalGroupStyle(bool rows); + const StylePropertySet* additionalCellStyle(); + const StylePropertySet* additionalGroupStyle(bool rows); private: HTMLTableElement(const QualifiedName&, Document*); @@ -77,7 +77,7 @@ private: virtual bool isURLAttribute(const Attribute&) const OVERRIDE; // Used to obtain either a solid or outset border decl and to deal with the frame and rules attributes. - virtual StylePropertySet* additionalAttributeStyle() OVERRIDE; + virtual const StylePropertySet* additionalAttributeStyle() OVERRIDE; virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const; diff --git a/Source/WebCore/html/HTMLTableSectionElement.cpp b/Source/WebCore/html/HTMLTableSectionElement.cpp index 60e54289c..582fcbbea 100644 --- a/Source/WebCore/html/HTMLTableSectionElement.cpp +++ b/Source/WebCore/html/HTMLTableSectionElement.cpp @@ -47,7 +47,7 @@ PassRefPtr<HTMLTableSectionElement> HTMLTableSectionElement::create(const Qualif return adoptRef(new HTMLTableSectionElement(tagName, document)); } -StylePropertySet* HTMLTableSectionElement::additionalAttributeStyle() +const StylePropertySet* HTMLTableSectionElement::additionalAttributeStyle() { if (HTMLTableElement* table = findParentTable()) return table->additionalGroupStyle(true); diff --git a/Source/WebCore/html/HTMLTableSectionElement.h b/Source/WebCore/html/HTMLTableSectionElement.h index 7156a70f0..075d052bf 100644 --- a/Source/WebCore/html/HTMLTableSectionElement.h +++ b/Source/WebCore/html/HTMLTableSectionElement.h @@ -56,7 +56,7 @@ public: private: HTMLTableSectionElement(const QualifiedName& tagName, Document*); - virtual StylePropertySet* additionalAttributeStyle() OVERRIDE; + virtual const StylePropertySet* additionalAttributeStyle() OVERRIDE; }; } //namespace diff --git a/Source/WebCore/html/HTMLTextAreaElement.h b/Source/WebCore/html/HTMLTextAreaElement.h index 18ebead28..4e6db563e 100644 --- a/Source/WebCore/html/HTMLTextAreaElement.h +++ b/Source/WebCore/html/HTMLTextAreaElement.h @@ -123,6 +123,11 @@ private: mutable bool m_wasModifiedByUser; }; +inline bool isHTMLTextAreaElement(Node* node) +{ + return node->hasTagName(HTMLNames::textareaTag); +} + } //namespace #endif diff --git a/Source/WebCore/html/HTMLTrackElement.idl b/Source/WebCore/html/HTMLTrackElement.idl index 0107df5a3..3e98fed66 100644 --- a/Source/WebCore/html/HTMLTrackElement.idl +++ b/Source/WebCore/html/HTMLTrackElement.idl @@ -28,8 +28,8 @@ module html { Conditional=VIDEO_TRACK, V8EnabledAtRuntime=webkitVideoTrack ] HTMLTrackElement : HTMLElement { - attribute [Reflect, URL] DOMString src; attribute DOMString kind; + attribute [Reflect, URL] DOMString src; attribute DOMString srclang; attribute DOMString label; attribute [Reflect] boolean default; diff --git a/Source/WebCore/html/HTMLVideoElement.cpp b/Source/WebCore/html/HTMLVideoElement.cpp index eebe53367..0e0e22f71 100644 --- a/Source/WebCore/html/HTMLVideoElement.cpp +++ b/Source/WebCore/html/HTMLVideoElement.cpp @@ -87,14 +87,6 @@ void HTMLVideoElement::attach() #endif } -void HTMLVideoElement::detach() -{ - HTMLMediaElement::detach(); - - if (!shouldDisplayPosterImage() && m_imageLoader) - m_imageLoader.clear(); -} - void HTMLVideoElement::collectStyleForAttribute(const Attribute& attribute, StylePropertySet* style) { if (attribute.name() == widthAttr) diff --git a/Source/WebCore/html/HTMLVideoElement.h b/Source/WebCore/html/HTMLVideoElement.h index b4c0391a7..dbe52a403 100644 --- a/Source/WebCore/html/HTMLVideoElement.h +++ b/Source/WebCore/html/HTMLVideoElement.h @@ -75,7 +75,6 @@ private: virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); #endif virtual void attach(); - virtual void detach(); virtual void parseAttribute(const Attribute&) OVERRIDE; virtual bool isPresentationAttribute(const QualifiedName&) const OVERRIDE; virtual void collectStyleForAttribute(const Attribute&, StylePropertySet*) OVERRIDE; diff --git a/Source/WebCore/html/InputType.cpp b/Source/WebCore/html/InputType.cpp index 09a895b50..674572e21 100644 --- a/Source/WebCore/html/InputType.cpp +++ b/Source/WebCore/html/InputType.cpp @@ -908,6 +908,12 @@ String InputType::defaultToolTip() const void InputType::listAttributeTargetChanged() { } + +Decimal InputType::findClosestTickMarkValue(const Decimal&) +{ + ASSERT_NOT_REACHED(); + return Decimal::nan(); +} #endif bool InputType::supportsIndeterminateAppearance() const diff --git a/Source/WebCore/html/InputType.h b/Source/WebCore/html/InputType.h index 0245ba888..a73ddba27 100644 --- a/Source/WebCore/html/InputType.h +++ b/Source/WebCore/html/InputType.h @@ -281,6 +281,7 @@ public: virtual String defaultToolTip() const; #if ENABLE(DATALIST_ELEMENT) virtual void listAttributeTargetChanged(); + virtual Decimal findClosestTickMarkValue(const Decimal&); #endif // Parses the specified string for the type, and return diff --git a/Source/WebCore/html/MediaController.cpp b/Source/WebCore/html/MediaController.cpp index 39fd09d4c..393ca8ade 100644 --- a/Source/WebCore/html/MediaController.cpp +++ b/Source/WebCore/html/MediaController.cpp @@ -32,6 +32,7 @@ #include "ExceptionCode.h" #include "HTMLMediaElement.h" #include "TimeRanges.h" +#include <wtf/CurrentTime.h> #include <wtf/StdLibExtras.h> #include <wtf/text/AtomicString.h> @@ -56,6 +57,8 @@ MediaController::MediaController(ScriptExecutionContext* context) , m_closedCaptionsVisible(false) , m_clock(Clock::create()) , m_scriptExecutionContext(context) + , m_timeupdateTimer(this, &MediaController::timeupdateTimerFired) + , m_previousTimeupdateTime(0) { } @@ -171,6 +174,8 @@ void MediaController::setCurrentTime(float time, ExceptionCode& code) // Seek each slaved media element to the new playback position relative to the media element timeline. for (size_t index = 0; index < m_mediaElements.size(); ++index) m_mediaElements[index]->seek(time, code); + + scheduleTimeupdateEvent(); } void MediaController::play() @@ -395,14 +400,17 @@ void MediaController::updatePlaybackState() case WAITING: eventName = eventNames().waitingEvent; m_clock->stop(); + m_timeupdateTimer.stop(); break; case ENDED: eventName = eventNames().endedEvent; m_clock->stop(); + m_timeupdateTimer.stop(); break; case PLAYING: eventName = eventNames().playingEvent; m_clock->start(); + startTimeupdateTimer(); break; default: ASSERT_NOT_REACHED(); @@ -605,4 +613,33 @@ const AtomicString& MediaController::interfaceName() const return eventNames().interfaceForMediaController; } +// The spec says to fire periodic timeupdate events (those sent while playing) every +// "15 to 250ms", we choose the slowest frequency +static const double maxTimeupdateEventFrequency = 0.25; + +void MediaController::startTimeupdateTimer() +{ + if (m_timeupdateTimer.isActive()) + return; + + m_timeupdateTimer.startRepeating(maxTimeupdateEventFrequency); +} + +void MediaController::timeupdateTimerFired(Timer<MediaController>*) +{ + scheduleTimeupdateEvent(); +} + +void MediaController::scheduleTimeupdateEvent() +{ + double now = WTF::currentTime(); + double timedelta = now - m_previousTimeupdateTime; + + if (timedelta < maxTimeupdateEventFrequency) + return; + + scheduleEvent(eventNames().timeupdateEvent); + m_previousTimeupdateTime = now; +} + #endif diff --git a/Source/WebCore/html/MediaController.h b/Source/WebCore/html/MediaController.h index d32b71279..d293ccb1d 100644 --- a/Source/WebCore/html/MediaController.h +++ b/Source/WebCore/html/MediaController.h @@ -125,6 +125,9 @@ private: void asyncEventTimerFired(Timer<MediaController>*); void clearPositionTimerFired(Timer<MediaController>*); bool hasEnded() const; + void scheduleTimeupdateEvent(); + void timeupdateTimerFired(Timer<MediaController>*); + void startTimeupdateTimer(); // EventTarget virtual void refEventTarget() { ref(); } @@ -152,6 +155,8 @@ private: bool m_closedCaptionsVisible; PassRefPtr<Clock> m_clock; ScriptExecutionContext* m_scriptExecutionContext; + Timer<MediaController> m_timeupdateTimer; + double m_previousTimeupdateTime; }; } // namespace WebCore diff --git a/Source/WebCore/html/NumberInputType.cpp b/Source/WebCore/html/NumberInputType.cpp index 8beff28af..82f12d1fd 100644 --- a/Source/WebCore/html/NumberInputType.cpp +++ b/Source/WebCore/html/NumberInputType.cpp @@ -239,13 +239,7 @@ String NumberInputType::localizeValue(const String& proposedValue) const // We don't localize scientific notations. if (proposedValue.find(isE) != notFound) return proposedValue; - // FIXME: The following three lines should be removed when we - // remove the second argument of convertToLocalizedNumber(). - // Note: parseToDoubleForNumberTypeWithDecimalPlaces set zero to decimalPlaces - // if currentValue isn't valid floating pointer number. - unsigned decimalPlace; - parseToDoubleForNumberTypeWithDecimalPlaces(proposedValue, &decimalPlace); - return convertToLocalizedNumber(proposedValue, decimalPlace); + return convertToLocalizedNumber(proposedValue); } String NumberInputType::visibleValue() const diff --git a/Source/WebCore/html/PublicURLManager.h b/Source/WebCore/html/PublicURLManager.h index 258ac067a..f5e7b20aa 100644 --- a/Source/WebCore/html/PublicURLManager.h +++ b/Source/WebCore/html/PublicURLManager.h @@ -37,6 +37,11 @@ #include "MediaStreamRegistry.h" #endif +#if ENABLE(MEDIA_SOURCE) +#include "MediaSource.h" +#include "MediaSourceRegistry.h" +#endif + namespace WebCore { class ScriptExecutionContext; @@ -56,18 +61,29 @@ public: for (HashSet<String>::iterator iter = m_streamURLs.begin(); iter != streamURLsEnd; ++iter) MediaStreamRegistry::registry().unregisterMediaStreamURL(KURL(ParsedURLString, *iter)); #endif +#if ENABLE(MEDIA_SOURCE) + HashSet<String>::iterator sourceURLsEnd = m_sourceURLs.end(); + for (HashSet<String>::iterator iter = m_sourceURLs.begin(); iter != sourceURLsEnd; ++iter) + MediaSourceRegistry::registry().unregisterMediaSourceURL(KURL(ParsedURLString, *iter)); +#endif } HashSet<String>& blobURLs() { return m_blobURLs; } #if ENABLE(MEDIA_STREAM) HashSet<String>& streamURLs() { return m_streamURLs; } #endif +#if ENABLE(MEDIA_SOURCE) + HashSet<String>& sourceURLs() { return m_sourceURLs; } +#endif private: HashSet<String> m_blobURLs; #if ENABLE(MEDIA_STREAM) HashSet<String> m_streamURLs; #endif +#if ENABLE(MEDIA_SOURCE) + HashSet<String> m_sourceURLs; +#endif }; } // namespace WebCore diff --git a/Source/WebCore/html/RangeInputType.cpp b/Source/WebCore/html/RangeInputType.cpp index 901a9acc1..ae696e6df 100644 --- a/Source/WebCore/html/RangeInputType.cpp +++ b/Source/WebCore/html/RangeInputType.cpp @@ -55,6 +55,12 @@ #include "TouchList.h" #endif +#if ENABLE(DATALIST_ELEMENT) +#include "HTMLDataListElement.h" +#include "HTMLOptionElement.h" +#include <wtf/NonCopyingSort.h> +#endif + namespace WebCore { using namespace HTMLNames; @@ -76,6 +82,14 @@ PassOwnPtr<InputType> RangeInputType::create(HTMLInputElement* element) return adoptPtr(new RangeInputType(element)); } +RangeInputType::RangeInputType(HTMLInputElement* element) + : InputType(element) +#if ENABLE(DATALIST_ELEMENT) + , m_tickMarkValuesDirty(true) +#endif +{ +} + bool RangeInputType::isRangeControl() const { return true; @@ -319,8 +333,70 @@ HTMLElement* RangeInputType::sliderThumbElement() const #if ENABLE(DATALIST_ELEMENT) void RangeInputType::listAttributeTargetChanged() { + m_tickMarkValuesDirty = true; element()->setNeedsStyleRecalc(); } + +static bool decimalCompare(const Decimal& a, const Decimal& b) +{ + return a < b; +} + +void RangeInputType::updateTickMarkValues() +{ + if (!m_tickMarkValuesDirty) + return; + m_tickMarkValues.clear(); + m_tickMarkValuesDirty = false; + HTMLDataListElement* dataList = element()->dataList(); + if (!dataList) + return; + RefPtr<HTMLCollection> options = dataList->options(); + m_tickMarkValues.reserveCapacity(options->length()); + for (unsigned i = 0; i < options->length(); ++i) { + Node* node = options->item(i); + HTMLOptionElement* optionElement = toHTMLOptionElement(node); + String optionValue = optionElement->value(); + if (!element()->isValidValue(optionValue)) + continue; + m_tickMarkValues.append(parseToNumber(optionValue, Decimal::nan())); + } + m_tickMarkValues.shrinkToFit(); + nonCopyingSort(m_tickMarkValues.begin(), m_tickMarkValues.end(), decimalCompare); +} + +Decimal RangeInputType::findClosestTickMarkValue(const Decimal& value) +{ + updateTickMarkValues(); + if (!m_tickMarkValues.size()) + return Decimal::nan(); + + size_t left = 0; + size_t right = m_tickMarkValues.size(); + size_t middle; + while (true) { + ASSERT(left <= right); + middle = left + (right - left) / 2; + if (!middle) + break; + if (middle == m_tickMarkValues.size() - 1 && m_tickMarkValues[middle] < value) { + middle++; + break; + } + if (m_tickMarkValues[middle - 1] <= value && m_tickMarkValues[middle] >= value) + break; + + if (m_tickMarkValues[middle] < value) + left = middle; + else + right = middle; + } + const Decimal closestLeft = middle ? m_tickMarkValues[middle - 1] : Decimal::infinity(Decimal::Negative); + const Decimal closestRight = middle != m_tickMarkValues.size() ? m_tickMarkValues[middle] : Decimal::infinity(Decimal::Positive); + if (closestRight - value < value - closestLeft) + return closestRight; + return closestLeft; +} #endif } // namespace WebCore diff --git a/Source/WebCore/html/RangeInputType.h b/Source/WebCore/html/RangeInputType.h index 69d2ec7c6..8367b6fef 100644 --- a/Source/WebCore/html/RangeInputType.h +++ b/Source/WebCore/html/RangeInputType.h @@ -42,7 +42,7 @@ public: static PassOwnPtr<InputType> create(HTMLInputElement*); private: - RangeInputType(HTMLInputElement* element) : InputType(element) { } + RangeInputType(HTMLInputElement*); virtual bool isRangeControl() const OVERRIDE; virtual const AtomicString& formControlType() const OVERRIDE; virtual double valueAsDouble() const OVERRIDE; @@ -72,6 +72,11 @@ private: virtual HTMLElement* sliderThumbElement() const OVERRIDE; #if ENABLE(DATALIST_ELEMENT) virtual void listAttributeTargetChanged() OVERRIDE; + void updateTickMarkValues(); + virtual Decimal findClosestTickMarkValue(const Decimal&) OVERRIDE; + + bool m_tickMarkValuesDirty; + Vector<Decimal> m_tickMarkValues; #endif }; diff --git a/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp b/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp index aced0bd0b..722c9c53d 100644 --- a/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp +++ b/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp @@ -1996,6 +1996,10 @@ void CanvasRenderingContext2D::setFont(const String& newFont) if (parsedStyle->isEmpty()) return; + RefPtr<CSSValue> fontValue = parsedStyle->getPropertyCSSValue(CSSPropertyFont); + if (fontValue && fontValue->isInheritedValue()) + return; + // The parse succeeded. realizeSaves(); modifiableState().m_unparsedFont = newFont; diff --git a/Source/WebCore/html/canvas/Float32Array.idl b/Source/WebCore/html/canvas/Float32Array.idl index 8eaebe4de..b445eb40d 100644 --- a/Source/WebCore/html/canvas/Float32Array.idl +++ b/Source/WebCore/html/canvas/Float32Array.idl @@ -26,14 +26,15 @@ module html { interface [ - CustomConstructor, + ConstructorTemplate=TypedArray, ConstructorParameters=1, NumericIndexedGetter, CustomIndexedSetter, JSGenerateToNativeObject, JSNoStaticTables, CustomToJSObject, - DoNotCheckConstants + DoNotCheckConstants, + TypedArray=float ] Float32Array : ArrayBufferView { const unsigned long BYTES_PER_ELEMENT = 4; @@ -43,6 +44,6 @@ module html { // void set(in Float32Array array, [Optional] in unsigned long offset); // void set(in sequence<long> array, [Optional] in unsigned long offset); - [Custom] void set(); + void set(); }; } diff --git a/Source/WebCore/html/canvas/Float64Array.idl b/Source/WebCore/html/canvas/Float64Array.idl index abfeb2178..da4b483a1 100644 --- a/Source/WebCore/html/canvas/Float64Array.idl +++ b/Source/WebCore/html/canvas/Float64Array.idl @@ -26,14 +26,15 @@ module html { interface [ - CustomConstructor, + ConstructorTemplate=TypedArray, ConstructorParameters=1, NumericIndexedGetter, CustomIndexedSetter, JSGenerateToNativeObject, JSNoStaticTables, CustomToJSObject, - DoNotCheckConstants + DoNotCheckConstants, + TypedArray=double ] Float64Array : ArrayBufferView { const unsigned long BYTES_PER_ELEMENT = 8; @@ -43,6 +44,6 @@ module html { // void set(in Float64Array array, [Optional] in unsigned long offset); // void set(in sequence<long> array, [Optional] in unsigned long offset); - [Custom] void set(); + void set(); }; } diff --git a/Source/WebCore/html/canvas/Int16Array.idl b/Source/WebCore/html/canvas/Int16Array.idl index f6d089ea3..9f98bea93 100644 --- a/Source/WebCore/html/canvas/Int16Array.idl +++ b/Source/WebCore/html/canvas/Int16Array.idl @@ -25,14 +25,15 @@ module html { interface [ - CustomConstructor, + ConstructorTemplate=TypedArray, ConstructorParameters=1, NumericIndexedGetter, CustomIndexedSetter, JSGenerateToNativeObject, JSNoStaticTables, CustomToJSObject, - DoNotCheckConstants + DoNotCheckConstants, + TypedArray=short ] Int16Array : ArrayBufferView { const unsigned long BYTES_PER_ELEMENT = 2; @@ -42,6 +43,6 @@ module html { // void set(in Int16Array array, [Optional] in unsigned long offset); // void set(in sequence<long> array, [Optional] in unsigned long offset); - [Custom] void set(); + void set(); }; } diff --git a/Source/WebCore/html/canvas/Int32Array.idl b/Source/WebCore/html/canvas/Int32Array.idl index f98835a2c..87cd7587c 100644 --- a/Source/WebCore/html/canvas/Int32Array.idl +++ b/Source/WebCore/html/canvas/Int32Array.idl @@ -26,14 +26,15 @@ module html { interface [ - CustomConstructor, + ConstructorTemplate=TypedArray, ConstructorParameters=1, NumericIndexedGetter, CustomIndexedSetter, JSGenerateToNativeObject, JSNoStaticTables, CustomToJSObject, - DoNotCheckConstants + DoNotCheckConstants, + TypedArray=int ] Int32Array : ArrayBufferView { const unsigned long BYTES_PER_ELEMENT = 4; @@ -43,6 +44,6 @@ module html { // void set(in Int32Array array, [Optional] in unsigned long offset); // void set(in sequence<long> array, [Optional] in unsigned long offset); - [Custom] void set(); + void set(); }; } diff --git a/Source/WebCore/html/canvas/Int8Array.idl b/Source/WebCore/html/canvas/Int8Array.idl index 00faa4fc3..10cf12003 100644 --- a/Source/WebCore/html/canvas/Int8Array.idl +++ b/Source/WebCore/html/canvas/Int8Array.idl @@ -26,14 +26,15 @@ module html { interface [ - CustomConstructor, + ConstructorTemplate=TypedArray, ConstructorParameters=1, NumericIndexedGetter, CustomIndexedSetter, JSGenerateToNativeObject, JSNoStaticTables, CustomToJSObject, - DoNotCheckConstants + DoNotCheckConstants, + TypedArray=signed char ] Int8Array : ArrayBufferView { const unsigned long BYTES_PER_ELEMENT = 1; @@ -43,6 +44,6 @@ module html { // void set(in Int8Array array, [Optional] in unsigned long offset); // void set(in sequence<long> array, [Optional] in unsigned long offset); - [Custom] void set(); + void set(); }; } diff --git a/Source/WebCore/html/canvas/Uint16Array.idl b/Source/WebCore/html/canvas/Uint16Array.idl index 79e05efc4..72998a35d 100644 --- a/Source/WebCore/html/canvas/Uint16Array.idl +++ b/Source/WebCore/html/canvas/Uint16Array.idl @@ -26,14 +26,15 @@ module html { interface [ - CustomConstructor, + ConstructorTemplate=TypedArray, ConstructorParameters=1, NumericIndexedGetter, CustomIndexedSetter, JSGenerateToNativeObject, JSNoStaticTables, CustomToJSObject, - DoNotCheckConstants + DoNotCheckConstants, + TypedArray=unsigned short ] Uint16Array : ArrayBufferView { const unsigned long BYTES_PER_ELEMENT = 2; @@ -42,6 +43,6 @@ module html { // void set(in Uint16Array array, [Optional] in unsigned long offset); // void set(in sequence<long> array, [Optional] in unsigned long offset); - [Custom] void set(); + void set(); }; } diff --git a/Source/WebCore/html/canvas/Uint32Array.idl b/Source/WebCore/html/canvas/Uint32Array.idl index 67e61b29f..65c44bef9 100644 --- a/Source/WebCore/html/canvas/Uint32Array.idl +++ b/Source/WebCore/html/canvas/Uint32Array.idl @@ -26,14 +26,15 @@ module html { interface [ - CustomConstructor, + ConstructorTemplate=TypedArray, ConstructorParameters=1, NumericIndexedGetter, CustomIndexedSetter, JSGenerateToNativeObject, JSNoStaticTables, CustomToJSObject, - DoNotCheckConstants + DoNotCheckConstants, + TypedArray=unsigned int ] Uint32Array : ArrayBufferView { const unsigned long BYTES_PER_ELEMENT = 4; @@ -42,6 +43,6 @@ module html { // void set(in Uint32Array array, [Optional] in unsigned long offset); // void set(in sequence<long> array, [Optional] in unsigned long offset); - [Custom] void set(); + void set(); }; } diff --git a/Source/WebCore/html/canvas/Uint8Array.idl b/Source/WebCore/html/canvas/Uint8Array.idl index 260a3273e..f6ef9377d 100644 --- a/Source/WebCore/html/canvas/Uint8Array.idl +++ b/Source/WebCore/html/canvas/Uint8Array.idl @@ -26,14 +26,15 @@ module html { interface [ - CustomConstructor, + ConstructorTemplate=TypedArray, ConstructorParameters=1, NumericIndexedGetter, CustomIndexedSetter, JSGenerateToNativeObject, JSNoStaticTables, CustomToJSObject, - DoNotCheckConstants + DoNotCheckConstants, + TypedArray=unsigned char ] Uint8Array : ArrayBufferView { const unsigned long BYTES_PER_ELEMENT = 1; @@ -42,6 +43,6 @@ module html { // void set(in Uint8Array array, [Optional] in unsigned long offset); // void set(in sequence<long> array, [Optional] in unsigned long offset); - [Custom] void set(); + void set(); }; } diff --git a/Source/WebCore/html/canvas/Uint8ClampedArray.idl b/Source/WebCore/html/canvas/Uint8ClampedArray.idl index cadd66364..c646e57e9 100644 --- a/Source/WebCore/html/canvas/Uint8ClampedArray.idl +++ b/Source/WebCore/html/canvas/Uint8ClampedArray.idl @@ -26,14 +26,15 @@ module html { interface [ - CustomConstructor, + ConstructorTemplate=TypedArray, ConstructorParameters=1, NumericIndexedGetter, CustomIndexedSetter, JSGenerateToNativeObject, JSNoStaticTables, CustomToJSObject, - DoNotCheckConstants + DoNotCheckConstants, + TypedArray=unsigned char ] Uint8ClampedArray : Uint8Array { const unsigned long BYTES_PER_ELEMENT = 1; @@ -43,6 +44,6 @@ module html { // FIXME: Missing other setters! // void set(in Uint8ClampedArray array, [Optional] in unsigned long offset); // void set(in sequence<long> array, [Optional] in unsigned long offset); - [Custom] void set(); + void set(); }; } diff --git a/Source/WebCore/html/canvas/WebGLRenderingContext.cpp b/Source/WebCore/html/canvas/WebGLRenderingContext.cpp index c0abf0fba..1ee6215fd 100644 --- a/Source/WebCore/html/canvas/WebGLRenderingContext.cpp +++ b/Source/WebCore/html/canvas/WebGLRenderingContext.cpp @@ -548,6 +548,7 @@ void WebGLRenderingContext::setupFlags() m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_ARB_texture_non_power_of_two"); m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_EXT_packed_depth_stencil"); } + m_isRobustnessEXTSupported = m_context->getExtensions()->isEnabled("GL_EXT_robustness"); } bool WebGLRenderingContext::allowPrivilegedExtensions() const @@ -2975,21 +2976,30 @@ WebGLGetInfo WebGLRenderingContext::getUniform(WebGLProgram* program, const WebG switch (baseType) { case GraphicsContext3D::FLOAT: { GC3Dfloat value[16] = {0}; - m_context->getUniformfv(objectOrZero(program), location, value); + if (m_isRobustnessEXTSupported) + m_context->getExtensions()->getnUniformfvEXT(objectOrZero(program), location, 16, value); + else + m_context->getUniformfv(objectOrZero(program), location, value); if (length == 1) return WebGLGetInfo(value[0]); return WebGLGetInfo(Float32Array::create(value, length)); } case GraphicsContext3D::INT: { GC3Dint value[4] = {0}; - m_context->getUniformiv(objectOrZero(program), location, value); + if (m_isRobustnessEXTSupported) + m_context->getExtensions()->getnUniformivEXT(objectOrZero(program), location, 4, value); + else + m_context->getUniformiv(objectOrZero(program), location, value); if (length == 1) return WebGLGetInfo(value[0]); return WebGLGetInfo(Int32Array::create(value, length)); } case GraphicsContext3D::BOOL: { GC3Dint value[4] = {0}; - m_context->getUniformiv(objectOrZero(program), location, value); + if (m_isRobustnessEXTSupported) + m_context->getExtensions()->getnUniformivEXT(objectOrZero(program), location, 4, value); + else + m_context->getUniformiv(objectOrZero(program), location, value); if (length > 1) { bool boolValue[16] = {0}; for (unsigned j = 0; j < length; j++) @@ -3290,26 +3300,34 @@ void WebGLRenderingContext::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC return; } // Calculate array size, taking into consideration of PACK_ALIGNMENT. - unsigned int totalBytesRequired; - unsigned int padding; - GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding); - if (error != GraphicsContext3D::NO_ERROR) { - synthesizeGLError(error, "readPixels", "invalid dimensions"); - return; - } - if (pixels->byteLength() < totalBytesRequired) { - synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "ArrayBufferView not large enough for dimensions"); - return; + unsigned int totalBytesRequired = 0; + unsigned int padding = 0; + if (!m_isRobustnessEXTSupported) { + GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding); + if (error != GraphicsContext3D::NO_ERROR) { + synthesizeGLError(error, "readPixels", "invalid dimensions"); + return; + } + if (pixels->byteLength() < totalBytesRequired) { + synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "ArrayBufferView not large enough for dimensions"); + return; + } } + clearIfComposited(); void* data = pixels->baseAddress(); { ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get()); - m_context->readPixels(x, y, width, height, format, type, data); + if (m_isRobustnessEXTSupported) + m_context->getExtensions()->readnPixelsEXT(x, y, width, height, format, type, pixels->byteLength(), data); + else + m_context->readPixels(x, y, width, height, format, type, data); } #if OS(DARWIN) || OS(QNX) + if (m_isRobustnessEXTSupported) // we haven't computed padding + m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding); // FIXME: remove this section when GL driver bug on Mac AND the GLES driver bug // on QC & Imagination QNX is fixed, i.e., when alpha is off, readPixels should // set alpha to 255 instead of 0. diff --git a/Source/WebCore/html/canvas/WebGLRenderingContext.h b/Source/WebCore/html/canvas/WebGLRenderingContext.h index 4c890ea21..c72ac590a 100644 --- a/Source/WebCore/html/canvas/WebGLRenderingContext.h +++ b/Source/WebCore/html/canvas/WebGLRenderingContext.h @@ -494,6 +494,7 @@ public: bool m_isErrorGeneratedOnOutOfBoundsAccesses; bool m_isResourceSafe; bool m_isDepthStencilSupported; + bool m_isRobustnessEXTSupported; bool m_synthesizedErrorsToConsole; int m_numGLErrorsToConsoleAllowed; diff --git a/Source/WebCore/html/parser/HTMLConstructionSite.cpp b/Source/WebCore/html/parser/HTMLConstructionSite.cpp index 62678722c..fc9d7c664 100644 --- a/Source/WebCore/html/parser/HTMLConstructionSite.cpp +++ b/Source/WebCore/html/parser/HTMLConstructionSite.cpp @@ -70,15 +70,6 @@ static bool hasImpliedEndTag(const HTMLStackItem* item) || item->hasTagName(rtTag); } -static bool causesFosterParenting(const HTMLStackItem* item) -{ - return item->hasTagName(tableTag) - || item->hasTagName(tbodyTag) - || item->hasTagName(tfootTag) - || item->hasTagName(theadTag) - || item->hasTagName(trTag); -} - static inline bool isAllWhitespace(const String& string) { return string.isAllSpecialCharacters<isHTMLSpace>(); @@ -277,9 +268,9 @@ void HTMLConstructionSite::insertCommentOnHTMLHtmlElement(AtomicHTMLToken* token void HTMLConstructionSite::insertHTMLHeadElement(AtomicHTMLToken* token) { ASSERT(!shouldFosterParent()); - m_head = createHTMLElement(token); - attachLater(currentNode(), m_head); - m_openElements.pushHTMLHeadElement(HTMLStackItem::create(m_head, token)); + m_head = HTMLStackItem::create(createHTMLElement(token), token); + attachLater(currentNode(), m_head->element()); + m_openElements.pushHTMLHeadElement(m_head); } void HTMLConstructionSite::insertHTMLBodyElement(AtomicHTMLToken* token) @@ -476,7 +467,10 @@ void HTMLConstructionSite::findFosterSite(HTMLConstructionSiteTask& task) HTMLElementStack::ElementRecord* lastTableElementRecord = m_openElements.topmost(tableTag.localName()); if (lastTableElementRecord) { Element* lastTableElement = lastTableElementRecord->element(); - if (ContainerNode* parent = lastTableElement->parentNode()) { + ContainerNode* parent = lastTableElement->parentNode(); + // When parsing HTML fragments, we skip step 4.2 ("Let root be a new html element with no attributes") for efficiency, + // and instead use the DocumentFragment as a root node. So we must treat the root node (DocumentFragment) as if it is a html element here. + if (parent && (parent->isElementNode() || (m_isParsingFragment && parent == m_openElements.rootNode()))) { task.parent = parent; task.nextChild = lastTableElement; return; @@ -492,7 +486,7 @@ bool HTMLConstructionSite::shouldFosterParent() const { return m_redirectAttachToFosterParent && currentStackItem()->isElementNode() - && causesFosterParenting(currentStackItem()); + && currentStackItem()->causesFosterParenting(); } void HTMLConstructionSite::fosterParent(PassRefPtr<Node> node) diff --git a/Source/WebCore/html/parser/HTMLConstructionSite.h b/Source/WebCore/html/parser/HTMLConstructionSite.h index 656e7987b..60572bdd8 100644 --- a/Source/WebCore/html/parser/HTMLConstructionSite.h +++ b/Source/WebCore/html/parser/HTMLConstructionSite.h @@ -97,7 +97,6 @@ public: void insertHTMLHtmlStartTagInBody(AtomicHTMLToken*); void insertHTMLBodyStartTagInBody(AtomicHTMLToken*); - PassRefPtr<Element> createHTMLElement(AtomicHTMLToken*); PassRefPtr<HTMLStackItem> createElementFromSavedToken(HTMLStackItem*); bool shouldFosterParent() const; @@ -114,12 +113,13 @@ public: Element* currentElement() const { return m_openElements.top(); } ContainerNode* currentNode() const { return m_openElements.topNode(); } HTMLStackItem* currentStackItem() const { return m_openElements.topStackItem(); } - Element* oneBelowTop() const { return m_openElements.oneBelowTop(); } + HTMLStackItem* oneBelowTop() const { return m_openElements.oneBelowTop(); } HTMLElementStack* openElements() const { return &m_openElements; } HTMLFormattingElementList* activeFormattingElements() const { return &m_activeFormattingElements; } - Element* head() const { return m_head.get(); } + Element* head() const { return m_head->element(); } + HTMLStackItem* headStackItem() const { return m_head.get(); } void setForm(HTMLFormElement*); HTMLFormElement* form() const { return m_form.get(); } @@ -154,6 +154,7 @@ private: void findFosterSite(HTMLConstructionSiteTask&); + PassRefPtr<Element> createHTMLElement(AtomicHTMLToken*); PassRefPtr<Element> createElement(AtomicHTMLToken*, const AtomicString& namespaceURI); void mergeAttributesFromTokenIntoElement(AtomicHTMLToken*, Element*); @@ -166,7 +167,7 @@ private: // and a Document in all other cases. ContainerNode* m_attachmentRoot; - RefPtr<Element> m_head; + RefPtr<HTMLStackItem> m_head; RefPtr<HTMLFormElement> m_form; mutable HTMLElementStack m_openElements; mutable HTMLFormattingElementList m_activeFormattingElements; diff --git a/Source/WebCore/html/parser/HTMLElementStack.cpp b/Source/WebCore/html/parser/HTMLElementStack.cpp index df074ffd3..62ed6f4e3 100644 --- a/Source/WebCore/html/parser/HTMLElementStack.cpp +++ b/Source/WebCore/html/parser/HTMLElementStack.cpp @@ -210,13 +210,13 @@ void HTMLElementStack::popAll() void HTMLElementStack::pop() { - ASSERT(!top()->hasTagName(HTMLNames::headTag)); + ASSERT(!topStackItem()->hasTagName(HTMLNames::headTag)); popCommon(); } void HTMLElementStack::popUntil(const AtomicString& tagName) { - while (!top()->hasLocalName(tagName)) { + while (!topStackItem()->hasLocalName(tagName)) { // pop() will ASSERT at <body> if callers fail to check that there is an // element with localName |tagName| on the stack of open elements. pop(); @@ -314,7 +314,7 @@ void HTMLElementStack::pushRootNode(PassRefPtr<HTMLStackItem> rootItem) void HTMLElementStack::pushHTMLHtmlElement(PassRefPtr<HTMLStackItem> item) { - ASSERT(item->element()->hasTagName(HTMLNames::htmlTag)); + ASSERT(item->hasTagName(HTMLNames::htmlTag)); pushRootNodeCommon(item); } @@ -328,7 +328,7 @@ void HTMLElementStack::pushRootNodeCommon(PassRefPtr<HTMLStackItem> rootItem) void HTMLElementStack::pushHTMLHeadElement(PassRefPtr<HTMLStackItem> item) { - ASSERT(item->element()->hasTagName(HTMLNames::headTag)); + ASSERT(item->hasTagName(HTMLNames::headTag)); ASSERT(!m_headElement); m_headElement = item->element(); pushCommon(item); @@ -336,7 +336,7 @@ void HTMLElementStack::pushHTMLHeadElement(PassRefPtr<HTMLStackItem> item) void HTMLElementStack::pushHTMLBodyElement(PassRefPtr<HTMLStackItem> item) { - ASSERT(item->element()->hasTagName(HTMLNames::bodyTag)); + ASSERT(item->hasTagName(HTMLNames::bodyTag)); ASSERT(!m_bodyElement); m_bodyElement = item->element(); pushCommon(item); @@ -344,9 +344,9 @@ void HTMLElementStack::pushHTMLBodyElement(PassRefPtr<HTMLStackItem> item) void HTMLElementStack::push(PassRefPtr<HTMLStackItem> item) { - ASSERT(!item->element()->hasTagName(HTMLNames::htmlTag)); - ASSERT(!item->element()->hasTagName(HTMLNames::headTag)); - ASSERT(!item->element()->hasTagName(HTMLNames::bodyTag)); + ASSERT(!item->hasTagName(HTMLNames::htmlTag)); + ASSERT(!item->hasTagName(HTMLNames::headTag)); + ASSERT(!item->hasTagName(HTMLNames::bodyTag)); ASSERT(m_rootNode); pushCommon(item); } @@ -356,9 +356,9 @@ void HTMLElementStack::insertAbove(PassRefPtr<HTMLStackItem> item, ElementRecord ASSERT(item); ASSERT(recordBelow); ASSERT(m_top); - ASSERT(!item->element()->hasTagName(HTMLNames::htmlTag)); - ASSERT(!item->element()->hasTagName(HTMLNames::headTag)); - ASSERT(!item->element()->hasTagName(HTMLNames::bodyTag)); + ASSERT(!item->hasTagName(HTMLNames::htmlTag)); + ASSERT(!item->hasTagName(HTMLNames::headTag)); + ASSERT(!item->hasTagName(HTMLNames::bodyTag)); ASSERT(m_rootNode); if (recordBelow == m_top) { push(item); @@ -383,21 +383,16 @@ HTMLElementStack::ElementRecord* HTMLElementStack::topRecord() const return m_top.get(); } -Element* HTMLElementStack::oneBelowTop() const +HTMLStackItem* HTMLElementStack::oneBelowTop() const { // We should never call this if there are fewer than 2 elements on the stack. ASSERT(m_top); ASSERT(m_top->next()); if (m_top->next()->stackItem()->isElementNode()) - return m_top->next()->element(); + return m_top->next()->stackItem().get(); return 0; } -Element* HTMLElementStack::bottom() const -{ - return htmlElement(); -} - void HTMLElementStack::removeHTMLHeadElement(Element* element) { ASSERT(m_headElement == element); @@ -576,9 +571,9 @@ void HTMLElementStack::pushCommon(PassRefPtr<HTMLStackItem> item) void HTMLElementStack::popCommon() { - ASSERT(!top()->hasTagName(HTMLNames::htmlTag)); - ASSERT(!top()->hasTagName(HTMLNames::headTag) || !m_headElement); - ASSERT(!top()->hasTagName(HTMLNames::bodyTag) || !m_bodyElement); + ASSERT(!topStackItem()->hasTagName(HTMLNames::htmlTag)); + ASSERT(!topStackItem()->hasTagName(HTMLNames::headTag) || !m_headElement); + ASSERT(!topStackItem()->hasTagName(HTMLNames::bodyTag) || !m_bodyElement); top()->finishParsingChildren(); m_top = m_top->releaseNext(); diff --git a/Source/WebCore/html/parser/HTMLElementStack.h b/Source/WebCore/html/parser/HTMLElementStack.h index f19bc3001..620c5a194 100644 --- a/Source/WebCore/html/parser/HTMLElementStack.h +++ b/Source/WebCore/html/parser/HTMLElementStack.h @@ -98,9 +98,8 @@ public: return m_top->stackItem().get(); } - Element* oneBelowTop() const; + HTMLStackItem* oneBelowTop() const; ElementRecord* topRecord() const; - Element* bottom() const; ElementRecord* find(Element*) const; ElementRecord* topmost(const AtomicString& tagName) const; diff --git a/Source/WebCore/html/parser/HTMLEntityParser.cpp b/Source/WebCore/html/parser/HTMLEntityParser.cpp index 442cedbc2..18718054b 100644 --- a/Source/WebCore/html/parser/HTMLEntityParser.cpp +++ b/Source/WebCore/html/parser/HTMLEntityParser.cpp @@ -87,7 +87,7 @@ public: StringBuilder consumedCharacters; HTMLEntitySearch entitySearch; while (!source.isEmpty()) { - cc = *source; + cc = source.currentChar(); entitySearch.advance(cc); if (!entitySearch.isEntityPrefix()) break; @@ -114,13 +114,13 @@ public: const int length = entitySearch.mostRecentMatch()->length; const UChar* reference = entitySearch.mostRecentMatch()->entity; for (int i = 0; i < length; ++i) { - cc = *source; + cc = source.currentChar(); ASSERT_UNUSED(reference, cc == *reference++); consumedCharacters.append(cc); source.advanceAndASSERT(cc); ASSERT(!source.isEmpty()); } - cc = *source; + cc = source.currentChar(); } if (entitySearch.mostRecentMatch()->lastCharacter() == ';' || !additionalAllowedCharacter diff --git a/Source/WebCore/html/parser/HTMLFormattingElementList.cpp b/Source/WebCore/html/parser/HTMLFormattingElementList.cpp index 1a45fb469..e7dd0dae1 100644 --- a/Source/WebCore/html/parser/HTMLFormattingElementList.cpp +++ b/Source/WebCore/html/parser/HTMLFormattingElementList.cpp @@ -59,7 +59,7 @@ Element* HTMLFormattingElementList::closestElementInScopeWithName(const AtomicSt const Entry& entry = m_entries[m_entries.size() - i]; if (entry.isMarker()) return 0; - if (entry.element()->hasLocalName(targetName)) + if (entry.stackItem()->hasLocalName(targetName)) return entry.element(); } return 0; diff --git a/Source/WebCore/html/parser/HTMLInputStream.h b/Source/WebCore/html/parser/HTMLInputStream.h index da6932fd4..593290bcf 100644 --- a/Source/WebCore/html/parser/HTMLInputStream.h +++ b/Source/WebCore/html/parser/HTMLInputStream.h @@ -74,7 +74,7 @@ public: { // FIXME: This should use InputStreamPreprocessor::endOfFileMarker // once InputStreamPreprocessor is split off into its own header. - static const UChar endOfFileMarker = 0; + static const LChar endOfFileMarker = 0; m_last->append(SegmentedString(String(&endOfFileMarker, 1))); m_last->close(); } diff --git a/Source/WebCore/html/parser/HTMLParserIdioms.cpp b/Source/WebCore/html/parser/HTMLParserIdioms.cpp index c3becc360..f0eb0ebb7 100644 --- a/Source/WebCore/html/parser/HTMLParserIdioms.cpp +++ b/Source/WebCore/html/parser/HTMLParserIdioms.cpp @@ -34,13 +34,13 @@ namespace WebCore { -String stripLeadingAndTrailingHTMLSpaces(const String& string) +template <typename CharType> +static String stripLeadingAndTrailingHTMLSpaces(String string, CharType characters, unsigned length) { - const UChar* characters = string.characters(); - unsigned length = string.length(); + unsigned numLeadingSpaces = 0; + unsigned numTrailingSpaces = 0; - unsigned numLeadingSpaces; - for (numLeadingSpaces = 0; numLeadingSpaces < length; ++numLeadingSpaces) { + for (; numLeadingSpaces < length; ++numLeadingSpaces) { if (isNotHTMLSpace(characters[numLeadingSpaces])) break; } @@ -48,17 +48,32 @@ String stripLeadingAndTrailingHTMLSpaces(const String& string) if (numLeadingSpaces == length) return string.isNull() ? string : emptyAtom.string(); - unsigned numTrailingSpaces; - for (numTrailingSpaces = 0; numTrailingSpaces < length; ++numTrailingSpaces) { + for (; numTrailingSpaces < length; ++numTrailingSpaces) { if (isNotHTMLSpace(characters[length - numTrailingSpaces - 1])) break; } ASSERT(numLeadingSpaces + numTrailingSpaces < length); + if (!(numLeadingSpaces | numTrailingSpaces)) + return string; + return string.substring(numLeadingSpaces, length - (numLeadingSpaces + numTrailingSpaces)); } +String stripLeadingAndTrailingHTMLSpaces(const String& string) +{ + unsigned length = string.length(); + + if (!length) + return string.isNull() ? string : emptyAtom.string(); + + if (string.is8Bit()) + return stripLeadingAndTrailingHTMLSpaces(string, string.characters8(), length); + + return stripLeadingAndTrailingHTMLSpaces(string, string.characters(), length); +} + String serializeForNumberType(const Decimal& number) { if (number.isZero()) { @@ -137,84 +152,6 @@ double parseToDoubleForNumberType(const String& string) return parseToDoubleForNumberType(string, std::numeric_limits<double>::quiet_NaN()); } -double parseToDoubleForNumberTypeWithDecimalPlaces(const String& string, unsigned *decimalPlaces, double fallbackValue) -{ - if (decimalPlaces) - *decimalPlaces = 0; - - double value = parseToDoubleForNumberType(string, std::numeric_limits<double>::quiet_NaN()); - if (!isfinite(value)) - return fallbackValue; - - if (!decimalPlaces) - return value; - - size_t dotIndex = string.find('.'); - size_t eIndex = string.find('e'); - if (eIndex == notFound) - eIndex = string.find('E'); - - unsigned baseDecimalPlaces = 0; - if (dotIndex != notFound) { - if (eIndex == notFound) - baseDecimalPlaces = string.length() - dotIndex - 1; - else - baseDecimalPlaces = eIndex - dotIndex - 1; - } - - int exponent = 0; - if (eIndex != notFound) { - unsigned cursor = eIndex + 1, cursorSaved; - int digit, exponentSign; - int32_t exponent32; - size_t length = string.length(); - - // Not using String.toInt() in order to perform the same computation as dtoa() does. - exponentSign = 0; - switch (digit = string[cursor]) { - case '-': - exponentSign = 1; - case '+': - digit = string[++cursor]; - } - if (digit >= '0' && digit <= '9') { - while (cursor < length && digit == '0') - digit = string[++cursor]; - if (digit > '0' && digit <= '9') { - exponent32 = digit - '0'; - cursorSaved = cursor; - while (cursor < length && (digit = string[++cursor]) >= '0' && digit <= '9') - exponent32 = (10 * exponent32) + digit - '0'; - if (cursor - cursorSaved > 8 || exponent32 > 19999) - /* Avoid confusion from exponents - * so large that e might overflow. - */ - exponent = 19999; /* safe for 16 bit ints */ - else - exponent = static_cast<int>(exponent32); - if (exponentSign) - exponent = -exponent; - } else - exponent = 0; - } - } - - int intDecimalPlaces = baseDecimalPlaces - exponent; - if (intDecimalPlaces < 0) - *decimalPlaces = 0; - else if (intDecimalPlaces > 19999) - *decimalPlaces = 19999; - else - *decimalPlaces = static_cast<unsigned>(intDecimalPlaces); - - return value; -} - -double parseToDoubleForNumberTypeWithDecimalPlaces(const String& string, unsigned *decimalPlaces) -{ - return parseToDoubleForNumberTypeWithDecimalPlaces(string, decimalPlaces, std::numeric_limits<double>::quiet_NaN()); -} - // http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers bool parseHTMLInteger(const String& input, int& value) { diff --git a/Source/WebCore/html/parser/HTMLParserIdioms.h b/Source/WebCore/html/parser/HTMLParserIdioms.h index 5f0186d44..577e02e85 100644 --- a/Source/WebCore/html/parser/HTMLParserIdioms.h +++ b/Source/WebCore/html/parser/HTMLParserIdioms.h @@ -51,8 +51,6 @@ Decimal parseToDecimalForNumberType(const String&); Decimal parseToDecimalForNumberType(const String&, const Decimal& fallbackValue); double parseToDoubleForNumberType(const String&); double parseToDoubleForNumberType(const String&, double fallbackValue); -double parseToDoubleForNumberTypeWithDecimalPlaces(const String&, unsigned*); -double parseToDoubleForNumberTypeWithDecimalPlaces(const String&, unsigned*, double fallbackValue); // http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers bool parseHTMLInteger(const String&, int&); diff --git a/Source/WebCore/html/parser/HTMLSourceTracker.cpp b/Source/WebCore/html/parser/HTMLSourceTracker.cpp index e7c68764b..b042dd657 100644 --- a/Source/WebCore/html/parser/HTMLSourceTracker.cpp +++ b/Source/WebCore/html/parser/HTMLSourceTracker.cpp @@ -71,12 +71,12 @@ String HTMLSourceTracker::sourceForToken(const HTMLToken& token) size_t i = 0; for ( ; i < length && !m_previousSource.isEmpty(); ++i) { - source.append(*m_previousSource); + source.append(m_previousSource.currentChar()); m_previousSource.advance(); } for ( ; i < length; ++i) { ASSERT(!m_currentSource.isEmpty()); - source.append(*m_currentSource); + source.append(m_currentSource.currentChar()); m_currentSource.advance(); } diff --git a/Source/WebCore/html/parser/HTMLStackItem.h b/Source/WebCore/html/parser/HTMLStackItem.h index 05b221042..371ac43f4 100644 --- a/Source/WebCore/html/parser/HTMLStackItem.h +++ b/Source/WebCore/html/parser/HTMLStackItem.h @@ -70,6 +70,15 @@ public: bool hasLocalName(const AtomicString& name) const { return m_token->name() == name; } bool hasTagName(const QualifiedName& name) const { return m_token->name() == name.localName() && m_namespaceURI == name.namespaceURI(); } + bool causesFosterParenting() + { + return hasTagName(HTMLNames::tableTag) + || hasTagName(HTMLNames::tbodyTag) + || hasTagName(HTMLNames::tfootTag) + || hasTagName(HTMLNames::theadTag) + || hasTagName(HTMLNames::trTag); + } + private: HTMLStackItem(PassRefPtr<ContainerNode> node, ItemType type) : m_node(node) diff --git a/Source/WebCore/html/parser/HTMLTreeBuilder.cpp b/Source/WebCore/html/parser/HTMLTreeBuilder.cpp index 3526acafc..a7f14519e 100644 --- a/Source/WebCore/html/parser/HTMLTreeBuilder.cpp +++ b/Source/WebCore/html/parser/HTMLTreeBuilder.cpp @@ -710,14 +710,15 @@ static void adjustForeignAttributes(AtomicHTMLToken* token) static PrefixedNameToQualifiedNameMap* map = 0; if (!map) { map = new PrefixedNameToQualifiedNameMap; + QualifiedName** attrs = XLinkNames::getXLinkAttrs(); - addNamesWithPrefix(map, "xlink", attrs, XLinkNames::XLinkAttrsCount); + addNamesWithPrefix(map, xlinkAtom, attrs, XLinkNames::XLinkAttrsCount); attrs = XMLNames::getXMLAttrs(); - addNamesWithPrefix(map, "xml", attrs, XMLNames::XMLAttrsCount); + addNamesWithPrefix(map, xmlAtom, attrs, XMLNames::XMLAttrsCount); - map->add("xmlns", XMLNSNames::xmlnsAttr); - map->add("xmlns:xlink", QualifiedName("xmlns", "xlink", XMLNSNames::xmlnsNamespaceURI)); + map->add(WTF::xmlnsAtom, XMLNSNames::xmlnsAttr); + map->add("xmlns:xlink", QualifiedName(xmlnsAtom, xlinkAtom, XMLNSNames::xmlnsNamespaceURI)); } for (unsigned i = 0; i < token->attributes().size(); ++i) { @@ -1189,7 +1190,7 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken* token) || token->name() == titleTag) { parseError(token); ASSERT(m_tree.head()); - m_tree.openElements()->pushHTMLHeadElement(HTMLStackItem::create(m_tree.head(), token)); + m_tree.openElements()->pushHTMLHeadElement(m_tree.headStackItem()); processStartTagForInHead(token); m_tree.openElements()->removeHTMLHeadElement(m_tree.head()); return; @@ -1542,7 +1543,7 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken* token) } // 4. ASSERT(furthestBlock->isAbove(formattingElementRecord)); - RefPtr<ContainerNode> commonAncestor = formattingElementRecord->next()->node(); + RefPtr<HTMLStackItem> commonAncestor = formattingElementRecord->next()->stackItem(); // 5. HTMLFormattingElementList::Bookmark bookmark = m_tree.activeFormattingElements()->bookmarkFor(formattingElement); // 6. @@ -1584,17 +1585,12 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken* token) lastNode = node; } // 7 - const AtomicString& commonAncestorTag = commonAncestor->localName(); if (ContainerNode* parent = lastNode->element()->parentNode()) parent->parserRemoveChild(lastNode->element()); - // FIXME: If this moves to HTMLConstructionSite, this check should use - // causesFosterParenting(tagName) instead. - if (commonAncestorTag == tableTag - || commonAncestorTag == trTag - || isTableBodyContextTag(commonAncestorTag)) + if (commonAncestor->causesFosterParenting()) m_tree.fosterParent(lastNode->element()); else { - commonAncestor->parserAddChild(lastNode->element()); + commonAncestor->node()->parserAddChild(lastNode->element()); ASSERT(lastNode->stackItem()->isElementNode()); ASSERT(lastNode->element()->parentNode()); if (lastNode->element()->parentNode()->attached() && !lastNode->element()->attached()) diff --git a/Source/WebCore/html/shadow/CalendarPickerElement.cpp b/Source/WebCore/html/shadow/CalendarPickerElement.cpp index b7ea32f28..e70151df6 100644 --- a/Source/WebCore/html/shadow/CalendarPickerElement.cpp +++ b/Source/WebCore/html/shadow/CalendarPickerElement.cpp @@ -104,6 +104,15 @@ void CalendarPickerElement::defaultEventHandler(Event* event) HTMLDivElement::defaultEventHandler(event); } +bool CalendarPickerElement::willRespondToMouseClickEvents() +{ + const HTMLInputElement* input = hostInput(); + if (renderer() && !input->readOnly() && !input->disabled()) + return true; + + return HTMLDivElement::willRespondToMouseClickEvents(); +} + void CalendarPickerElement::openPopup() { if (m_popup) @@ -139,7 +148,7 @@ void CalendarPickerElement::detach() IntSize CalendarPickerElement::contentSize() { - return IntSize(100, 100); + return IntSize(0, 0); } void CalendarPickerElement::writeDocument(DocumentWriter& writer) diff --git a/Source/WebCore/html/shadow/CalendarPickerElement.h b/Source/WebCore/html/shadow/CalendarPickerElement.h index e6f6a4d1d..cbf213fc5 100644 --- a/Source/WebCore/html/shadow/CalendarPickerElement.h +++ b/Source/WebCore/html/shadow/CalendarPickerElement.h @@ -46,6 +46,7 @@ public: virtual ~CalendarPickerElement(); void openPopup(); void closePopup(); + virtual bool willRespondToMouseClickEvents() OVERRIDE; private: CalendarPickerElement(Document*); diff --git a/Source/WebCore/html/shadow/ContentDistributor.cpp b/Source/WebCore/html/shadow/ContentDistributor.cpp index b3fdd32ad..324a5d0ed 100644 --- a/Source/WebCore/html/shadow/ContentDistributor.cpp +++ b/Source/WebCore/html/shadow/ContentDistributor.cpp @@ -49,7 +49,6 @@ InsertionPoint* ContentDistributor::findInsertionPointFor(const Node* key) const return m_nodeToInsertionPoint.get(key); } - void ContentDistributor::distribute(Element* host) { ASSERT(needsDistribution()); diff --git a/Source/WebCore/html/shadow/ContentDistributor.h b/Source/WebCore/html/shadow/ContentDistributor.h index 3077cff41..214e54fce 100644 --- a/Source/WebCore/html/shadow/ContentDistributor.h +++ b/Source/WebCore/html/shadow/ContentDistributor.h @@ -60,6 +60,8 @@ public: InsertionPoint* findInsertionPointFor(const Node* key) const; + void setValidity(Validity validity) { m_validity = validity; } + void distribute(Element* host); bool invalidate(Element* host); void finishInivalidation(); diff --git a/Source/WebCore/html/shadow/DateTimeEditElement.cpp b/Source/WebCore/html/shadow/DateTimeEditElement.cpp new file mode 100644 index 000000000..0ed1dacc3 --- /dev/null +++ b/Source/WebCore/html/shadow/DateTimeEditElement.cpp @@ -0,0 +1,472 @@ +/* + * 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 "DateTimeEditElement.h" + +#include "DateComponents.h" +#include "DateTimeFieldElements.h" +#include "DateTimeFormat.h" +#include "DateTimeSymbolicFieldElement.h" +#include "EventHandler.h" +#include "HTMLNames.h" +#include "KeyboardEvent.h" +#include "LocalizedDate.h" +#include "LocalizedNumber.h" +#include "MouseEvent.h" +#include "StepRange.h" +#include "Text.h" +#include <wtf/DateMath.h> +#include <wtf/text/StringBuilder.h> + +namespace WebCore { + +using namespace HTMLNames; + +class DateTimeEditBuilder : private DateTimeFormat::TokenHandler { + WTF_MAKE_NONCOPYABLE(DateTimeEditBuilder); + +public: + DateTimeEditBuilder(DateTimeEditElement&, const StepRange&); + + bool build(const String&); + bool needSecondField() const; + +private: + bool needMillisecondField() const; + bool needMinuteField() const; + bool shouldMillisecondFieldReadOnly() const; + bool shouldMinuteFieldReadOnly() const; + bool shouldSecondFieldReadOnly() const; + + // DateTimeFormat::TokenHandler functions. + virtual void visitField(DateTimeFormat::FieldType, int) OVERRIDE FINAL; + virtual void visitLiteral(const String&) OVERRIDE FINAL; + + DateTimeEditElement& m_editElement; + const StepRange& m_stepRange; +}; + +DateTimeEditBuilder::DateTimeEditBuilder(DateTimeEditElement& elemnt, const StepRange& stepRange) + : m_editElement(elemnt) + , m_stepRange(stepRange) +{ +} + +bool DateTimeEditBuilder::build(const String& formatString) +{ + m_editElement.resetLayout(); + return DateTimeFormat::parse(formatString, *this); +} + +bool DateTimeEditBuilder::needMillisecondField() const +{ + return !m_stepRange.minimum().remainder(static_cast<int>(msPerSecond)).isZero() + || !m_stepRange.step().remainder(static_cast<int>(msPerSecond)).isZero(); +} + +bool DateTimeEditBuilder::needMinuteField() const +{ + return !m_stepRange.minimum().remainder(static_cast<int>(msPerHour)).isZero() + || !m_stepRange.step().remainder(static_cast<int>(msPerHour)).isZero(); +} + +bool DateTimeEditBuilder::needSecondField() const +{ + return !m_stepRange.minimum().remainder(static_cast<int>(msPerMinute)).isZero() + || !m_stepRange.step().remainder(static_cast<int>(msPerMinute)).isZero(); +} + +void DateTimeEditBuilder::visitField(DateTimeFormat::FieldType fieldType, int) +{ + Document* const document = m_editElement.document(); + + switch (fieldType) { + case DateTimeFormat::FieldTypeHour11: + m_editElement.addField(DateTimeHourFieldElement::create(document, m_editElement, 0, 11)); + return; + + case DateTimeFormat::FieldTypeHour12: + m_editElement.addField(DateTimeHourFieldElement::create(document, m_editElement, 1, 12)); + return; + + case DateTimeFormat::FieldTypeHour23: + m_editElement.addField(DateTimeHourFieldElement::create(document, m_editElement, 0, 23)); + return; + + case DateTimeFormat::FieldTypeHour24: + m_editElement.addField(DateTimeHourFieldElement::create(document, m_editElement, 1, 24)); + return; + + case DateTimeFormat::FieldTypeMinute: { + RefPtr<DateTimeNumericFieldElement> field = DateTimeMinuteFieldElement::create(document, m_editElement); + m_editElement.addField(field); + if (shouldMinuteFieldReadOnly()) + field->setReadOnly(); + return; + } + + case DateTimeFormat::FieldTypePeriod: + m_editElement.addField(DateTimeAMPMFieldElement::create(document, m_editElement, timeAMPMLabels())); + return; + + case DateTimeFormat::FieldTypeSecond: { + RefPtr<DateTimeSecondFieldElement> field = DateTimeSecondFieldElement::create(document, m_editElement); + m_editElement.addField(field); + if (shouldSecondFieldReadOnly()) + field->setReadOnly(); + + if (needMillisecondField()) { + visitLiteral(localizedDecimalSeparator()); + visitField(DateTimeFormat::FieldTypeFractionalSecond, 3); + } + return; + } + + case DateTimeFormat::FieldTypeFractionalSecond: { + RefPtr<DateTimeMillisecondFieldElement> field = DateTimeMillisecondFieldElement::create(document, m_editElement); + m_editElement.addField(field); + if (shouldMillisecondFieldReadOnly()) + field->setReadOnly(); + return; + } + + default: + return; + } +} + +bool DateTimeEditBuilder::shouldMillisecondFieldReadOnly() const +{ + return m_stepRange.step().remainder(static_cast<int>(msPerSecond)).isZero(); +} + +bool DateTimeEditBuilder::shouldMinuteFieldReadOnly() const +{ + return m_stepRange.step().remainder(static_cast<int>(msPerHour)).isZero(); +} + +bool DateTimeEditBuilder::shouldSecondFieldReadOnly() const +{ + return m_stepRange.step().remainder(static_cast<int>(msPerMinute)).isZero(); +} + +void DateTimeEditBuilder::visitLiteral(const String& text) +{ + ASSERT(text.length()); + m_editElement.appendChild(Text::create(m_editElement.document(), text)); +} + +// ---------------------------- + +DateTimeEditElement::EditControlOwner::~EditControlOwner() +{ +} + +DateTimeEditElement::DateTimeEditElement(Document* document, EditControlOwner& editControlOwner) + : HTMLDivElement(divTag, document) + , m_editControlOwner(&editControlOwner) + , m_spinButton(0) + , m_focusFieldIndex(invalidFieldIndex) +{ + DEFINE_STATIC_LOCAL(AtomicString, dateTimeEditPseudoId, ("-webkit-datetime-edit")); + setShadowPseudoId(dateTimeEditPseudoId); +} + +DateTimeEditElement::~DateTimeEditElement() +{ + for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) + m_fields[fieldIndex]->removeEventHandler(); + + if (m_spinButton) + m_spinButton->removeStepActionHandler(); +} + +void DateTimeEditElement::addField(PassRefPtr<DateTimeFieldElement> field) +{ + if (m_fields.size() == m_fields.capacity()) + return; + m_fields.append(field.get()); + appendChild(field); +} + +PassRefPtr<DateTimeEditElement> DateTimeEditElement::create(Document* document, EditControlOwner& editControlOwner, const StepRange& stepRange) +{ + RefPtr<DateTimeEditElement> container = adoptRef(new DateTimeEditElement(document, editControlOwner)); + container->layout(stepRange); + return container.release(); +} + +void DateTimeEditElement::disabledStateChanged() +{ + updateUIState(); +} + +DateTimeFieldElement* DateTimeEditElement::fieldAt(size_t fieldIndex) const +{ + return fieldIndex < m_fields.size() ? m_fields[fieldIndex] : 0; +} + +void DateTimeEditElement::focusFieldAt(size_t newFocusFieldIndex) +{ + if (m_focusFieldIndex == newFocusFieldIndex) + return; + + DateTimeFieldElement* const newFocusField = fieldAt(newFocusFieldIndex); + if (newFocusField && newFocusField->isReadOnly()) + return; + + DateTimeFieldElement* const currentFocusField = fieldAt(m_focusFieldIndex); + + if (currentFocusField) + currentFocusField->setFocus(false); + + if (!newFocusField) { + m_focusFieldIndex = invalidFieldIndex; + return; + } + + m_focusFieldIndex = newFocusFieldIndex; + newFocusField->setFocus(true); +} + +void DateTimeEditElement::handleKeyboardEvent(KeyboardEvent* keyboardEvent) +{ + if (isDisabled() || isReadOnly()) + return; + + if (!fieldAt(m_focusFieldIndex)) + return; + + if (keyboardEvent->type() != eventNames().keydownEvent) + return; + + const String& keyIdentifier = keyboardEvent->keyIdentifier(); + + if (keyIdentifier == "Left") { + keyboardEvent->setDefaultHandled(); + const size_t fieldIndex = previousFieldIndex(); + if (fieldAt(fieldIndex)) + focusFieldAt(fieldIndex); + return; + } + + if (keyIdentifier == "Right") { + keyboardEvent->setDefaultHandled(); + const size_t fieldIndex = nextFieldIndex(); + if (fieldAt(fieldIndex)) + focusFieldAt(fieldIndex); + return; + } + + if (keyIdentifier == "U+0009") { + const size_t fieldIndex = keyboardEvent->getModifierState("Shift") ? previousFieldIndex() : nextFieldIndex(); + if (fieldAt(fieldIndex)) { + keyboardEvent->setDefaultHandled(); + focusFieldAt(fieldIndex); + return; + } + } +} + +void DateTimeEditElement::fieldValueChanged() +{ + if (m_editControlOwner) + m_editControlOwner->editControlValueChanged(); +} + +void DateTimeEditElement::focusOnNextField() +{ + if (m_focusFieldIndex != invalidFieldIndex) + focusFieldAt(nextFieldIndex()); +} + +void DateTimeEditElement::handleMouseEvent(MouseEvent* mouseEvent) +{ + if (isDisabled() || isReadOnly()) + return; + + if (mouseEvent->type() != eventNames().mousedownEvent || mouseEvent->button() != LeftButton) + return; + + Node* const relatedTarget = mouseEvent->target()->toNode(); + for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) { + if (m_fields[fieldIndex] == relatedTarget) { + mouseEvent->setDefaultHandled(); + focusFieldAt(fieldIndex); + if (m_editControlOwner) + m_editControlOwner->editControlMouseFocus(); + break; + } + } +} + +bool DateTimeEditElement::isDisabled() const +{ + return m_editControlOwner && m_editControlOwner->isEditControlOwnerDisabled(); +} + +bool DateTimeEditElement::isReadOnly() const +{ + return m_editControlOwner && m_editControlOwner->isEditControlOwnerReadOnly(); +} + +void DateTimeEditElement::layout(const StepRange& stepRange) +{ + DateTimeFieldElement* const focusField = fieldAt(m_focusFieldIndex); + focusFieldAt(invalidFieldIndex); + + DateTimeEditBuilder builder(*this, stepRange); + const String dateTimeFormat = builder.needSecondField() ? localizedTimeFormatText() : localizedShortTimeFormatText(); + if (!builder.build(dateTimeFormat) || m_fields.isEmpty()) + builder.build(builder.needSecondField() ? "HH:mm:ss" : "HH:mm"); + + RefPtr<SpinButtonElement> spinButton = SpinButtonElement::create(document(), *this); + m_spinButton = spinButton.get(); + appendChild(spinButton); + + if (focusField) { + for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) { + if (focusField == m_fields[fieldIndex]) { + focusFieldAt(fieldIndex); + break; + } + } + } +} + +size_t DateTimeEditElement::nextFieldIndex() const +{ + ASSERT(m_focusFieldIndex != invalidFieldIndex); + for (size_t fieldIndex = m_focusFieldIndex + 1; fieldIndex < m_fields.size(); ++fieldIndex) { + if (!m_fields[fieldIndex]->isReadOnly()) + return fieldIndex; + } + return m_fields.size(); +} + +size_t DateTimeEditElement::previousFieldIndex() const +{ + ASSERT(m_focusFieldIndex != invalidFieldIndex); + size_t fieldIndex = m_focusFieldIndex; + while (fieldIndex > 0) { + --fieldIndex; + if (!m_fields[fieldIndex]->isReadOnly()) + return fieldIndex; + } + return invalidFieldIndex; +} + +void DateTimeEditElement::readOnlyStateChanged() +{ + updateUIState(); +} + +void DateTimeEditElement::resetLayout() +{ + m_fields.shrink(0); + m_spinButton = 0; + m_focusFieldIndex = invalidFieldIndex; + removeChildren(); +} + +void DateTimeEditElement::defaultEventHandler(Event* event) +{ + if (event->type() == eventNames().focusEvent) { + if (!isDisabled() && !isReadOnly() && m_focusFieldIndex == invalidFieldIndex) + focusFieldAt(0); + return; + } + + if (event->type() == eventNames().blurEvent) { + focusFieldAt(invalidFieldIndex); + return; + } + + if (event->isMouseEvent()) { + handleMouseEvent(static_cast<MouseEvent*>(event)); + } else if (event->isKeyboardEvent()) + handleKeyboardEvent(static_cast<KeyboardEvent*>(event)); + + if (event->defaultHandled()) + return; + + DateTimeFieldElement* const focusField = fieldAt(m_focusFieldIndex); + if (!focusField) + return; + + focusField->defaultEventHandler(event); +} + +void DateTimeEditElement::setValueAsDate(const DateComponents& date) +{ + for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) + m_fields[fieldIndex]->setValueAsDate(date); +} + +void DateTimeEditElement::setEmptyValue(const DateComponents& dateForReadOnlyField) +{ + for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) + m_fields[fieldIndex]->setEmptyValue(dateForReadOnlyField, DateTimeFieldElement::DispatchNoEvent); +} + +void DateTimeEditElement::spinButtonStepDown() +{ + if (DateTimeFieldElement* const focusField = fieldAt(m_focusFieldIndex)) + focusField->stepDown(); +} + +void DateTimeEditElement::spinButtonStepUp() +{ + if (DateTimeFieldElement* const focusField = fieldAt(m_focusFieldIndex)) + focusField->stepUp(); +} + +void DateTimeEditElement::updateUIState() +{ + if (isDisabled() || isReadOnly()) { + m_spinButton->releaseCapture(); + focusFieldAt(invalidFieldIndex); + } +} + +double DateTimeEditElement::valueAsDouble() const +{ + double value = 0; + + for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) { + const DateTimeFieldElement* const field = m_fields[fieldIndex]; + if (!field->hasValue()) + return std::numeric_limits<double>::quiet_NaN(); + value += field->valueAsDouble(); + } + + return value; +} + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/html/shadow/DateTimeEditElement.h b/Source/WebCore/html/shadow/DateTimeEditElement.h new file mode 100644 index 000000000..462faa4a6 --- /dev/null +++ b/Source/WebCore/html/shadow/DateTimeEditElement.h @@ -0,0 +1,117 @@ +/* + * 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 DateTimeEditElement_h +#define DateTimeEditElement_h + +#if ENABLE(INPUT_TYPE_TIME_MULTIPLE_FIELDS) +#include "DateTimeFieldElement.h" +#include "TextControlInnerElements.h" + +namespace WebCore { + +class DateComponents; +class DateTimeEditLayouter; +class KeyboardEvent; +class MouseEvent; +class StepRange; + +// DateTimeEditElement class contains numberic field and symbolc field for +// representing date and time, such as +// - Year, Month, Day Of Month +// - Hour, Minute, Second, Millisecond, AM/PM +class DateTimeEditElement : public HTMLDivElement, public DateTimeFieldElement::FieldEventHandler, private SpinButtonElement::StepActionHandler { + WTF_MAKE_NONCOPYABLE(DateTimeEditElement); + +public: + // EditControlOwner implementer must call removeEditControlOwner when + // it doesn't handle event, e.g. at destruction. + class EditControlOwner { + public: + virtual ~EditControlOwner(); + virtual void editControlMouseFocus() = 0; + virtual void editControlValueChanged() = 0; + virtual bool isEditControlOwnerDisabled() const = 0; + virtual bool isEditControlOwnerReadOnly() const = 0; + }; + + static PassRefPtr<DateTimeEditElement> create(Document*, EditControlOwner&, const StepRange&); + + virtual ~DateTimeEditElement(); + void addField(PassRefPtr<DateTimeFieldElement>); + virtual void defaultEventHandler(Event*) OVERRIDE; + void disabledStateChanged(); + void layout(const StepRange&); + void readOnlyStateChanged(); + void removeEditControlOwner() { m_editControlOwner = 0; } + void resetLayout(); + void setEmptyValue(const DateComponents& dateForReadOnlyField); + void setValueAsDate(const DateComponents&); + double valueAsDouble() const; + +private: + static const size_t invalidFieldIndex = static_cast<size_t>(-1); + + // Datetime can be represent at most five fields, such as + // 1. year + // 2. month + // 3. day-of-month + // 4. hour + // 5. minute + // 6. second + // 7. millisecond + // 8. AM/PM + static const int maximumNumberOfFields = 8; + + DateTimeEditElement(Document*, EditControlOwner&); + + DateTimeFieldElement* fieldAt(size_t) const; + void focusFieldAt(size_t); + void handleKeyboardEvent(KeyboardEvent*); + void handleMouseEvent(MouseEvent*); + bool isDisabled() const; + bool isReadOnly() const; + size_t nextFieldIndex() const; + size_t previousFieldIndex() const; + void updateUIState(); + + // DateTimeFieldElement::FieldEventHandler functions. + virtual void fieldValueChanged() OVERRIDE FINAL; + virtual void focusOnNextField() OVERRIDE FINAL; + + // SpinButtonElement::StepActionHandler functions. + virtual void spinButtonStepDown() OVERRIDE FINAL; + virtual void spinButtonStepUp() OVERRIDE FINAL; + + Vector<DateTimeFieldElement*, maximumNumberOfFields> m_fields; + EditControlOwner* m_editControlOwner; + SpinButtonElement* m_spinButton; + size_t m_focusFieldIndex; +}; + +} // namespace WebCore + +#endif +#endif diff --git a/Source/WebCore/html/shadow/DateTimeFieldElement.cpp b/Source/WebCore/html/shadow/DateTimeFieldElement.cpp new file mode 100644 index 000000000..702e4900c --- /dev/null +++ b/Source/WebCore/html/shadow/DateTimeFieldElement.cpp @@ -0,0 +1,136 @@ +/* + * 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 "DateTimeFieldElement.h" + +#include "DateComponents.h" +#include "HTMLNames.h" +#include "KeyboardEvent.h" +#include "Text.h" + +namespace WebCore { + +using namespace HTMLNames; + +DateTimeFieldElement::FieldEventHandler::~FieldEventHandler() +{ +} + +DateTimeFieldElement::DateTimeFieldElement(Document* document, FieldEventHandler& fieldEventHandler) + : HTMLElement(spanTag, document) + , m_fieldEventHandler(&fieldEventHandler) +{ +} + +void DateTimeFieldElement::defaultEventHandler(Event* event) +{ + if (event->isKeyboardEvent()) { + KeyboardEvent* keyboardEvent = static_cast<KeyboardEvent*>(event); + handleKeyboardEvent(keyboardEvent); + if (keyboardEvent->defaultHandled()) + return; + defaultKeyboardEventHandler(keyboardEvent); + if (keyboardEvent->defaultHandled()) + return; + } + + HTMLElement::defaultEventHandler(event); +} + +void DateTimeFieldElement::defaultKeyboardEventHandler(KeyboardEvent* keyboardEvent) +{ + if (keyboardEvent->type() != eventNames().keydownEvent) + return; + + const String& keyIdentifier = keyboardEvent->keyIdentifier(); + + if (keyIdentifier == "Down") { + keyboardEvent->setDefaultHandled(); + stepDown(); + return; + } + + if (keyIdentifier == "Up") { + keyboardEvent->setDefaultHandled(); + stepUp(); + return; + } + + if (keyIdentifier == "U+0008") { + keyboardEvent->setDefaultHandled(); + setEmptyValue(DateComponents(), DispatchEvent); + return; + } +} + +void DateTimeFieldElement::focusOnNextField() +{ + if (m_fieldEventHandler) + m_fieldEventHandler->focusOnNextField(); +} + +void DateTimeFieldElement::initialize(const AtomicString& shadowPseudoId) +{ + setShadowPseudoId(shadowPseudoId); + appendChild(Text::create(document(), visibleValue())); +} + +bool DateTimeFieldElement::isReadOnly() const +{ + return fastHasAttribute(readonlyAttr); +} + +void DateTimeFieldElement::setReadOnly() +{ + // Set HTML attribute readonly to change apperance. + setBooleanAttribute(readonlyAttr, true); + setNeedsStyleRecalc(); +} + +void DateTimeFieldElement::updateVisibleValue(EventBehavior eventBehavior) +{ + Text* const textNode = toText(firstChild()); + const String newVisibleValue = visibleValue(); + ASSERT(newVisibleValue.length() > 0); + + if (textNode->wholeText() == newVisibleValue) + return; + + textNode->replaceWholeText(newVisibleValue, ASSERT_NO_EXCEPTION); + + if (eventBehavior == DispatchEvent && m_fieldEventHandler) + m_fieldEventHandler->fieldValueChanged(); +} + +double DateTimeFieldElement::valueAsDouble() const +{ + return hasValue() ? valueAsInteger() * unitInMillisecond() : std::numeric_limits<double>::quiet_NaN(); +} + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/html/shadow/DateTimeFieldElement.h b/Source/WebCore/html/shadow/DateTimeFieldElement.h new file mode 100644 index 000000000..066b61ffa --- /dev/null +++ b/Source/WebCore/html/shadow/DateTimeFieldElement.h @@ -0,0 +1,88 @@ +/* + * 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 DateTimeFieldElement_h +#define DateTimeFieldElement_h + +#if ENABLE(INPUT_TYPE_TIME_MULTIPLE_FIELDS) + +#include "HTMLDivElement.h" + +namespace WebCore { + +class DateComponents; + +// DateTimeFieldElement is base class of date time field element. +class DateTimeFieldElement : public HTMLElement { + WTF_MAKE_NONCOPYABLE(DateTimeFieldElement); + +public: + enum EventBehavior { + DispatchNoEvent, + DispatchEvent, + }; + + // FieldEventHandler implementer must call removeEventHandler when + // it doesn't handle event, e.g. at destruction. + class FieldEventHandler { + public: + virtual ~FieldEventHandler(); + virtual void fieldValueChanged() = 0; + virtual void focusOnNextField() = 0; + }; + + virtual void defaultEventHandler(Event*) OVERRIDE; + virtual bool hasValue() const = 0; + bool isReadOnly() const; + void removeEventHandler() { m_fieldEventHandler = 0; } + void setReadOnly(); + virtual void setEmptyValue(const DateComponents& dateForReadOnlyField, EventBehavior = DispatchNoEvent) = 0; + virtual void setValueAsDate(const DateComponents&) = 0; + virtual void setValueAsInteger(int, EventBehavior = DispatchNoEvent) = 0; + virtual void stepDown() = 0; + virtual void stepUp() = 0; + virtual String value() const = 0; + double valueAsDouble() const; + virtual int valueAsInteger() const = 0; + virtual String visibleValue() const = 0; + +protected: + DateTimeFieldElement(Document*, FieldEventHandler&); + void focusOnNextField(); + virtual void handleKeyboardEvent(KeyboardEvent*) = 0; + void initialize(const AtomicString&); + virtual double unitInMillisecond() const = 0; + void updateVisibleValue(EventBehavior); + +private: + void defaultKeyboardEventHandler(KeyboardEvent*); + + FieldEventHandler* m_fieldEventHandler; +}; + +} // namespace WebCore + +#endif +#endif diff --git a/Source/WebCore/html/shadow/DateTimeFieldElements.cpp b/Source/WebCore/html/shadow/DateTimeFieldElements.cpp new file mode 100644 index 000000000..1ff7fa5c7 --- /dev/null +++ b/Source/WebCore/html/shadow/DateTimeFieldElements.cpp @@ -0,0 +1,173 @@ +/* + * 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 "DateTimeFieldElements.h" + +#include "DateComponents.h" +#include <wtf/DateMath.h> + +namespace WebCore { + +DateTimeAMPMFieldElement::DateTimeAMPMFieldElement(Document* document, FieldEventHandler& fieldEventHandler, const Vector<String>& ampmLabels) + : DateTimeSymbolicFieldElement(document, fieldEventHandler, ampmLabels) +{ +} + +PassRefPtr<DateTimeAMPMFieldElement> DateTimeAMPMFieldElement::create(Document* document, FieldEventHandler& fieldEventHandler, const Vector<String>& ampmLabels) +{ + DEFINE_STATIC_LOCAL(AtomicString, ampmPsuedoId, ("-webkit-datetime-edit-ampm-field")); + RefPtr<DateTimeAMPMFieldElement> field = adoptRef(new DateTimeAMPMFieldElement(document, fieldEventHandler, ampmLabels)); + field->initialize(ampmPsuedoId); + return field.release(); +} + +void DateTimeAMPMFieldElement::setValueAsDate(const DateComponents& date) +{ + setValueAsInteger(date.hour() >= 12 ? 1 : 0); +} + +double DateTimeAMPMFieldElement::unitInMillisecond() const +{ + return msPerHour * 12; +} + +// ---------------------------- + +DateTimeHourFieldElement::DateTimeHourFieldElement(Document* document, FieldEventHandler& fieldEventHandler, int minimum, int maximum) + : DateTimeNumericFieldElement(document, fieldEventHandler, minimum, maximum) + , m_alignment(maximum + maximum % 2) +{ + ASSERT((!minimum && (maximum == 11 || maximum == 23)) || (minimum == 1 && (maximum == 12 || maximum == 24))); +} + +PassRefPtr<DateTimeHourFieldElement> DateTimeHourFieldElement::create(Document* document, FieldEventHandler& fieldEventHandler, int minimum, int maximum) +{ + DEFINE_STATIC_LOCAL(AtomicString, hourPsuedoId, ("-webkit-datetime-edit-hour-field")); + RefPtr<DateTimeHourFieldElement> field = adoptRef(new DateTimeHourFieldElement(document, fieldEventHandler, minimum, maximum)); + field->initialize(hourPsuedoId); + return field.release(); +} + +void DateTimeHourFieldElement::setValueAsDate(const DateComponents& date) +{ + setValueAsInteger(date.hour()); +} + +void DateTimeHourFieldElement::setValueAsInteger(int valueAsHour23, EventBehavior eventBehavior) +{ + const int value = Range(0, 23).clampValue(valueAsHour23) % m_alignment; + DateTimeNumericFieldElement::setValueAsInteger(range().minimum && !value ? m_alignment : value, eventBehavior); +} + +double DateTimeHourFieldElement::unitInMillisecond() const +{ + return msPerHour; +} + +int DateTimeHourFieldElement::valueAsInteger() const +{ + return hasValue() ? DateTimeNumericFieldElement::valueAsInteger() % m_alignment : -1; +} + +// ---------------------------- + +DateTimeMillisecondFieldElement::DateTimeMillisecondFieldElement(Document* document, FieldEventHandler& fieldEventHandler) + : DateTimeNumericFieldElement(document, fieldEventHandler, 0, 999) +{ +} + +PassRefPtr<DateTimeMillisecondFieldElement> DateTimeMillisecondFieldElement::create(Document* document, FieldEventHandler& fieldEventHandler) +{ + DEFINE_STATIC_LOCAL(AtomicString, millisecondPsuedoId, ("-webkit-datetime-edit-millisecond-field")); + RefPtr<DateTimeMillisecondFieldElement> field = adoptRef(new DateTimeMillisecondFieldElement(document, fieldEventHandler)); + field->initialize(millisecondPsuedoId); + return field.release(); +} + +void DateTimeMillisecondFieldElement::setValueAsDate(const DateComponents& date) +{ + setValueAsInteger(date.millisecond()); +} + +double DateTimeMillisecondFieldElement::unitInMillisecond() const +{ + return 1; +} + +// ---------------------------- + +DateTimeMinuteFieldElement::DateTimeMinuteFieldElement(Document* document, FieldEventHandler& fieldEventHandler) + : DateTimeNumericFieldElement(document, fieldEventHandler, 0, 59) +{ +} + +PassRefPtr<DateTimeMinuteFieldElement> DateTimeMinuteFieldElement::create(Document* document, FieldEventHandler& fieldEventHandler) +{ + DEFINE_STATIC_LOCAL(AtomicString, minutePsuedoId, ("-webkit-datetime-edit-minute-field")); + RefPtr<DateTimeMinuteFieldElement> field = adoptRef(new DateTimeMinuteFieldElement(document, fieldEventHandler)); + field->initialize(minutePsuedoId); + return field.release(); +} + +void DateTimeMinuteFieldElement::setValueAsDate(const DateComponents& date) +{ + setValueAsInteger(date.minute()); +} + +double DateTimeMinuteFieldElement::unitInMillisecond() const +{ + return msPerMinute; +} + +// ---------------------------- + +DateTimeSecondFieldElement::DateTimeSecondFieldElement(Document* document, FieldEventHandler& fieldEventHandler) + : DateTimeNumericFieldElement(document, fieldEventHandler, 0, 59) +{ +} + +PassRefPtr<DateTimeSecondFieldElement> DateTimeSecondFieldElement::create(Document* document, FieldEventHandler& fieldEventHandler) +{ + DEFINE_STATIC_LOCAL(AtomicString, secondPsuedoId, ("-webkit-datetime-edit-second-field")); + RefPtr<DateTimeSecondFieldElement> field = adoptRef(new DateTimeSecondFieldElement(document, fieldEventHandler)); + field->initialize(secondPsuedoId); + return field.release(); +} + +void DateTimeSecondFieldElement::setValueAsDate(const DateComponents& date) +{ + setValueAsInteger(date.second()); +} + +double DateTimeSecondFieldElement::unitInMillisecond() const +{ + return msPerSecond; +} + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/html/shadow/DateTimeFieldElements.h b/Source/WebCore/html/shadow/DateTimeFieldElements.h new file mode 100644 index 000000000..57bc1efa5 --- /dev/null +++ b/Source/WebCore/html/shadow/DateTimeFieldElements.h @@ -0,0 +1,119 @@ +/* + * 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 DateTimeFieldElements_h +#define DateTimeFieldElements_h + +#if ENABLE(INPUT_TYPE_TIME_MULTIPLE_FIELDS) +#include "DateTimeNumericFieldElement.h" +#include "DateTimeSymbolicFieldElement.h" + +namespace WebCore { + +class DateTimeAMPMFieldElement : public DateTimeSymbolicFieldElement { + WTF_MAKE_NONCOPYABLE(DateTimeAMPMFieldElement); + +public: + static PassRefPtr<DateTimeAMPMFieldElement> create(Document*, FieldEventHandler&, const Vector<String>&); + +private: + DateTimeAMPMFieldElement(Document*, FieldEventHandler&, const Vector<String>&); + + // DateTimeFieldElement functions. + virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL; + virtual double unitInMillisecond() const OVERRIDE FINAL; +}; + + +// DateTimeHourFieldElement is used for hour field of date time format +// supporting following patterns: +// - 0 to 11 +// - 1 to 12 +// - 0 to 23 +// - 1 to 24 +class DateTimeHourFieldElement : public DateTimeNumericFieldElement { + WTF_MAKE_NONCOPYABLE(DateTimeHourFieldElement); + +public: + static PassRefPtr<DateTimeHourFieldElement> create(Document*, FieldEventHandler&, int minimum, int maximum); + +private: + DateTimeHourFieldElement(Document*, FieldEventHandler&, int minimum, int maximum); + + // DateTimeFieldElement functions. + virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL; + virtual void setValueAsInteger(int, EventBehavior = DispatchNoEvent) OVERRIDE FINAL; + virtual double unitInMillisecond() const OVERRIDE FINAL; + virtual int valueAsInteger() const OVERRIDE FINAL; + + const int m_alignment; +}; + +class DateTimeMillisecondFieldElement : public DateTimeNumericFieldElement { + WTF_MAKE_NONCOPYABLE(DateTimeMillisecondFieldElement); + +public: + static PassRefPtr<DateTimeMillisecondFieldElement> create(Document*, FieldEventHandler&); + +private: + DateTimeMillisecondFieldElement(Document*, FieldEventHandler&); + + // DateTimeFieldElement functions. + virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL; + virtual double unitInMillisecond() const OVERRIDE FINAL; +}; + +class DateTimeMinuteFieldElement : public DateTimeNumericFieldElement { + WTF_MAKE_NONCOPYABLE(DateTimeMinuteFieldElement); + +public: + static PassRefPtr<DateTimeMinuteFieldElement> create(Document*, FieldEventHandler&); + +private: + DateTimeMinuteFieldElement(Document*, FieldEventHandler&); + + // DateTimeFieldElement functions. + virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL; + virtual double unitInMillisecond() const OVERRIDE FINAL; +}; + +class DateTimeSecondFieldElement : public DateTimeNumericFieldElement { + WTF_MAKE_NONCOPYABLE(DateTimeSecondFieldElement); + +public: + static PassRefPtr<DateTimeSecondFieldElement> create(Document*, FieldEventHandler&); + +private: + DateTimeSecondFieldElement(Document*, FieldEventHandler&); + + // DateTimeFieldElement functions. + virtual void setValueAsDate(const DateComponents&) OVERRIDE FINAL; + virtual double unitInMillisecond() const OVERRIDE FINAL; +}; + +} // namespace WebCore + +#endif +#endif diff --git a/Source/WebCore/html/shadow/DateTimeNumericFieldElement.cpp b/Source/WebCore/html/shadow/DateTimeNumericFieldElement.cpp new file mode 100644 index 000000000..d522e1579 --- /dev/null +++ b/Source/WebCore/html/shadow/DateTimeNumericFieldElement.cpp @@ -0,0 +1,178 @@ +/* + * 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 "DateTimeNumericFieldElement.h" + +#include "KeyboardEvent.h" +#include "LocalizedNumber.h" +#include <wtf/text/StringBuilder.h> + +namespace WebCore { + +static const DOMTimeStamp typeAheadTimeout = 1000; + +static size_t displaySizeOfNumber(int value) +{ + ASSERT(value >= 0); + + if (!value) + return 1; + + int numberOfDigits = 0; + while (value) { + value /= 10; + ++numberOfDigits; + } + + return numberOfDigits; +} + +DateTimeNumericFieldElement::Range::Range(int minimum, int maximum) + : maximum(maximum) + , minimum(minimum) +{ + ASSERT(minimum <= maximum); +} + +int DateTimeNumericFieldElement::Range::clampValue(int value) const +{ + return std::min(std::max(value, minimum), maximum); +} + +DateTimeNumericFieldElement::DateTimeNumericFieldElement(Document* document, FieldEventHandler& fieldEventHandler, int minimum, int maximum) + : DateTimeFieldElement(document, fieldEventHandler) + , m_lastDigitCharTime(0) + , m_range(minimum, maximum) + , m_value(0) + , m_hasValue(false) +{ +} + +void DateTimeNumericFieldElement::handleKeyboardEvent(KeyboardEvent* keyboardEvent) +{ + if (isReadOnly()) + return; + + if (keyboardEvent->type() != eventNames().keypressEvent) + return; + + UChar charCode = static_cast<UChar>(keyboardEvent->charCode()); + if (charCode < ' ') + return; + + DOMTimeStamp delta = keyboardEvent->timeStamp() - m_lastDigitCharTime; + m_lastDigitCharTime = 0; + + String number = convertFromLocalizedNumber(String(&charCode, 1)); + const int digit = number[0] - '0'; + if (digit < 0 || digit > 9) + return; + + keyboardEvent->setDefaultHandled(); + setValueAsInteger(m_hasValue && delta < typeAheadTimeout ? m_value * 10 + digit : digit, DispatchEvent); + if (m_value * 10 > m_range.maximum) + focusOnNextField(); + else + m_lastDigitCharTime = keyboardEvent->timeStamp(); +} + +bool DateTimeNumericFieldElement::hasValue() const +{ + return m_hasValue; +} + +void DateTimeNumericFieldElement::setEmptyValue(const DateComponents& dateForReadOnlyField, EventBehavior eventBehavior) +{ + m_lastDigitCharTime = 0; + + if (isReadOnly()) { + setValueAsDate(dateForReadOnlyField); + return; + } + + m_hasValue = false; + m_value = 0; + updateVisibleValue(eventBehavior); +} + +void DateTimeNumericFieldElement::setValueAsInteger(int value, EventBehavior eventBehavior) +{ + m_value = clampValue(value); + m_hasValue = true; + updateVisibleValue(eventBehavior); + m_lastDigitCharTime = 0; +} + +void DateTimeNumericFieldElement::stepDown() +{ + if (m_hasValue) + setValueAsInteger(m_value == m_range.minimum ? m_range.maximum : clampValue(m_value - 1), DispatchEvent); + else + setValueAsInteger(m_range.maximum, DispatchEvent); +} + +void DateTimeNumericFieldElement::stepUp() +{ + if (m_hasValue) + setValueAsInteger(m_value == m_range.maximum ? m_range.minimum : clampValue(m_value + 1), DispatchEvent); + else + setValueAsInteger(m_range.minimum, DispatchEvent); +} + +String DateTimeNumericFieldElement::value() const +{ + if (!m_hasValue) + return emptyString(); + + if (m_range.maximum > 999) + return convertToLocalizedNumber(String::number(m_value)); + + if (m_range.maximum > 99) + return convertToLocalizedNumber(String::format("%03d", m_value)); + + return convertToLocalizedNumber(String::format("%02d", m_value)); +} + +int DateTimeNumericFieldElement::valueAsInteger() const +{ + return m_hasValue ? m_value : -1; +} + +String DateTimeNumericFieldElement::visibleValue() const +{ + if (m_hasValue) + return value(); + + StringBuilder builder; + for (int numberOfDashs = std::max(displaySizeOfNumber(m_range.maximum), displaySizeOfNumber(m_range.minimum)); numberOfDashs; --numberOfDashs) + builder.append('-'); + return builder.toString(); +} + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/html/shadow/DateTimeNumericFieldElement.h b/Source/WebCore/html/shadow/DateTimeNumericFieldElement.h new file mode 100644 index 000000000..7cb398250 --- /dev/null +++ b/Source/WebCore/html/shadow/DateTimeNumericFieldElement.h @@ -0,0 +1,81 @@ +/* + * 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 DateTimeNumericFieldElement_h +#define DateTimeNumericFieldElement_h + +#if ENABLE(INPUT_TYPE_TIME_MULTIPLE_FIELDS) +#include "DateTimeFieldElement.h" + +namespace WebCore { + +// DateTimeNumericFieldElement represents numeric field of date time format, +// such as: +// - hour +// - minute +// - millisecond +// - second +// - year +class DateTimeNumericFieldElement : public DateTimeFieldElement { + WTF_MAKE_NONCOPYABLE(DateTimeNumericFieldElement); + +protected: + struct Range { + Range(int minimum, int maximum); + int clampValue(int) const; + + int maximum; + int minimum; + }; + + DateTimeNumericFieldElement(Document*, FieldEventHandler&, int minimum, int maximum); + + int clampValue(int value) const { return m_range.clampValue(value); } + const Range& range() const { return m_range; } + + // DateTimeFieldElement functions. + virtual bool hasValue() const OVERRIDE FINAL; + virtual void setValueAsInteger(int, EventBehavior = DispatchNoEvent) OVERRIDE; + virtual int valueAsInteger() const OVERRIDE; + virtual String visibleValue() const OVERRIDE FINAL; + +private: + // DateTimeFieldElement functions. + virtual void handleKeyboardEvent(KeyboardEvent*) OVERRIDE FINAL; + virtual void setEmptyValue(const DateComponents& dateForReadOnlyField, EventBehavior) OVERRIDE FINAL; + virtual void stepDown() OVERRIDE FINAL; + virtual void stepUp() OVERRIDE FINAL; + virtual String value() const OVERRIDE FINAL; + + DOMTimeStamp m_lastDigitCharTime; + const Range m_range; + int m_value; + bool m_hasValue; +}; + +} // namespace WebCore + +#endif +#endif diff --git a/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.cpp b/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.cpp new file mode 100644 index 000000000..08eb52229 --- /dev/null +++ b/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.cpp @@ -0,0 +1,108 @@ +/* + * 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 "DateTimeSymbolicFieldElement.h" + +#include "KeyboardEvent.h" +#include <wtf/unicode/Unicode.h> + +namespace WebCore { + +DateTimeSymbolicFieldElement::DateTimeSymbolicFieldElement(Document* document, FieldEventHandler& fieldEventHandler, const Vector<String>& symbols) + : DateTimeFieldElement(document, fieldEventHandler) + , m_symbols(symbols) + , m_selectedIndex(-1) +{ + ASSERT(!symbols.isEmpty()); +} + +void DateTimeSymbolicFieldElement::handleKeyboardEvent(KeyboardEvent* keyboardEvent) +{ + if (keyboardEvent->type() != eventNames().keypressEvent) + return; + + const UChar charCode = WTF::Unicode::toLower(keyboardEvent->charCode()); + if (charCode < ' ') + return; + + keyboardEvent->setDefaultHandled(); + for (unsigned index = 0; index < m_symbols.size(); ++index) { + if (!m_symbols[index].isEmpty() && WTF::Unicode::toLower(m_symbols[index][0]) == charCode) { + setValueAsInteger(index, DispatchEvent); + return; + } + } +} + +bool DateTimeSymbolicFieldElement::hasValue() const +{ + return m_selectedIndex >= 0; +} + +void DateTimeSymbolicFieldElement::setEmptyValue(const DateComponents&, EventBehavior eventBehavior) +{ + m_selectedIndex = invalidIndex; + updateVisibleValue(eventBehavior); +} + +void DateTimeSymbolicFieldElement::setValueAsInteger(int newSelectedIndex, EventBehavior eventBehavior) +{ + m_selectedIndex = std::max(0, std::min(newSelectedIndex, static_cast<int>(m_symbols.size() - 1))); + updateVisibleValue(eventBehavior); +} + +void DateTimeSymbolicFieldElement::stepDown() +{ + const int size = m_symbols.size(); + m_selectedIndex = hasValue() ? (m_selectedIndex + size - 1) % size : size - 1; + updateVisibleValue(DispatchEvent); +} + +void DateTimeSymbolicFieldElement::stepUp() +{ + m_selectedIndex = hasValue() ? (m_selectedIndex + 1) % m_symbols.size() : 0; + updateVisibleValue(DispatchEvent); +} + +String DateTimeSymbolicFieldElement::value() const +{ + return hasValue() ? m_symbols[m_selectedIndex] : emptyString(); +} + +int DateTimeSymbolicFieldElement::valueAsInteger() const +{ + return m_selectedIndex; +} + +String DateTimeSymbolicFieldElement::visibleValue() const +{ + return hasValue() ? m_symbols[m_selectedIndex] : "--"; +} + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.h b/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.h new file mode 100644 index 000000000..8329dd114 --- /dev/null +++ b/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.h @@ -0,0 +1,63 @@ +/* + * 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 DateTimeSymbolicFieldElement_h +#define DateTimeSymbolicFieldElement_h + +#if ENABLE(INPUT_TYPE_TIME_MULTIPLE_FIELDS) +#include "DateTimeFieldElement.h" + +namespace WebCore { + +// DateTimeSymbolicFieldElement represents non-numeric field of data time +// format, such as: AM/PM, and month. +class DateTimeSymbolicFieldElement : public DateTimeFieldElement { + WTF_MAKE_NONCOPYABLE(DateTimeSymbolicFieldElement); + +protected: + DateTimeSymbolicFieldElement(Document*, FieldEventHandler&, const Vector<String>&); + virtual void setValueAsInteger(int, EventBehavior = DispatchNoEvent) OVERRIDE FINAL; + +private: + static const int invalidIndex = -1; + + // 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 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; + int m_selectedIndex; +}; + +} // namespace WebCore + +#endif +#endif diff --git a/Source/WebCore/html/shadow/InsertionPoint.cpp b/Source/WebCore/html/shadow/InsertionPoint.cpp index fadbb457b..435796677 100644 --- a/Source/WebCore/html/shadow/InsertionPoint.cpp +++ b/Source/WebCore/html/shadow/InsertionPoint.cpp @@ -118,8 +118,10 @@ Node::InsertionNotificationRequest InsertionPoint::insertedInto(ContainerNode* i { HTMLElement::insertedInto(insertionPoint); if (insertionPoint->inDocument()) { - if (ShadowRoot* root = shadowRoot()) - root->owner()->invalidateDistribution(ElementShadow::InvalidateAndForceReattach); + if (ShadowRoot* root = shadowRoot()) { + root->owner()->setValidityUndetermined(); + root->owner()->invalidateDistribution(); + } } return InsertionDone; diff --git a/Source/WebCore/html/shadow/MediaControlElements.cpp b/Source/WebCore/html/shadow/MediaControlElements.cpp index 2c4bd9e91..1b67afec3 100644 --- a/Source/WebCore/html/shadow/MediaControlElements.cpp +++ b/Source/WebCore/html/shadow/MediaControlElements.cpp @@ -388,7 +388,6 @@ void MediaControlVolumeSliderContainerElement::defaultEventHandler(Event* event) hide(); } - MediaControlElementType MediaControlVolumeSliderContainerElement::displayType() const { return MediaVolumeSliderContainer; @@ -924,7 +923,15 @@ void MediaControlTimelineElement::defaultEventHandler(Event* event) m_controls->updateTimeDisplay(); } -void MediaControlTimelineElement::setPosition(float currentTime) +bool MediaControlTimelineElement::willRespondToMouseClickEvents() +{ + if (!attached()) + return false; + + return true; +} + +void MediaControlTimelineElement::setPosition(float currentTime) { setValue(String::number(currentTime)); } @@ -983,6 +990,22 @@ void MediaControlVolumeSliderElement::defaultEventHandler(Event* event) mediaController()->setMuted(false); } +bool MediaControlVolumeSliderElement::willRespondToMouseMoveEvents() +{ + if (!attached()) + return false; + + return MediaControlInputElement::willRespondToMouseMoveEvents(); +} + +bool MediaControlVolumeSliderElement::willRespondToMouseClickEvents() +{ + if (!attached()) + return false; + + return MediaControlInputElement::willRespondToMouseClickEvents(); +} + void MediaControlVolumeSliderElement::setVolume(float volume) { if (value().toFloat() != volume) diff --git a/Source/WebCore/html/shadow/MediaControlElements.h b/Source/WebCore/html/shadow/MediaControlElements.h index c1514e231..effdcee7f 100644 --- a/Source/WebCore/html/shadow/MediaControlElements.h +++ b/Source/WebCore/html/shadow/MediaControlElements.h @@ -116,6 +116,9 @@ public: void makeOpaque(); void makeTransparent(); + virtual bool willRespondToMouseMoveEvents() OVERRIDE { return true; } + virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; } + private: MediaControlPanelElement(Document*); virtual MediaControlElementType displayType() const; @@ -160,6 +163,8 @@ class MediaControlVolumeSliderContainerElement : public MediaControlElement { public: static PassRefPtr<MediaControlVolumeSliderContainerElement> create(Document*); + virtual bool willRespondToMouseMoveEvents() OVERRIDE { return true; } + private: MediaControlVolumeSliderContainerElement(Document*); virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); @@ -218,11 +223,12 @@ class MediaControlMuteButtonElement : public MediaControlInputElement { public: void changedMute(); + virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; } + protected: MediaControlMuteButtonElement(Document*, MediaControlElementType); virtual void defaultEventHandler(Event*); - private: virtual void updateDisplayType(); }; @@ -233,6 +239,8 @@ class MediaControlPanelMuteButtonElement : public MediaControlMuteButtonElement public: static PassRefPtr<MediaControlPanelMuteButtonElement> create(Document*, MediaControls*); + virtual bool willRespondToMouseMoveEvents() OVERRIDE { return true; } + private: MediaControlPanelMuteButtonElement(Document*, MediaControls*); @@ -262,6 +270,7 @@ public: static PassRefPtr<MediaControlPlayButtonElement> create(Document*); virtual void defaultEventHandler(Event*); + virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; } virtual void updateDisplayType(); private: @@ -289,6 +298,7 @@ private: class MediaControlSeekButtonElement : public MediaControlInputElement { public: virtual void defaultEventHandler(Event*); + virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; } protected: MediaControlSeekButtonElement(Document*, MediaControlElementType); @@ -342,6 +352,7 @@ public: static PassRefPtr<MediaControlRewindButtonElement> create(Document*); virtual void defaultEventHandler(Event*); + virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; } private: MediaControlRewindButtonElement(Document*); @@ -356,6 +367,7 @@ public: static PassRefPtr<MediaControlReturnToRealtimeButtonElement> create(Document*); virtual void defaultEventHandler(Event*); + virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; } private: MediaControlReturnToRealtimeButtonElement(Document*); @@ -370,6 +382,7 @@ public: static PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> create(Document*); virtual void defaultEventHandler(Event*); + virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; } virtual void updateDisplayType(); private: @@ -385,6 +398,7 @@ public: static PassRefPtr<MediaControlTimelineElement> create(Document*, MediaControls*); virtual void defaultEventHandler(Event*); + virtual bool willRespondToMouseClickEvents() OVERRIDE; void setPosition(float); void setDuration(float); @@ -403,6 +417,8 @@ public: static PassRefPtr<MediaControlVolumeSliderElement> create(Document*); virtual void defaultEventHandler(Event*); + virtual bool willRespondToMouseMoveEvents() OVERRIDE; + virtual bool willRespondToMouseClickEvents() OVERRIDE; void setVolume(float); void setClearMutedOnUserInteraction(bool); @@ -421,6 +437,7 @@ public: static PassRefPtr<MediaControlFullscreenButtonElement> create(Document*, MediaControls*); virtual void defaultEventHandler(Event*); + virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; } void setIsFullscreen(bool); private: @@ -448,7 +465,8 @@ public: static PassRefPtr<MediaControlFullscreenVolumeMinButtonElement> create(Document*); virtual void defaultEventHandler(Event*); - + virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; } + private: MediaControlFullscreenVolumeMinButtonElement(Document*); @@ -462,7 +480,8 @@ public: static PassRefPtr<MediaControlFullscreenVolumeMaxButtonElement> create(Document*); virtual void defaultEventHandler(Event*); - + virtual bool willRespondToMouseClickEvents() OVERRIDE { return true; } + private: MediaControlFullscreenVolumeMaxButtonElement(Document*); diff --git a/Source/WebCore/html/shadow/MediaControlRootElement.h b/Source/WebCore/html/shadow/MediaControlRootElement.h index f9f475c2e..5ce6ac7ea 100644 --- a/Source/WebCore/html/shadow/MediaControlRootElement.h +++ b/Source/WebCore/html/shadow/MediaControlRootElement.h @@ -114,6 +114,8 @@ public: void bufferingProgressed(); + virtual bool willRespondToMouseMoveEvents() OVERRIDE { return true; } + private: MediaControlRootElement(Document*); diff --git a/Source/WebCore/html/shadow/ProgressShadowElement.cpp b/Source/WebCore/html/shadow/ProgressShadowElement.cpp index 800f22351..465d5ba8f 100644 --- a/Source/WebCore/html/shadow/ProgressShadowElement.cpp +++ b/Source/WebCore/html/shadow/ProgressShadowElement.cpp @@ -34,22 +34,20 @@ #if ENABLE(PROGRESS_ELEMENT) #include "HTMLNames.h" #include "HTMLProgressElement.h" -#include "RenderObject.h" +#include "RenderProgress.h" namespace WebCore { using namespace HTMLNames; -ProgressShadowElement::ProgressShadowElement(Document* document) +ProgressShadowElement::ProgressShadowElement(Document* document) : HTMLDivElement(HTMLNames::divTag, document) { } HTMLProgressElement* ProgressShadowElement::progressElement() const { - Element* element = shadowHost(); - ASSERT(!element || element->hasTagName(progressTag)); - return static_cast<HTMLProgressElement*>(element); + return toHTMLProgressElement(shadowHost()); } bool ProgressShadowElement::rendererIsNeeded(const NodeRenderingContext& context) @@ -58,6 +56,36 @@ bool ProgressShadowElement::rendererIsNeeded(const NodeRenderingContext& context return progressRenderer && !progressRenderer->style()->hasAppearance() && HTMLDivElement::rendererIsNeeded(context); } +ProgressInnerElement::ProgressInnerElement(Document* document) + : ProgressShadowElement(document) +{ +} + +PassRefPtr<ProgressInnerElement> ProgressInnerElement::create(Document* document) +{ + return adoptRef(new ProgressInnerElement(document)); +} + +const AtomicString& ProgressInnerElement::shadowPseudoId() const +{ + DEFINE_STATIC_LOCAL(AtomicString, pseudId, ("-webkit-progress-inner-element")); + return pseudId; +} + +RenderObject* ProgressInnerElement::createRenderer(RenderArena* arena, RenderStyle*) +{ + return new (arena) RenderProgress(this); +} + +bool ProgressInnerElement::rendererIsNeeded(const NodeRenderingContext& context) +{ + if (progressElement()->hasAuthorShadowRoot()) + return HTMLDivElement::rendererIsNeeded(context); + + RenderObject* progressRenderer = progressElement()->renderer(); + return progressRenderer && !progressRenderer->style()->hasAppearance() && HTMLDivElement::rendererIsNeeded(context); +} + const AtomicString& ProgressBarElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, pseudId, ("-webkit-progress-bar")); diff --git a/Source/WebCore/html/shadow/ProgressShadowElement.h b/Source/WebCore/html/shadow/ProgressShadowElement.h index aff94fba3..4d03e43ab 100644 --- a/Source/WebCore/html/shadow/ProgressShadowElement.h +++ b/Source/WebCore/html/shadow/ProgressShadowElement.h @@ -45,7 +45,18 @@ public: ProgressShadowElement(Document*); HTMLProgressElement* progressElement() const; +protected: + virtual bool rendererIsNeeded(const NodeRenderingContext&); +}; + +class ProgressInnerElement : public ProgressShadowElement { +public: + ProgressInnerElement(Document*); + + static PassRefPtr<ProgressInnerElement> create(Document*); private: + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) OVERRIDE; + virtual const AtomicString& shadowPseudoId() const; virtual bool rendererIsNeeded(const NodeRenderingContext&); }; @@ -65,7 +76,6 @@ inline PassRefPtr<ProgressBarElement> ProgressBarElement::create(Document* docum return adoptRef(new ProgressBarElement(document)); } - class ProgressValueElement : public ProgressShadowElement { public: ProgressValueElement(Document* document) diff --git a/Source/WebCore/html/shadow/SliderThumbElement.cpp b/Source/WebCore/html/shadow/SliderThumbElement.cpp index cccad81ef..baca86c7b 100644 --- a/Source/WebCore/html/shadow/SliderThumbElement.cpp +++ b/Source/WebCore/html/shadow/SliderThumbElement.cpp @@ -51,6 +51,8 @@ using namespace std; namespace WebCore { +using namespace HTMLNames; + inline static Decimal sliderPosition(HTMLInputElement* element) { const StepRange stepRange(element->createStepRange(RejectAny)); @@ -214,9 +216,14 @@ bool SliderThumbElement::isEnabledFormControl() const return hostInput()->isEnabledFormControl(); } -bool SliderThumbElement::isReadOnlyFormControl() const +bool SliderThumbElement::shouldMatchReadOnlySelector() const { - return hostInput()->isReadOnlyFormControl(); + return hostInput()->shouldMatchReadOnlySelector(); +} + +bool SliderThumbElement::shouldMatchReadWriteSelector() const +{ + return hostInput()->shouldMatchReadWriteSelector(); } Node* SliderThumbElement::focusDelegate() @@ -265,7 +272,21 @@ void SliderThumbElement::setPositionFromPoint(const LayoutPoint& point) const Decimal ratio = Decimal::fromDouble(static_cast<double>(position) / trackSize); const Decimal fraction = isVertical || !renderBox()->style()->isLeftToRightDirection() ? Decimal(1) - ratio : ratio; StepRange stepRange(input->createStepRange(RejectAny)); - const Decimal value = stepRange.clampValue(stepRange.valueFromProportion(fraction)); + Decimal value = stepRange.clampValue(stepRange.valueFromProportion(fraction)); + +#if ENABLE(DATALIST_ELEMENT) + const LayoutUnit snappingThreshold = renderer()->theme()->sliderTickSnappingThreshold(); + if (snappingThreshold > 0) { + Decimal closest = input->findClosestTickMarkValue(value); + if (closest.isFinite()) { + double closestFraction = stepRange.proportionFromValue(closest).toDouble(); + double closestRatio = isVertical || !renderBox()->style()->isLeftToRightDirection() ? 1.0 - closestFraction : closestFraction; + LayoutUnit closestPosition = trackSize * closestRatio; + if ((closestPosition - position).abs() <= snappingThreshold) + value = closest; + } + } +#endif // FIXME: This is no longer being set from renderer. Consider updating the method name. input->setValueFromRenderer(serializeForNumberType(value)); @@ -303,7 +324,7 @@ void SliderThumbElement::defaultEventHandler(Event* event) // FIXME: Should handle this readonly/disabled check in more general way. // Missing this kind of check is likely to occur elsewhere if adding it in each shadow element. HTMLInputElement* input = hostInput(); - if (!input || input->isReadOnlyFormControl() || !input->isEnabledFormControl()) { + if (!input || input->readOnly() || !input->isEnabledFormControl()) { stopDragging(); HTMLDivElement::defaultEventHandler(event); return; @@ -331,6 +352,24 @@ void SliderThumbElement::defaultEventHandler(Event* event) HTMLDivElement::defaultEventHandler(event); } +bool SliderThumbElement::willRespondToMouseMoveEvents() +{ + const HTMLInputElement* input = hostInput(); + if (input && !input->readOnly() && input->isEnabledFormControl() && m_inDragMode) + return true; + + return HTMLDivElement::willRespondToMouseMoveEvents(); +} + +bool SliderThumbElement::willRespondToMouseClickEvents() +{ + const HTMLInputElement* input = hostInput(); + if (input && !input->readOnly() && input->isEnabledFormControl()) + return true; + + return HTMLDivElement::willRespondToMouseClickEvents(); +} + void SliderThumbElement::detach() { if (m_inDragMode) { diff --git a/Source/WebCore/html/shadow/SliderThumbElement.h b/Source/WebCore/html/shadow/SliderThumbElement.h index 36d64186f..04e41c7bf 100644 --- a/Source/WebCore/html/shadow/SliderThumbElement.h +++ b/Source/WebCore/html/shadow/SliderThumbElement.h @@ -54,6 +54,8 @@ public: void dragFrom(const LayoutPoint&); virtual void defaultEventHandler(Event*); + virtual bool willRespondToMouseMoveEvents() OVERRIDE; + virtual bool willRespondToMouseClickEvents() OVERRIDE; virtual void detach(); virtual const AtomicString& shadowPseudoId() const; HTMLInputElement* hostInput() const; @@ -64,7 +66,8 @@ private: virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); virtual PassRefPtr<Element> cloneElementWithoutAttributesAndChildren(); virtual bool isEnabledFormControl() const; - virtual bool isReadOnlyFormControl() const; + virtual bool shouldMatchReadOnlySelector() const OVERRIDE; + virtual bool shouldMatchReadWriteSelector() const OVERRIDE; virtual Node* focusDelegate(); void startDragging(); void stopDragging(); diff --git a/Source/WebCore/html/shadow/TextControlInnerElements.cpp b/Source/WebCore/html/shadow/TextControlInnerElements.cpp index e3097bb5e..e06d56f2f 100644 --- a/Source/WebCore/html/shadow/TextControlInnerElements.cpp +++ b/Source/WebCore/html/shadow/TextControlInnerElements.cpp @@ -165,6 +165,11 @@ void SearchFieldResultsButtonElement::defaultEventHandler(Event* event) HTMLDivElement::defaultEventHandler(event); } +bool SearchFieldResultsButtonElement::willRespondToMouseClickEvents() +{ + return true; +} + // ---------------------------- inline SearchFieldCancelButtonElement::SearchFieldCancelButtonElement(Document* document) @@ -198,7 +203,7 @@ void SearchFieldCancelButtonElement::defaultEventHandler(Event* event) { // If the element is visible, on mouseup, clear the value, and set selection RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowHost())); - if (input->disabled() || input->isReadOnlyFormControl()) { + if (input->disabled() || input->readOnly()) { if (!event->defaultHandled()) HTMLDivElement::defaultEventHandler(event); return; @@ -234,6 +239,15 @@ void SearchFieldCancelButtonElement::defaultEventHandler(Event* event) HTMLDivElement::defaultEventHandler(event); } +bool SearchFieldCancelButtonElement::willRespondToMouseClickEvents() +{ + const HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowHost()); + if (!input->disabled() && !input->readOnly()) + return true; + + return HTMLDivElement::willRespondToMouseClickEvents(); +} + // ---------------------------- inline SpinButtonElement::SpinButtonElement(Document* document, StepActionHandler& stepActionHandler) @@ -279,7 +293,7 @@ void SpinButtonElement::defaultEventHandler(Event* event) } RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowHost())); - if (input->disabled() || input->isReadOnlyFormControl()) { + if (input->disabled() || input->readOnly()) { if (!event->defaultHandled()) HTMLDivElement::defaultEventHandler(event); return; @@ -328,6 +342,24 @@ void SpinButtonElement::defaultEventHandler(Event* event) HTMLDivElement::defaultEventHandler(event); } +bool SpinButtonElement::willRespondToMouseMoveEvents() +{ + const HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowHost()); + if (renderBox() && !input->disabled() && !input->readOnly()) + return true; + + return HTMLDivElement::willRespondToMouseMoveEvents(); +} + +bool SpinButtonElement::willRespondToMouseClickEvents() +{ + const HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowHost()); + if (renderBox() && !input->disabled() && !input->readOnly()) + return true; + + return HTMLDivElement::willRespondToMouseClickEvents(); +} + void SpinButtonElement::doStepAction(int amount) { if (!m_stepActionHandler) @@ -350,6 +382,16 @@ void SpinButtonElement::releaseCapture() } } +bool SpinButtonElement::shouldMatchReadOnlySelector() const +{ + return shadowHost()->shouldMatchReadOnlySelector(); +} + +bool SpinButtonElement::shouldMatchReadWriteSelector() const +{ + return shadowHost()->shouldMatchReadWriteSelector(); +} + void SpinButtonElement::startRepeatingTimer() { m_pressStartingState = m_upDownState; @@ -365,7 +407,7 @@ void SpinButtonElement::stopRepeatingTimer() void SpinButtonElement::step(int amount) { HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowHost()); - if (input->disabled() || input->isReadOnlyFormControl()) + if (input->disabled() || input->readOnly()) return; // On Mac OS, NSStepper updates the value for the button under the mouse // cursor regardless of the button pressed at the beginning. So the @@ -431,7 +473,7 @@ void InputFieldSpeechButtonElement::defaultEventHandler(Event* event) // here, we take a temporary reference. RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowHost())); - if (input->disabled() || input->isReadOnlyFormControl()) { + if (input->disabled() || input->readOnly()) { if (!event->defaultHandled()) HTMLDivElement::defaultEventHandler(event); return; @@ -479,6 +521,15 @@ void InputFieldSpeechButtonElement::defaultEventHandler(Event* event) HTMLDivElement::defaultEventHandler(event); } +bool InputFieldSpeechButtonElement::willRespondToMouseClickEvents() +{ + const HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowHost()); + if (!input->disabled() && !input->readOnly()) + return true; + + return HTMLDivElement::willRespondToMouseClickEvents(); +} + void InputFieldSpeechButtonElement::setState(SpeechInputState state) { if (m_state != state) { @@ -510,7 +561,7 @@ void InputFieldSpeechButtonElement::setRecognitionResult(int, const SpeechInputR // remove the input element from DOM. To make sure it remains valid until we finish our work // here, we take a temporary reference. RefPtr<HTMLInputElement> input(static_cast<HTMLInputElement*>(shadowHost())); - if (input->disabled() || input->isReadOnlyFormControl()) + if (input->disabled() || input->readOnly()) return; RefPtr<InputFieldSpeechButtonElement> holdRefButton(this); diff --git a/Source/WebCore/html/shadow/TextControlInnerElements.h b/Source/WebCore/html/shadow/TextControlInnerElements.h index 33d5890a9..6336dcb63 100644 --- a/Source/WebCore/html/shadow/TextControlInnerElements.h +++ b/Source/WebCore/html/shadow/TextControlInnerElements.h @@ -66,6 +66,7 @@ public: static PassRefPtr<SearchFieldResultsButtonElement> create(Document*); virtual void defaultEventHandler(Event*); + virtual bool willRespondToMouseClickEvents() OVERRIDE; private: SearchFieldResultsButtonElement(Document*); @@ -78,6 +79,7 @@ public: static PassRefPtr<SearchFieldCancelButtonElement> create(Document*); virtual void defaultEventHandler(Event*); + virtual bool willRespondToMouseClickEvents() OVERRIDE; private: SearchFieldCancelButtonElement(Document*); @@ -113,6 +115,9 @@ public: void step(int amount); + virtual bool willRespondToMouseMoveEvents() OVERRIDE; + virtual bool willRespondToMouseClickEvents() OVERRIDE; + private: SpinButtonElement(Document*, StepActionHandler&); @@ -120,7 +125,8 @@ private: virtual void detach(); virtual bool isSpinButtonElement() const { return true; } virtual bool isEnabledFormControl() const { return shadowHost()->isEnabledFormControl(); } - virtual bool isReadOnlyFormControl() const { return shadowHost()->isReadOnlyFormControl(); } + virtual bool shouldMatchReadOnlySelector() const OVERRIDE; + virtual bool shouldMatchReadWriteSelector() const OVERRIDE; virtual void defaultEventHandler(Event*); void doStepAction(int); void startRepeatingTimer(); @@ -153,6 +159,7 @@ public: virtual void detach(); virtual void defaultEventHandler(Event*); + virtual bool willRespondToMouseClickEvents(); virtual bool isInputFieldSpeechButtonElement() const { return true; } SpeechInputState state() const { return m_state; } void startSpeechInput(); diff --git a/Source/WebCore/html/shadow/TextFieldDecorationElement.cpp b/Source/WebCore/html/shadow/TextFieldDecorationElement.cpp index 09cc7b1d4..689aa0ad2 100644 --- a/Source/WebCore/html/shadow/TextFieldDecorationElement.cpp +++ b/Source/WebCore/html/shadow/TextFieldDecorationElement.cpp @@ -198,4 +198,13 @@ void TextFieldDecorationElement::defaultEventHandler(Event* event) HTMLDivElement::defaultEventHandler(event); } +bool TextFieldDecorationElement::willRespondToMouseClickEvents() +{ + const HTMLInputElement* input = hostInput(); + if (!input->disabled() && !input->readOnly()) + return true; + + return HTMLDivElement::willRespondToMouseClickEvents(); +} + } // namespace WebCore diff --git a/Source/WebCore/html/shadow/TextFieldDecorationElement.h b/Source/WebCore/html/shadow/TextFieldDecorationElement.h index f2c827a45..2c8d822b3 100644 --- a/Source/WebCore/html/shadow/TextFieldDecorationElement.h +++ b/Source/WebCore/html/shadow/TextFieldDecorationElement.h @@ -71,6 +71,8 @@ public: TextFieldDecorator* textFieldDecorator() { return m_textFieldDecorator; } void decorate(HTMLInputElement*, bool visible); + virtual bool willRespondToMouseClickEvents() OVERRIDE; + private: TextFieldDecorationElement(Document*, TextFieldDecorator*); virtual bool isTextFieldDecoration() const OVERRIDE; diff --git a/Source/WebCore/html/track/TextTrack.cpp b/Source/WebCore/html/track/TextTrack.cpp index a6e7f844c..75d763cdd 100644 --- a/Source/WebCore/html/track/TextTrack.cpp +++ b/Source/WebCore/html/track/TextTrack.cpp @@ -198,6 +198,10 @@ void TextTrack::addCue(PassRefPtr<TextTrackCue> prpCue, ExceptionCode& ec) RefPtr<TextTrackCue> cue = prpCue; + // TODO(93143): Add spec-compliant behavior for negative time values. + if (cue->startTime() < 0 || cue->endTime() < 0) + return; + // 4.8.10.12.4 Text track API // The addCue(cue) method of TextTrack objects, when invoked, must run the following steps: diff --git a/Source/WebCore/html/track/TextTrackCue.cpp b/Source/WebCore/html/track/TextTrackCue.cpp index d2de4d3e5..7973fc5f5 100644 --- a/Source/WebCore/html/track/TextTrackCue.cpp +++ b/Source/WebCore/html/track/TextTrackCue.cpp @@ -168,7 +168,8 @@ void TextTrackCue::setId(const String& id) void TextTrackCue::setStartTime(double value) { - if (m_startTime == value) + // TODO(93143): Add spec-compliant behavior for negative time values. + if (m_startTime == value || value < 0) return; cueWillChange(); @@ -178,7 +179,8 @@ void TextTrackCue::setStartTime(double value) void TextTrackCue::setEndTime(double value) { - if (m_endTime == value) + // TODO(93143): Add spec-compliant behavior for negative time values. + if (m_endTime == value || value < 0) return; cueWillChange(); diff --git a/Source/WebCore/html/track/TextTrackCueList.cpp b/Source/WebCore/html/track/TextTrackCueList.cpp index 391b2f651..45ef441b1 100644 --- a/Source/WebCore/html/track/TextTrackCueList.cpp +++ b/Source/WebCore/html/track/TextTrackCueList.cpp @@ -77,6 +77,9 @@ TextTrackCueList* TextTrackCueList::activeCues() bool TextTrackCueList::add(PassRefPtr<TextTrackCue> cue) { + ASSERT(cue->startTime() >= 0); + ASSERT(cue->endTime() >= 0); + return add(cue, 0, m_list.size()); } |