diff options
Diffstat (limited to 'Source/WebCore/dom')
41 files changed, 779 insertions, 457 deletions
diff --git a/Source/WebCore/dom/ClientRect.h b/Source/WebCore/dom/ClientRect.h index f9acef0..f739497 100644 --- a/Source/WebCore/dom/ClientRect.h +++ b/Source/WebCore/dom/ClientRect.h @@ -42,8 +42,8 @@ namespace WebCore { static PassRefPtr<ClientRect> create(const FloatRect& rect) { return adoptRef(new ClientRect(rect)); } float top() const { return m_rect.y(); } - float right() const { return m_rect.right(); } - float bottom() const { return m_rect.bottom(); } + float right() const { return m_rect.maxX(); } + float bottom() const { return m_rect.maxY(); } float left() const { return m_rect.x(); } float width() const { return m_rect.width(); } float height() const { return m_rect.height(); } diff --git a/Source/WebCore/dom/DOMAllInOne.cpp b/Source/WebCore/dom/DOMAllInOne.cpp index aa85bfb..c88aecf 100644 --- a/Source/WebCore/dom/DOMAllInOne.cpp +++ b/Source/WebCore/dom/DOMAllInOne.cpp @@ -60,6 +60,7 @@ #include "Document.cpp" #include "DocumentFragment.cpp" #include "DocumentMarkerController.cpp" +#include "DocumentOrderedMap.cpp" #include "DocumentParser.cpp" #include "DocumentType.cpp" #include "DynamicNodeList.cpp" diff --git a/Source/WebCore/dom/DeviceMotionController.cpp b/Source/WebCore/dom/DeviceMotionController.cpp index 3385167..28e201e 100644 --- a/Source/WebCore/dom/DeviceMotionController.cpp +++ b/Source/WebCore/dom/DeviceMotionController.cpp @@ -54,7 +54,7 @@ void DeviceMotionController::timerFired(Timer<DeviceMotionController>* timer) RefPtr<DeviceMotionData> deviceMotionData = m_client ? m_client->currentDeviceMotion() : DeviceMotionData::create(); RefPtr<DeviceMotionEvent> event = DeviceMotionEvent::create(eventNames().devicemotionEvent, deviceMotionData.get()); - Vector<DOMWindow*> listenersVector; + Vector<RefPtr<DOMWindow> > listenersVector; copyToVector(m_newListeners, listenersVector); m_newListeners.clear(); for (size_t i = 0; i < listenersVector.size(); ++i) @@ -100,7 +100,7 @@ void DeviceMotionController::removeAllListeners(DOMWindow* window) void DeviceMotionController::didChangeDeviceMotion(DeviceMotionData* deviceMotionData) { RefPtr<DeviceMotionEvent> event = DeviceMotionEvent::create(eventNames().devicemotionEvent, deviceMotionData); - Vector<DOMWindow*> listenersVector; + Vector<RefPtr<DOMWindow> > listenersVector; copyToVector(m_listeners, listenersVector); for (size_t i = 0; i < listenersVector.size(); ++i) listenersVector[i]->dispatchEvent(event); diff --git a/Source/WebCore/dom/DeviceMotionController.h b/Source/WebCore/dom/DeviceMotionController.h index 70c948e..80c9d94 100644 --- a/Source/WebCore/dom/DeviceMotionController.h +++ b/Source/WebCore/dom/DeviceMotionController.h @@ -52,9 +52,9 @@ private: void timerFired(Timer<DeviceMotionController>*); DeviceMotionClient* m_client; - typedef HashCountedSet<DOMWindow*> ListenersCountedSet; + typedef HashCountedSet<RefPtr<DOMWindow> > ListenersCountedSet; ListenersCountedSet m_listeners; - typedef HashSet<DOMWindow*> ListenersSet; + typedef HashSet<RefPtr<DOMWindow> > ListenersSet; ListenersSet m_newListeners; Timer<DeviceMotionController> m_timer; }; diff --git a/Source/WebCore/dom/DeviceOrientationController.cpp b/Source/WebCore/dom/DeviceOrientationController.cpp index 60fcf13..da42bec 100644 --- a/Source/WebCore/dom/DeviceOrientationController.cpp +++ b/Source/WebCore/dom/DeviceOrientationController.cpp @@ -54,7 +54,7 @@ void DeviceOrientationController::timerFired(Timer<DeviceOrientationController>* RefPtr<DeviceOrientation> orientation = m_client->lastOrientation(); RefPtr<DeviceOrientationEvent> event = DeviceOrientationEvent::create(eventNames().deviceorientationEvent, orientation.get()); - Vector<DOMWindow*> listenersVector; + Vector<RefPtr<DOMWindow> > listenersVector; copyToVector(m_newListeners, listenersVector); m_newListeners.clear(); for (size_t i = 0; i < listenersVector.size(); ++i) @@ -102,7 +102,7 @@ void DeviceOrientationController::removeAllListeners(DOMWindow* window) void DeviceOrientationController::didChangeDeviceOrientation(DeviceOrientation* orientation) { RefPtr<DeviceOrientationEvent> event = DeviceOrientationEvent::create(eventNames().deviceorientationEvent, orientation); - Vector<DOMWindow*> listenersVector; + Vector<RefPtr<DOMWindow> > listenersVector; copyToVector(m_listeners, listenersVector); for (size_t i = 0; i < listenersVector.size(); ++i) listenersVector[i]->dispatchEvent(event); diff --git a/Source/WebCore/dom/DeviceOrientationController.h b/Source/WebCore/dom/DeviceOrientationController.h index 4fa9006..5e06771 100644 --- a/Source/WebCore/dom/DeviceOrientationController.h +++ b/Source/WebCore/dom/DeviceOrientationController.h @@ -55,9 +55,9 @@ private: Page* m_page; DeviceOrientationClient* m_client; - typedef HashCountedSet<DOMWindow*> ListenersCountedSet; + typedef HashCountedSet<RefPtr<DOMWindow> > ListenersCountedSet; ListenersCountedSet m_listeners; - typedef HashSet<DOMWindow*> ListenersSet; + typedef HashSet<RefPtr<DOMWindow> > ListenersSet; ListenersSet m_newListeners; Timer<DeviceOrientationController> m_timer; }; diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp index 0bdd603..6b1b90d 100644 --- a/Source/WebCore/dom/Document.cpp +++ b/Source/WebCore/dom/Document.cpp @@ -55,6 +55,7 @@ #include "DocumentType.h" #include "EditingText.h" #include "Editor.h" +#include "Element.h" #include "EntityReference.h" #include "Event.h" #include "EventHandler.h" @@ -102,6 +103,7 @@ #include "MouseEventWithHitTestResults.h" #include "MutationEvent.h" #include "NameNodeList.h" +#include "NestingLevelIncrementer.h" #include "NodeFilter.h" #include "NodeIterator.h" #include "NodeWithIndex.h" @@ -143,7 +145,6 @@ #include "XMLHttpRequest.h" #include "XMLNSNames.h" #include "XMLNames.h" -#include "XSSAuditor.h" #include "htmlediting.h" #include <wtf/CurrentTime.h> #include <wtf/HashFunctions.h> @@ -235,16 +236,13 @@ using namespace HTMLNames; // #define INSTRUMENT_LAYOUT_SCHEDULING 1 +static const unsigned cMaxWriteRecursionDepth = 21; + // This amount of time must have elapsed before we will even consider scheduling a layout without a delay. // FIXME: For faster machines this value can really be lowered to 200. 250 is adequate, but a little high // for dual G5s. :) static const int cLayoutScheduleThreshold = 250; -// These functions can't have internal linkage because they are used as template arguments. -bool keyMatchesId(AtomicStringImpl*, Element*); -bool keyMatchesMapName(AtomicStringImpl*, Element*); -bool keyMatchesLowercasedMapName(AtomicStringImpl*, Element*); - // DOM Level 2 says (letters added): // // a) Name start characters must have one of the categories Ll, Lu, Lo, Lt, Nl. @@ -383,7 +381,7 @@ private: Document* m_document; }; -Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML, const KURL& baseURL) +Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML) : ContainerNode(0) , m_compatibilityMode(NoQuirksMode) , m_compatibilityModeLocked(false) @@ -430,7 +428,7 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML, con , m_normalWorldWrapperCache(0) #endif , m_usingGeolocation(false) - , m_eventQueue(adoptPtr(new EventQueue)) + , m_eventQueue(EventQueue::create(this)) #if ENABLE(WML) , m_containsWMLContent(false) #endif @@ -446,6 +444,8 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML, con , m_loadEventDelayTimer(this, &Document::loadEventDelayTimerFired) , m_directionSetOnDocumentElement(false) , m_writingModeSetOnDocumentElement(false) + , m_writeRecursionIsTooDeep(false) + , m_writeRecursionDepth(0) #if ENABLE(REQUEST_ANIMATION_FRAME) , m_nextRequestAnimationFrameCallbackId(0) #endif @@ -460,16 +460,25 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML, con m_ignoreAutofocus = false; m_frame = frame; - - if (frame || !url.isEmpty()) + m_documentLoader = frame ? frame->loader()->activeDocumentLoader() : 0; + + // We depend on the url getting immediately set in subframes, but we + // also depend on the url NOT getting immediately set in opened windows. + // See fast/dom/early-frame-url.html + // and fast/dom/location-new-window-no-crash.html, respectively. + // FIXME: Can/should we unify this behavior? + if ((frame && frame->ownerElement()) || !url.isEmpty()) setURL(url); +<<<<<<< HEAD // Setting of m_baseURL needs to happen after the setURL call, since that // calls updateBaseURL, which would clobber the passed in value. if (!baseURL.isNull()) m_baseURL = baseURL; #if !PLATFORM(ANDROID) +======= +>>>>>>> webkit.org at r78450 m_axObjectCache = 0; #endif @@ -521,12 +530,6 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML, con #endif } -inline void Document::DocumentOrderedMap::clear() -{ - m_map.clear(); - m_duplicateCounts.clear(); -} - void Document::removedLastRef() { ASSERT(!m_deletionHasBegun); @@ -736,10 +739,7 @@ void Document::childrenChanged(bool changedByParser, Node* beforeChange, Node* a void Document::cacheDocumentElement() const { ASSERT(!m_documentElement); - Node* n = firstChild(); - while (n && !n->isElementNode()) - n = n->nextSibling(); - m_documentElement = static_cast<Element*>(n); + m_documentElement = firstElementChild(this); } PassRefPtr<Element> Document::createElement(const AtomicString& name, ExceptionCode& ec) @@ -1019,87 +1019,11 @@ PassRefPtr<Element> Document::createElementNS(const String& namespaceURI, const return createElement(qName, false); } -inline void Document::DocumentOrderedMap::add(AtomicStringImpl* key, Element* element) -{ - ASSERT(key); - ASSERT(element); - - if (!m_duplicateCounts.contains(key)) { - // Fast path. The key is not already in m_duplicateCounts, so we assume that it's - // also not already in m_map and try to add it. If that add succeeds, we're done. - pair<Map::iterator, bool> addResult = m_map.add(key, element); - if (addResult.second) - return; - - // The add failed, so this key was already cached in m_map. - // There are multiple elements with this key. Remove the m_map - // cache for this key so get searches for it next time it is called. - m_map.remove(addResult.first); - m_duplicateCounts.add(key); - } else { - // There are multiple elements with this key. Remove the m_map - // cache for this key so get will search for it next time it is called. - Map::iterator cachedItem = m_map.find(key); - if (cachedItem != m_map.end()) { - m_map.remove(cachedItem); - m_duplicateCounts.add(key); - } - } - - m_duplicateCounts.add(key); -} - -inline void Document::DocumentOrderedMap::remove(AtomicStringImpl* key, Element* element) -{ - ASSERT(key); - ASSERT(element); - - m_map.checkConsistency(); - Map::iterator cachedItem = m_map.find(key); - if (cachedItem != m_map.end() && cachedItem->second == element) - m_map.remove(cachedItem); - else - m_duplicateCounts.remove(key); -} - -template<bool keyMatches(AtomicStringImpl*, Element*)> inline Element* Document::DocumentOrderedMap::get(AtomicStringImpl* key, const Document* document) const -{ - ASSERT(key); - - m_map.checkConsistency(); - - Element* element = m_map.get(key); - if (element) - return element; - - if (m_duplicateCounts.contains(key)) { - // We know there's at least one node that matches; iterate to find the first one. - for (Node* node = document->firstChild(); node; node = node->traverseNextNode()) { - if (!node->isElementNode()) - continue; - element = static_cast<Element*>(node); - if (!keyMatches(key, element)) - continue; - m_duplicateCounts.remove(key); - m_map.set(key, element); - return element; - } - ASSERT_NOT_REACHED(); - } - - return 0; -} - -inline bool keyMatchesId(AtomicStringImpl* key, Element* element) -{ - return element->hasID() && element->getIdAttribute().impl() == key; -} - Element* Document::getElementById(const AtomicString& elementId) const { if (elementId.isEmpty()) return 0; - return m_elementsById.get<keyMatchesId>(elementId.impl(), this); + return m_elementsById.getElementById(elementId.impl(), this); } String Document::readyState() const @@ -1209,7 +1133,7 @@ void Document::setContent(const String& content) open(); m_parser->append(content); m_parser->finish(); - close(); + explicitClose(); } // FIXME: We need to discuss the DOM API here at some point. Ideas: @@ -2038,6 +1962,8 @@ void Document::open(Document* ownerDocument) removeAllEventListeners(); implicitOpen(); + if (ScriptableDocumentParser* parser = scriptableDocumentParser()) + parser->setWasCreatedByScript(true); if (DOMWindow* domWindow = this->domWindow()) domWindow->removeAllEventListeners(); @@ -2056,14 +1982,15 @@ void Document::detachParser() void Document::cancelParsing() { - if (m_parser) { - // We have to clear the parser to avoid possibly triggering - // the onload handler when closing as a side effect of a cancel-style - // change, such as opening a new document or closing the window while - // still parsing - detachParser(); - close(); - } + if (!m_parser) + return; + + // We have to clear the parser to avoid possibly triggering + // the onload handler when closing as a side effect of a cancel-style + // change, such as opening a new document or closing the window while + // still parsing + detachParser(); + explicitClose(); } void Document::implicitOpen() @@ -2078,10 +2005,6 @@ void Document::implicitOpen() setParsing(true); setReadyState(Loading); - ScriptableDocumentParser* parser = scriptableDocumentParser(); - if (m_frame && parser) - parser->setXSSAuditor(m_frame->script()->xssAuditor()); - // If we reload, the animation controller sticks around and has // a stale animation time. We need to update it here. if (m_frame && m_frame->animation()) @@ -2098,12 +2021,12 @@ HTMLElement* Document::body() const Node* body = 0; for (Node* i = de->firstChild(); i; i = i->nextSibling()) { if (i->hasTagName(framesetTag)) - return static_cast<HTMLElement*>(i); + return toHTMLElement(i); if (i->hasTagName(bodyTag) && !body) body = i; } - return static_cast<HTMLElement*>(body); + return toHTMLElement(body); } void Document::setBody(PassRefPtr<HTMLElement> newBody, ExceptionCode& ec) @@ -2135,18 +2058,28 @@ HTMLHeadElement* Document::head() void Document::close() { - Frame* frame = this->frame(); - if (frame) { - // This code calls implicitClose() if all loading has completed. - FrameLoader* frameLoader = frame->loader(); - frameLoader->writer()->endIfNotLoadingMainResource(); - frameLoader->checkCompleted(); - } else { + // FIXME: We should follow the specification more closely: + // http://www.whatwg.org/specs/web-apps/current-work/#dom-document-close + + if (!scriptableDocumentParser() || !scriptableDocumentParser()->wasCreatedByScript()) + return; + + explicitClose(); +} + +void Document::explicitClose() +{ + if (!m_frame) { // Because we have no frame, we don't know if all loading has completed, // so we just call implicitClose() immediately. FIXME: This might fire // the load event prematurely <http://bugs.webkit.org/show_bug.cgi?id=14568>. implicitClose(); + return; } + + // This code calls implicitClose() if all loading has completed. + loader()->writer()->endIfNotLoadingMainResource(); + m_frame->loader()->checkCompleted(); } void Document::implicitClose() @@ -2297,6 +2230,14 @@ int Document::elapsedTime() const void Document::write(const SegmentedString& text, Document* ownerDocument) { + NestingLevelIncrementer nestingLevelIncrementer(m_writeRecursionDepth); + + m_writeRecursionIsTooDeep = (m_writeRecursionDepth > 1) && m_writeRecursionIsTooDeep; + m_writeRecursionIsTooDeep = (m_writeRecursionDepth > cMaxWriteRecursionDepth) || m_writeRecursionIsTooDeep; + + if (m_writeRecursionIsTooDeep) + return; + #ifdef INSTRUMENT_LAYOUT_SCHEDULING if (!ownerElement()) printf("Beginning a document.write at %d\n", elapsedTime()); @@ -2421,7 +2362,7 @@ void Document::processBaseElement() KURL baseElementURL; if (href) { String strippedHref = stripLeadingAndTrailingHTMLSpaces(*href); - if (!strippedHref.isEmpty() && (!frame() || frame()->script()->xssAuditor()->canSetBaseElementURL(*href))) + if (!strippedHref.isEmpty()) baseElementURL = KURL(url(), strippedHref); } if (m_baseElementURL != baseElementURL) { @@ -2698,7 +2639,7 @@ void Document::processHttpEquiv(const String& equiv, const String& content) String url; if (frame && parseHTTPRefresh(content, true, delay, url)) { if (url.isEmpty()) - url = frame->loader()->url().string(); + url = m_url.string(); else url = completeURL(url).string(); frame->navigationScheduler()->scheduleRedirect(delay, url); @@ -2979,12 +2920,11 @@ void Document::removePendingSheet() styleSelectorChanged(RecalcStyleImmediately); - ScriptableDocumentParser* parser = scriptableDocumentParser(); - if (parser) + if (ScriptableDocumentParser* parser = scriptableDocumentParser()) parser->executeScriptsWaitingForStylesheets(); if (m_gotoAnchorNeededAfterStylesheetsLoad && view()) - view()->scrollToFragment(m_frame->loader()->url()); + view()->scrollToFragment(m_url); } void Document::styleSelectorChanged(StyleSelectorUpdateFlag updateFlag) @@ -3037,6 +2977,9 @@ void Document::styleSelectorChanged(StyleSelectorUpdateFlag updateFlag) void Document::addStyleSheetCandidateNode(Node* node, bool createdByParser) { + if (!node->inDocument()) + return; + // Until the <body> exists, we have no choice but to compare document positions, // since styles outside of the body and head continue to be shunted into the head // (and thus can shift to end up before dynamically added DOM content that is also @@ -3825,7 +3768,7 @@ String Document::lastModified() const DateComponents date; bool foundDate = false; if (m_frame) { - String httpLastModified = m_frame->loader()->documentLoader()->response().httpHeaderField("Last-Modified"); + String httpLastModified = m_documentLoader->response().httpHeaderField("Last-Modified"); if (!httpLastModified.isEmpty()) { date.setMillisecondsSinceEpochForDateTime(parseDate(httpLastModified)); foundDate = true; @@ -3957,16 +3900,6 @@ void Document::removeImageMap(HTMLMapElement* imageMap) m_imageMapsByName.remove(name, imageMap); } -inline bool keyMatchesMapName(AtomicStringImpl* key, Element* element) -{ - return element->hasTagName(mapTag) && static_cast<HTMLMapElement*>(element)->getName().impl() == key; -} - -inline bool keyMatchesLowercasedMapName(AtomicStringImpl* key, Element* element) -{ - return element->hasTagName(mapTag) && static_cast<HTMLMapElement*>(element)->getName().lower().impl() == key; -} - HTMLMapElement* Document::getImageMap(const String& url) const { if (url.isNull()) @@ -3974,8 +3907,8 @@ HTMLMapElement* Document::getImageMap(const String& url) const size_t hashPos = url.find('#'); String name = (hashPos == notFound ? url : url.substring(hashPos + 1)).impl(); if (isHTMLDocument()) - return static_cast<HTMLMapElement*>(m_imageMapsByName.get<keyMatchesLowercasedMapName>(AtomicString(name.lower()).impl(), this)); - return static_cast<HTMLMapElement*>(m_imageMapsByName.get<keyMatchesMapName>(AtomicString(name).impl(), this)); + return static_cast<HTMLMapElement*>(m_imageMapsByName.getElementByLowercasedMapName(AtomicString(name.lower()).impl(), this)); + return static_cast<HTMLMapElement*>(m_imageMapsByName.getElementByMapName(AtomicString(name).impl(), this)); } void Document::setDecoder(PassRefPtr<TextResourceDecoder> decoder) @@ -4338,7 +4271,7 @@ void Document::finishedParsing() f->loader()->finishedParsing(); - InspectorInstrumentation::mainResourceFiredDOMContentEvent(f, url()); + InspectorInstrumentation::domContentLoadedEventFired(f, url()); } } @@ -4551,8 +4484,7 @@ void Document::initSecurityContext() // load local resources. See https://bugs.webkit.org/show_bug.cgi?id=16756 // and https://bugs.webkit.org/show_bug.cgi?id=19760 for further // discussion. - DocumentLoader* documentLoader = m_frame->loader()->documentLoader(); - if (documentLoader && documentLoader->substituteData().isValid()) + if (m_documentLoader->substituteData().isValid()) securityOrigin()->grantLoadLocalResources(); } @@ -4629,10 +4561,9 @@ void Document::updateURLForPushOrReplaceState(const KURL& url) if (!f) return; - // FIXME: Eliminate this redundancy. setURL(url); - f->loader()->setURL(url); - f->loader()->documentLoader()->replaceRequestURLForSameDocumentNavigation(url); + f->loader()->setOutgoingReferrer(url); + m_documentLoader->replaceRequestURLForSameDocumentNavigation(url); } void Document::statePopped(SerializedScriptValue* stateObject) @@ -5048,7 +4979,7 @@ void Document::webkitCancelRequestAnimationFrame(int id) } } -void Document::serviceScriptedAnimations() +void Document::serviceScriptedAnimations(DOMTimeStamp time) { if (!m_requestAnimationFrameCallbacks) return; @@ -5076,7 +5007,7 @@ void Document::serviceScriptedAnimations() RequestAnimationFrameCallback* callback = callbacks[i].get(); if (!callback->m_firedOrCancelled && (!callback->m_element || callback->m_element->renderer())) { callback->m_firedOrCancelled = true; - callback->handleEvent(); + callback->handleEvent(time); firedCallback = true; callbacks.remove(i); break; diff --git a/Source/WebCore/dom/Document.h b/Source/WebCore/dom/Document.h index c9c8d38..9ace93d 100644 --- a/Source/WebCore/dom/Document.h +++ b/Source/WebCore/dom/Document.h @@ -32,15 +32,19 @@ #include "CollectionType.h" #include "Color.h" #include "ContainerNode.h" +#include "ContentSecurityPolicy.h" +#include "DOMTimeStamp.h" +#include "DocumentLoader.h" +#include "DocumentOrderedMap.h" #include "DocumentTiming.h" #include "QualifiedName.h" #include "ScriptExecutionContext.h" #include "Timer.h" #include "ViewportArguments.h" #include <wtf/FixedArray.h> -#include <wtf/HashCountedSet.h> #include <wtf/OwnPtr.h> #include <wtf/PassOwnPtr.h> +#include <wtf/PassRefPtr.h> #if USE(JSC) #include <runtime/WeakGCMap.h> @@ -347,7 +351,6 @@ public: String defaultCharset() const; - // Synonyms backing similar DOM attributes. Use Document::encoding() to avoid virtual dispatch. String inputEncoding() const { return Document::encoding(); } String charset() const { return Document::encoding(); } String characterSet() const { return Document::encoding(); } @@ -429,6 +432,7 @@ public: #endif virtual bool isFrameSet() const { return false; } + CSSStyleSelector* styleSelectorIfExists() const { return m_styleSelector.get(); } CSSStyleSelector* styleSelector() { if (!m_styleSelector) @@ -554,11 +558,22 @@ public: // to get visually ordered hebrew and arabic pages right void setVisuallyOrdered(); bool visuallyOrdered() const { return m_visuallyOrdered; } + + void setDocumentLoader(DocumentLoader* documentLoader) { m_documentLoader = documentLoader; } + DocumentLoader* loader() const { return m_documentLoader; } void open(Document* ownerDocument = 0); void implicitOpen(); + + // close() is the DOM API document.close() void close(); + // In some situations (see the code), we ignore document.close(). + // explicitClose() bypass these checks and actually tries to close the + // input stream. + void explicitClose(); + // implicitClose() actually does the work of closing the input stream. void implicitClose(); + void cancelParsing(); void write(const SegmentedString& text, Document* ownerDocument = 0); @@ -952,7 +967,7 @@ public: virtual void postTask(PassOwnPtr<Task>); // Executes the task on context's thread asynchronously. #if USE(JSC) - typedef JSC::WeakGCMap<WebCore::Node*, JSNode*> JSWrapperCache; + typedef JSC::WeakGCMap<WebCore::Node*, JSNode> JSWrapperCache; typedef HashMap<DOMWrapperWorld*, JSWrapperCache*> JSWrapperCacheMap; JSWrapperCacheMap& wrapperCacheMap() { return m_wrapperCacheMap; } JSWrapperCache* getWrapperCache(DOMWrapperWorld* world); @@ -1091,7 +1106,7 @@ public: #if ENABLE(REQUEST_ANIMATION_FRAME) int webkitRequestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback>, Element*); void webkitCancelRequestAnimationFrame(int id); - void serviceScriptedAnimations(); + void serviceScriptedAnimations(DOMTimeStamp); #endif bool mayCauseFlashOfUnstyledContent() const; @@ -1101,35 +1116,15 @@ public: void initDNSPrefetch(); + ContentSecurityPolicy* contentSecurityPolicy() { return &m_contentSecurityPolicy; } + protected: - Document(Frame*, const KURL& url, bool isXHTML, bool isHTML, const KURL& baseURL = KURL()); + Document(Frame*, const KURL&, bool isXHTML, bool isHTML); void clearXMLVersion() { m_xmlVersion = String(); } private: - class DocumentOrderedMap { - public: - void add(AtomicStringImpl*, Element*); - void remove(AtomicStringImpl*, Element*); - void clear(); - - bool contains(AtomicStringImpl*) const; - bool containsMultiple(AtomicStringImpl*) const; - template<bool keyMatches(AtomicStringImpl*, Element*)> Element* get(AtomicStringImpl*, const Document*) const; - - void checkConsistency() const; - - private: - typedef HashMap<AtomicStringImpl*, Element*> Map; - - // We maintain the invariant that m_duplicateCounts is the count of all elements with a given key - // excluding the one referenced in m_map, if any. This means it one less than the total count - // when the first node with a given key is cached, otherwise the same as the total count. - mutable Map m_map; - mutable HashCountedSet<AtomicStringImpl*> m_duplicateCounts; - }; - friend class IgnoreDestructiveWriteCountIncrementer; void detachParser(); @@ -1172,6 +1167,7 @@ private: bool m_didCalculateStyleSelector; Frame* m_frame; + DocumentLoader* m_documentLoader; OwnPtr<CachedResourceLoader> m_cachedResourceLoader; RefPtr<DocumentParser> m_parser; bool m_wellFormed; @@ -1422,23 +1418,17 @@ private: DocumentTiming m_documentTiming; RefPtr<MediaQueryMatcher> m_mediaQueryMatcher; + bool m_writeRecursionIsTooDeep; + unsigned m_writeRecursionDepth; #if ENABLE(REQUEST_ANIMATION_FRAME) typedef Vector<RefPtr<RequestAnimationFrameCallback> > RequestAnimationFrameCallbackList; OwnPtr<RequestAnimationFrameCallbackList> m_requestAnimationFrameCallbacks; int m_nextRequestAnimationFrameCallbackId; #endif -}; -inline bool Document::DocumentOrderedMap::contains(AtomicStringImpl* id) const -{ - return m_map.contains(id) || m_duplicateCounts.contains(id); -} - -inline bool Document::DocumentOrderedMap::containsMultiple(AtomicStringImpl* id) const -{ - return m_duplicateCounts.contains(id); -} + ContentSecurityPolicy m_contentSecurityPolicy; +}; inline bool Document::hasElementWithId(AtomicStringImpl* id) const { diff --git a/Source/WebCore/dom/DocumentMarker.h b/Source/WebCore/dom/DocumentMarker.h index 2be60f8..76b85bb 100644 --- a/Source/WebCore/dom/DocumentMarker.h +++ b/Source/WebCore/dom/DocumentMarker.h @@ -37,10 +37,20 @@ struct DocumentMarker { Spelling = 1 << 0, Grammar = 1 << 1, TextMatch = 1 << 2, + // Text has been modified by spell correction. On some platforms, this prevents the text + // to be autocorrected again. Replacement = 1 << 3, + // Renderer needs to add underline indicating that the text has been modified by spell + // correction. Text with Replacement marker doesn't necessarily has CorrectionIndicator + // marker. For instance, after some text has been corrected, it will have both Replacement + // and CorrectionIndicator. However, if user further modifies such text, we would remove + // CorrectionIndicator marker, but retain Replacement marker. CorrectionIndicator = 1 << 4, + // Correction suggestion has been offered, but got rejected by user. RejectedCorrection = 1 << 5, - AllMarkers = Spelling | Grammar | TextMatch | Replacement | CorrectionIndicator | RejectedCorrection + // On some platforms, this prevents the text to be spellchecked again. + SpellCheckingExemption = 1 << 6, + AllMarkers = Spelling | Grammar | TextMatch | Replacement | CorrectionIndicator | RejectedCorrection | SpellCheckingExemption }; MarkerType type; typedef unsigned MarkerTypes; diff --git a/Source/WebCore/dom/DocumentMarkerController.cpp b/Source/WebCore/dom/DocumentMarkerController.cpp index 5f88631..1bc7cb4 100644 --- a/Source/WebCore/dom/DocumentMarkerController.cpp +++ b/Source/WebCore/dom/DocumentMarkerController.cpp @@ -57,21 +57,16 @@ void DocumentMarkerController::addMarker(Range* range, DocumentMarker::MarkerTyp } } -void DocumentMarkerController::removeMarkers(Range* range, DocumentMarker::MarkerType markerType) +void DocumentMarkerController::removeMarkers(Range* range, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker) { if (m_markers.isEmpty()) return; - ExceptionCode ec = 0; - Node* startContainer = range->startContainer(ec); - Node* endContainer = range->endContainer(ec); - - Node* pastLastNode = range->pastLastNode(); - for (Node* node = range->firstNode(); node != pastLastNode; node = node->traverseNextNode()) { - int startOffset = node == startContainer ? range->startOffset(ec) : 0; - int endOffset = node == endContainer ? range->endOffset(ec) : INT_MAX; - int length = endOffset - startOffset; - removeMarkers(node, startOffset, length, markerType); + for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) { + RefPtr<Range> textPiece = markedText.range(); + int startOffset = textPiece->startOffset(); + int endOffset = textPiece->endOffset(); + removeMarkers(textPiece->startContainer(), startOffset, endOffset - startOffset, markerTypes, shouldRemovePartiallyOverlappingMarker); } } @@ -185,7 +180,7 @@ void DocumentMarkerController::copyMarkers(Node* srcNode, unsigned startOffset, dstNode->renderer()->repaint(); } -void DocumentMarkerController::removeMarkers(Node* node, unsigned startOffset, int length, DocumentMarker::MarkerType markerType) +void DocumentMarkerController::removeMarkers(Node* node, unsigned startOffset, int length, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker) { if (length <= 0) return; @@ -207,7 +202,7 @@ void DocumentMarkerController::removeMarkers(Node* node, unsigned startOffset, i break; // skip marker that is wrong type or before target - if (marker.endOffset < startOffset || (marker.type != markerType && markerType != DocumentMarker::AllMarkers)) { + if (marker.endOffset <= startOffset || !(marker.type & markerTypes)) { i++; continue; } @@ -219,6 +214,10 @@ void DocumentMarkerController::removeMarkers(Node* node, unsigned startOffset, i markers.remove(i); rects.remove(i); + if (shouldRemovePartiallyOverlappingMarker) + // Stop here. Don't add resulting slices back. + continue; + // add either of the resulting slices that are left after removing target if (startOffset > marker.startOffset) { DocumentMarker newLeft = marker; @@ -321,14 +320,14 @@ Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers(DocumentMarker return result; } -void DocumentMarkerController::removeMarkers(Node* node, DocumentMarker::MarkerType markerType) +void DocumentMarkerController::removeMarkers(Node* node, DocumentMarker::MarkerTypes markerTypes) { MarkerMap::iterator iterator = m_markers.find(node); if (iterator != m_markers.end()) - removeMarkersFromMarkerMapVectorPair(node, iterator->second, markerType); + removeMarkersFromMarkerMapVectorPair(node, iterator->second, markerTypes); } -void DocumentMarkerController::removeMarkers(DocumentMarker::MarkerType markerType) +void DocumentMarkerController::removeMarkers(DocumentMarker::MarkerTypes markerTypes) { // outer loop: process each markered node in the document MarkerMap markerMapCopy = m_markers; @@ -336,14 +335,14 @@ void DocumentMarkerController::removeMarkers(DocumentMarker::MarkerType markerTy for (MarkerMap::iterator i = markerMapCopy.begin(); i != end; ++i) { Node* node = i->first.get(); MarkerMapVectorPair* vectorPair = i->second; - removeMarkersFromMarkerMapVectorPair(node, vectorPair, markerType); + removeMarkersFromMarkerMapVectorPair(node, vectorPair, markerTypes); } } // This function may release node and vectorPair. -void DocumentMarkerController::removeMarkersFromMarkerMapVectorPair(Node* node, MarkerMapVectorPair* vectorPair, DocumentMarker::MarkerType markerType) +void DocumentMarkerController::removeMarkersFromMarkerMapVectorPair(Node* node, MarkerMapVectorPair* vectorPair, DocumentMarker::MarkerTypes markerTypes) { - if (markerType == DocumentMarker::AllMarkers) { + if (!~(markerTypes & DocumentMarker::AllMarkers)) { delete vectorPair; m_markers.remove(node); if (RenderObject* renderer = node->renderer()) @@ -357,7 +356,7 @@ void DocumentMarkerController::removeMarkersFromMarkerMapVectorPair(Node* node, DocumentMarker marker = markers[i]; // skip nodes that are not of the specified type - if (marker.type != markerType) { + if (!(marker.type & markerTypes)) { ++i; continue; } @@ -566,7 +565,6 @@ bool DocumentMarkerController::hasMarkers(Range* range, DocumentMarker::MarkerTy } return false; } - #ifndef NDEBUG void DocumentMarkerController::showMarkers() const { diff --git a/Source/WebCore/dom/DocumentMarkerController.h b/Source/WebCore/dom/DocumentMarkerController.h index 2dc2b9e..21b351b 100644 --- a/Source/WebCore/dom/DocumentMarkerController.h +++ b/Source/WebCore/dom/DocumentMarkerController.h @@ -49,10 +49,16 @@ public: void addMarker(Node*, DocumentMarker); void copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta, DocumentMarker::MarkerType = DocumentMarker::AllMarkers); bool hasMarkers(Range*, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers); - void removeMarkers(Range*, DocumentMarker::MarkerType = DocumentMarker::AllMarkers); - void removeMarkers(Node*, unsigned startOffset, int length, DocumentMarker::MarkerType = DocumentMarker::AllMarkers); - void removeMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers); - void removeMarkers(Node*, DocumentMarker::MarkerType = DocumentMarker::AllMarkers); + + // When a marker partially overlaps with range, if removePartiallyOverlappingMarkers is true, we completely + // remove the marker. If the argument is false, we will adjust the span of the marker so that it retains + // the portion that is outside of the range. + enum RemovePartiallyOverlappingMarkerOrNot { DoNotRemovePartiallyOverlappingMarker, RemovePartiallyOverlappingMarker }; + void removeMarkers(Range*, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers, RemovePartiallyOverlappingMarkerOrNot = DoNotRemovePartiallyOverlappingMarker); + void removeMarkers(Node*, unsigned startOffset, int length, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers, RemovePartiallyOverlappingMarkerOrNot = DoNotRemovePartiallyOverlappingMarker); + + void removeMarkers(DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers); + void removeMarkers(Node*, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers); void repaintMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers); void setRenderedRectForMarker(Node*, const DocumentMarker&, const IntRect&); void invalidateRenderedRectsForMarkersInRect(const IntRect&); @@ -72,7 +78,7 @@ private: typedef std::pair<Vector<DocumentMarker>, Vector<IntRect> > MarkerMapVectorPair; typedef HashMap<RefPtr<Node>, MarkerMapVectorPair*> MarkerMap; MarkerMap m_markers; - void removeMarkersFromMarkerMapVectorPair(Node*, MarkerMapVectorPair*, DocumentMarker::MarkerType); + void removeMarkersFromMarkerMapVectorPair(Node*, MarkerMapVectorPair*, DocumentMarker::MarkerTypes); }; } // namespace WebCore diff --git a/Source/WebCore/dom/DocumentOrderedMap.cpp b/Source/WebCore/dom/DocumentOrderedMap.cpp new file mode 100644 index 0000000..787fcf4 --- /dev/null +++ b/Source/WebCore/dom/DocumentOrderedMap.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DocumentOrderedMap.h" + +#include "Element.h" +#include "HTMLMapElement.h" +#include "HTMLNames.h" + +namespace WebCore { + +using namespace HTMLNames; + +inline bool keyMatchesId(AtomicStringImpl* key, Element* element) +{ + return element->hasID() && element->getIdAttribute().impl() == key; +} + +inline bool keyMatchesMapName(AtomicStringImpl* key, Element* element) +{ + return element->hasTagName(mapTag) && static_cast<HTMLMapElement*>(element)->getName().impl() == key; +} + +inline bool keyMatchesLowercasedMapName(AtomicStringImpl* key, Element* element) +{ + return element->hasTagName(mapTag) && static_cast<HTMLMapElement*>(element)->getName().lower().impl() == key; +} + +void DocumentOrderedMap::clear() +{ + m_map.clear(); + m_duplicateCounts.clear(); +} + +void DocumentOrderedMap::add(AtomicStringImpl* key, Element* element) +{ + ASSERT(key); + ASSERT(element); + + if (!m_duplicateCounts.contains(key)) { + // Fast path. The key is not already in m_duplicateCounts, so we assume that it's + // also not already in m_map and try to add it. If that add succeeds, we're done. + pair<Map::iterator, bool> addResult = m_map.add(key, element); + if (addResult.second) + return; + + // The add failed, so this key was already cached in m_map. + // There are multiple elements with this key. Remove the m_map + // cache for this key so get searches for it next time it is called. + m_map.remove(addResult.first); + m_duplicateCounts.add(key); + } else { + // There are multiple elements with this key. Remove the m_map + // cache for this key so get will search for it next time it is called. + Map::iterator cachedItem = m_map.find(key); + if (cachedItem != m_map.end()) { + m_map.remove(cachedItem); + m_duplicateCounts.add(key); + } + } + + m_duplicateCounts.add(key); +} + +void DocumentOrderedMap::remove(AtomicStringImpl* key, Element* element) +{ + ASSERT(key); + ASSERT(element); + + m_map.checkConsistency(); + Map::iterator cachedItem = m_map.find(key); + if (cachedItem != m_map.end() && cachedItem->second == element) + m_map.remove(cachedItem); + else + m_duplicateCounts.remove(key); +} + +template<bool keyMatches(AtomicStringImpl*, Element*)> +inline Element* DocumentOrderedMap::get(AtomicStringImpl* key, const Document* document) const +{ + ASSERT(key); + + m_map.checkConsistency(); + + Element* element = m_map.get(key); + if (element) + return element; + + if (m_duplicateCounts.contains(key)) { + // We know there's at least one node that matches; iterate to find the first one. + for (Node* node = document->firstChild(); node; node = node->traverseNextNode()) { + if (!node->isElementNode()) + continue; + element = static_cast<Element*>(node); + if (!keyMatches(key, element)) + continue; + m_duplicateCounts.remove(key); + m_map.set(key, element); + return element; + } + ASSERT_NOT_REACHED(); + } + + return 0; +} + +Element* DocumentOrderedMap::getElementById(AtomicStringImpl* key, const Document* document) const +{ + return get<keyMatchesId>(key, document); +} + +Element* DocumentOrderedMap::getElementByMapName(AtomicStringImpl* key, const Document* document) const +{ + return get<keyMatchesMapName>(key, document); +} + +Element* DocumentOrderedMap::getElementByLowercasedMapName(AtomicStringImpl* key, const Document* document) const +{ + return get<keyMatchesLowercasedMapName>(key, document); +} + +} // namespace WebCore + diff --git a/Source/WebCore/dom/DocumentOrderedMap.h b/Source/WebCore/dom/DocumentOrderedMap.h new file mode 100644 index 0000000..58767c6 --- /dev/null +++ b/Source/WebCore/dom/DocumentOrderedMap.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DocumentOrderedMap_h +#define DocumentOrderedMap_h + +#include <wtf/HashCountedSet.h> +#include <wtf/HashMap.h> +#include <wtf/text/AtomicStringImpl.h> + +namespace WebCore { + +class Document; +class Element; + +class DocumentOrderedMap { +public: + void add(AtomicStringImpl*, Element*); + void remove(AtomicStringImpl*, Element*); + void clear(); + + bool contains(AtomicStringImpl*) const; + bool containsMultiple(AtomicStringImpl*) const; + // concrete instantiations of the get<>() method template + Element* getElementById(AtomicStringImpl*, const Document*) const; + Element* getElementByMapName(AtomicStringImpl*, const Document*) const; + Element* getElementByLowercasedMapName(AtomicStringImpl*, const Document*) const; + + void checkConsistency() const; + +private: + template<bool keyMatches(AtomicStringImpl*, Element*)> Element* get(AtomicStringImpl*, const Document*) const; + + typedef HashMap<AtomicStringImpl*, Element*> Map; + + // We maintain the invariant that m_duplicateCounts is the count of all elements with a given key + // excluding the one referenced in m_map, if any. This means it one less than the total count + // when the first node with a given key is cached, otherwise the same as the total count. + mutable Map m_map; + mutable HashCountedSet<AtomicStringImpl*> m_duplicateCounts; +}; + +inline bool DocumentOrderedMap::contains(AtomicStringImpl* id) const +{ + return m_map.contains(id) || m_duplicateCounts.contains(id); +} + +inline bool DocumentOrderedMap::containsMultiple(AtomicStringImpl* id) const +{ + return m_duplicateCounts.contains(id); +} + +} // namespace WebCore + +#endif // DocumentOrderedMap_h + diff --git a/Source/WebCore/dom/Element.cpp b/Source/WebCore/dom/Element.cpp index 276a409..142febd 100644 --- a/Source/WebCore/dom/Element.cpp +++ b/Source/WebCore/dom/Element.cpp @@ -68,6 +68,34 @@ namespace WebCore { using namespace HTMLNames; using namespace XMLNames; +class StyleSelectorParentPusher { +public: + StyleSelectorParentPusher(Element* parent) + : m_parent(parent) + , m_pushedStyleSelector(0) + { + } + void push() + { + if (m_pushedStyleSelector) + return; + m_pushedStyleSelector = m_parent->document()->styleSelector(); + m_pushedStyleSelector->pushParent(m_parent); + } + ~StyleSelectorParentPusher() + { + + if (!m_pushedStyleSelector) + return; + ASSERT(m_pushedStyleSelector == m_parent->document()->styleSelector()); + m_pushedStyleSelector->popParent(m_parent); + } + +private: + Element* m_parent; + CSSStyleSelector* m_pushedStyleSelector; +}; + PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document) { return adoptRef(new Element(tagName, document, CreateElement)); @@ -124,7 +152,7 @@ PassRefPtr<DocumentFragment> Element::deprecatedCreateContextualFragment(const S for (RefPtr<Node> node = fragment->firstChild(); node; node = nextNode) { nextNode = node->nextSibling(); if (node->hasTagName(htmlTag) || node->hasTagName(bodyTag)) { - HTMLElement* element = static_cast<HTMLElement*>(node.get()); + HTMLElement* element = toHTMLElement(node.get()); Node* firstChild = element->firstChild(); if (firstChild) nextNode = firstChild; @@ -917,9 +945,15 @@ void Element::attach() RenderWidget::suspendWidgetHierarchyUpdates(); createRendererIfNeeded(); + + StyleSelectorParentPusher parentPusher(this); + if (firstChild()) + parentPusher.push(); ContainerNode::attach(); - if (Node* shadow = shadowRoot()) + if (Node* shadow = shadowRoot()) { + parentPusher.push(); shadow->attach(); + } if (hasRareData()) { ElementRareData* data = rareData(); if (data->needsFocusAppearanceUpdateSoonAfterAttach()) { @@ -1075,7 +1109,7 @@ void Element::recalcStyle(StyleChange change) change = ch; } } - + StyleSelectorParentPusher parentPusher(this); // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar. // For now we will just worry about the common case, since it's a lot trickier to get the second case right // without doing way too much re-resolution. @@ -1084,15 +1118,19 @@ void Element::recalcStyle(StyleChange change) bool childRulesChanged = n->needsStyleRecalc() && n->styleChangeType() == FullStyleChange; if (forceCheckOfNextElementSibling && n->isElementNode()) n->setNeedsStyleRecalc(); - if (change >= Inherit || n->isTextNode() || n->childNeedsStyleRecalc() || n->needsStyleRecalc()) + if (change >= Inherit || n->isTextNode() || n->childNeedsStyleRecalc() || n->needsStyleRecalc()) { + parentPusher.push(); n->recalcStyle(change); + } if (n->isElementNode()) forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules; } // FIXME: This does not care about sibling combinators. Will be necessary in XBL2 world. if (Node* shadow = shadowRoot()) { - if (change >= Inherit || shadow->isTextNode() || shadow->childNeedsStyleRecalc() || shadow->needsStyleRecalc()) + if (change >= Inherit || shadow->isTextNode() || shadow->childNeedsStyleRecalc() || shadow->needsStyleRecalc()) { + parentPusher.push(); shadow->recalcStyle(change); + } } clearNeedsStyleRecalc(); @@ -1238,12 +1276,22 @@ void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* af if (!changedByParser) checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta); } + +void Element::beginParsingChildren() +{ + clearIsParsingChildrenFinished(); + CSSStyleSelector* styleSelector = document()->styleSelectorIfExists(); + if (styleSelector && attached()) + styleSelector->pushParent(this); +} void Element::finishParsingChildren() { ContainerNode::finishParsingChildren(); setIsParsingChildrenFinished(); checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0); + if (CSSStyleSelector* styleSelector = document()->styleSelectorIfExists()) + styleSelector->popParent(this); } void Element::dispatchAttrRemovalEvent(Attribute*) @@ -1632,10 +1680,7 @@ void Element::normalizeAttributes() // ElementTraversal API Element* Element::firstElementChild() const { - Node* n = firstChild(); - while (n && !n->isElementNode()) - n = n->nextSibling(); - return static_cast<Element*>(n); + return WebCore::firstElementChild(this); } Element* Element::lastElementChild() const diff --git a/Source/WebCore/dom/Element.h b/Source/WebCore/dom/Element.h index 4510478..a85f8cd 100644 --- a/Source/WebCore/dom/Element.h +++ b/Source/WebCore/dom/Element.h @@ -232,7 +232,7 @@ public: Node* shadowRoot(); void setShadowRoot(PassRefPtr<Node>); - virtual AtomicString shadowPseudoId() const; + virtual const AtomicString& shadowPseudoId() const; RenderStyle* computedStyle(PseudoId = NOPSEUDO); @@ -276,7 +276,7 @@ public: bool isFinishedParsingChildren() const { return isParsingChildrenFinished(); } virtual void finishParsingChildren(); - virtual void beginParsingChildren() { clearIsParsingChildrenFinished(); } + virtual void beginParsingChildren(); // ElementTraversal API Element* firstElementChild() const; @@ -510,9 +510,18 @@ inline void Element::setIdAttribute(const AtomicString& value) setAttribute(document()->idAttributeName(), value); } -inline AtomicString Element::shadowPseudoId() const +inline const AtomicString& Element::shadowPseudoId() const { - return AtomicString(); + return nullAtom; +} + +inline Element* firstElementChild(const ContainerNode* container) +{ + ASSERT_ARG(container, container); + Node* child = container->firstChild(); + while (child && !child->isElementNode()) + child = child->nextSibling(); + return static_cast<Element*>(child); } } // namespace diff --git a/Source/WebCore/dom/Event.cpp b/Source/WebCore/dom/Event.cpp index 0e11c69..bdc1c58 100644 --- a/Source/WebCore/dom/Event.cpp +++ b/Source/WebCore/dom/Event.cpp @@ -193,6 +193,16 @@ bool Event::isStorageEvent() const #endif #if ENABLE(INDEXED_DATABASE) +bool Event::isIDBAbortEvent() const +{ + return false; +} + +bool Event::isIDBCompleteEvent() const +{ + return false; +} + bool Event::isIDBErrorEvent() const { return false; diff --git a/Source/WebCore/dom/Event.h b/Source/WebCore/dom/Event.h index 45b879d..81f9e6b 100644 --- a/Source/WebCore/dom/Event.h +++ b/Source/WebCore/dom/Event.h @@ -126,6 +126,8 @@ namespace WebCore { virtual bool isStorageEvent() const; #endif #if ENABLE(INDEXED_DATABASE) + virtual bool isIDBAbortEvent() const; + virtual bool isIDBCompleteEvent() const; virtual bool isIDBErrorEvent() const; virtual bool isIDBSuccessEvent() const; #endif diff --git a/Source/WebCore/dom/EventQueue.cpp b/Source/WebCore/dom/EventQueue.cpp index a43929e..5a1abe8 100644 --- a/Source/WebCore/dom/EventQueue.cpp +++ b/Source/WebCore/dom/EventQueue.cpp @@ -28,24 +28,41 @@ #include "EventQueue.h" #include "DOMWindow.h" -#include "Document.h" #include "Event.h" #include "EventNames.h" +#include "ScriptExecutionContext.h" +#include "SuspendableTimer.h" namespace WebCore { -EventQueue::EventQueue() - : m_pendingEventTimer(this, &EventQueue::pendingEventTimerFired) +class EventQueueTimer : public SuspendableTimer { + WTF_MAKE_NONCOPYABLE(EventQueueTimer); +public: + EventQueueTimer(EventQueue* eventQueue, ScriptExecutionContext* context) + : SuspendableTimer(context) + , m_eventQueue(eventQueue) { } + +private: + virtual void fired() { m_eventQueue->pendingEventTimerFired(); } + EventQueue* m_eventQueue; +}; + +EventQueue::EventQueue(ScriptExecutionContext* context) + : m_pendingEventTimer(adoptPtr(new EventQueueTimer(this, context))) +{ +} + +EventQueue::~EventQueue() { } void EventQueue::enqueueEvent(PassRefPtr<Event> event) { - ASSERT(event->target()->toNode() || event->target()->toDOMWindow()); + ASSERT(event->target()); m_queuedEvents.append(event); - if (!m_pendingEventTimer.isActive()) - m_pendingEventTimer.startOneShot(0); + if (!m_pendingEventTimer->isActive()) + m_pendingEventTimer->startOneShot(0); } void EventQueue::enqueueScrollEvent(PassRefPtr<Node> target, ScrollEventTargetType targetType) @@ -60,9 +77,9 @@ void EventQueue::enqueueScrollEvent(PassRefPtr<Node> target, ScrollEventTargetTy enqueueEvent(scrollEvent.release()); } -void EventQueue::pendingEventTimerFired(Timer<EventQueue>*) +void EventQueue::pendingEventTimerFired() { - ASSERT(!m_pendingEventTimer.isActive()); + ASSERT(!m_pendingEventTimer->isActive()); Vector<RefPtr<Event> > queuedEvents; queuedEvents.swap(m_queuedEvents); @@ -81,7 +98,7 @@ void EventQueue::dispatchEvent(PassRefPtr<Event> event) else if (eventTarget->toDOMWindow()) eventTarget->toDOMWindow()->dispatchEvent(event, 0); else - ASSERT_NOT_REACHED(); + eventTarget->dispatchEvent(event); } } diff --git a/Source/WebCore/dom/EventQueue.h b/Source/WebCore/dom/EventQueue.h index 7f8d5fb..a589ed8 100644 --- a/Source/WebCore/dom/EventQueue.h +++ b/Source/WebCore/dom/EventQueue.h @@ -27,38 +27,51 @@ #ifndef EventQueue_h #define EventQueue_h -#include "Timer.h" #include <wtf/HashSet.h> #include <wtf/Noncopyable.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> #include <wtf/RefPtr.h> #include <wtf/Vector.h> namespace WebCore { class Event; +class EventQueueTimer; class Node; +class ScriptExecutionContext; class EventQueue { WTF_MAKE_NONCOPYABLE(EventQueue); + public: enum ScrollEventTargetType { ScrollEventDocumentTarget, ScrollEventElementTarget }; - EventQueue(); + static PassOwnPtr<EventQueue> create(ScriptExecutionContext* context) + { + return adoptPtr(new EventQueue(context)); + } + + ~EventQueue(); void enqueueEvent(PassRefPtr<Event>); void enqueueScrollEvent(PassRefPtr<Node>, ScrollEventTargetType); private: - void pendingEventTimerFired(Timer<EventQueue>*); + explicit EventQueue(ScriptExecutionContext*); + + void pendingEventTimerFired(); void dispatchEvent(PassRefPtr<Event>); - Timer<EventQueue> m_pendingEventTimer; + OwnPtr<EventQueueTimer> m_pendingEventTimer; Vector<RefPtr<Event> > m_queuedEvents; HashSet<Node*> m_nodesWithQueuedScrollEvents; + + friend class EventQueueTimer; }; } diff --git a/Source/WebCore/dom/EventTarget.cpp b/Source/WebCore/dom/EventTarget.cpp index 5f2f8a7..ed5995c 100644 --- a/Source/WebCore/dom/EventTarget.cpp +++ b/Source/WebCore/dom/EventTarget.cpp @@ -181,6 +181,10 @@ FileWriter* EventTarget::toFileWriter() #endif #if ENABLE(INDEXED_DATABASE) +IDBDatabase* EventTarget::toIDBDatabase() +{ + return 0; +} IDBRequest* EventTarget::toIDBRequest() { return 0; diff --git a/Source/WebCore/dom/EventTarget.h b/Source/WebCore/dom/EventTarget.h index 81eeb7f..a03801b 100644 --- a/Source/WebCore/dom/EventTarget.h +++ b/Source/WebCore/dom/EventTarget.h @@ -49,6 +49,7 @@ namespace WebCore { class EventSource; class FileReader; class FileWriter; + class IDBDatabase; class IDBRequest; class IDBTransaction; class JavaScriptAudioNode; @@ -138,6 +139,7 @@ namespace WebCore { #endif #if ENABLE(INDEXED_DATABASE) + virtual IDBDatabase* toIDBDatabase(); virtual IDBRequest* toIDBRequest(); virtual IDBTransaction* toIDBTransaction(); #endif diff --git a/Source/WebCore/dom/InputElement.h b/Source/WebCore/dom/InputElement.h index 2d5606d..02ac5cf 100644 --- a/Source/WebCore/dom/InputElement.h +++ b/Source/WebCore/dom/InputElement.h @@ -59,6 +59,8 @@ public: virtual String value() const = 0; virtual void setValue(const String&, bool sendChangeEvent = false) = 0; virtual void setValueForUser(const String&) = 0; + // The value which is drawn by a renderer. + virtual String visibleValue() const = 0; // Returns true if the specified string can be set as the value of InputElement. virtual bool isAcceptableValue(const String&) const = 0; diff --git a/Source/WebCore/dom/NamedNodeMap.cpp b/Source/WebCore/dom/NamedNodeMap.cpp index 0e2861e..2861226 100644 --- a/Source/WebCore/dom/NamedNodeMap.cpp +++ b/Source/WebCore/dom/NamedNodeMap.cpp @@ -357,7 +357,7 @@ bool NamedNodeMap::mappedMapsEquivalent(const NamedNodeMap* otherMap) const ASSERT(attr->isMappedAttribute()); Attribute* otherAttr = otherMap->getAttributeItem(attr->name()); - if (!otherAttr || attr->value() != otherAttr->value()) + if (!otherAttr || !otherAttr->decl() || attr->value() != otherAttr->value()) return false; if (!attr->decl()->propertiesEqual(otherAttr->decl())) return false; diff --git a/Source/WebCore/dom/Node.cpp b/Source/WebCore/dom/Node.cpp index 275e370..72592ae 100644 --- a/Source/WebCore/dom/Node.cpp +++ b/Source/WebCore/dom/Node.cpp @@ -1641,7 +1641,7 @@ PassRefPtr<Element> Node::querySelector(const String& selectors, ExceptionCode& // FIXME: we could also optimize for the the [id="foo"] case if (strictParsing && inDocument() && querySelectorList.hasOneSelector() && querySelectorList.first()->m_match == CSSSelector::Id) { - Element* element = document()->getElementById(querySelectorList.first()->m_value); + Element* element = document()->getElementById(querySelectorList.first()->value()); if (element && (isDocumentNode() || element->isDescendantOf(this)) && selectorChecker.checkSelector(querySelectorList.first(), element)) return element; return 0; @@ -2913,6 +2913,18 @@ void Node::dispatchSimulatedClick(PassRefPtr<Event> event, bool sendMouseEvents, gNodesDispatchingSimulatedClicks->remove(this); } +// FIXME: Once https://bugs.webkit.org/show_bug.cgi?id=52963 lands, this should +// be greatly improved. See https://bugs.webkit.org/show_bug.cgi?id=54025. +static Node* pullOutOfShadow(Node* node) +{ + Node* outermostShadowBoundary = node; + for (Node* n = node; n; n = n->parentOrHostNode()) { + if (n->isShadowRoot()) + outermostShadowBoundary = n->parentOrHostNode(); + } + return outermostShadowBoundary; +} + bool Node::dispatchMouseEvent(const AtomicString& eventType, int button, int detail, int pageX, int pageY, int screenX, int screenY, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, @@ -2935,7 +2947,7 @@ bool Node::dispatchMouseEvent(const AtomicString& eventType, int button, int det bool swallowEvent = false; // Attempting to dispatch with a non-EventTarget relatedTarget causes the relatedTarget to be silently ignored. - RefPtr<Node> relatedTarget = relatedTargetArg; + RefPtr<Node> relatedTarget = pullOutOfShadow(relatedTargetArg); int adjustedPageX = pageX; int adjustedPageY = pageY; diff --git a/Source/WebCore/dom/Position.cpp b/Source/WebCore/dom/Position.cpp index 6749ca9..cbad302 100644 --- a/Source/WebCore/dom/Position.cpp +++ b/Source/WebCore/dom/Position.cpp @@ -27,7 +27,6 @@ #include "Position.h" #include "CSSComputedStyleDeclaration.h" -#include "CharacterNames.h" #include "Logging.h" #include "PositionIterator.h" #include "RenderBlock.h" @@ -38,6 +37,7 @@ #include "visible_units.h" #include <stdio.h> #include <wtf/text/CString.h> +#include <wtf/unicode/CharacterNames.h> namespace WebCore { diff --git a/Source/WebCore/dom/ProcessingInstruction.cpp b/Source/WebCore/dom/ProcessingInstruction.cpp index e7dea48..ed329bc 100644 --- a/Source/WebCore/dom/ProcessingInstruction.cpp +++ b/Source/WebCore/dom/ProcessingInstruction.cpp @@ -168,7 +168,7 @@ void ProcessingInstruction::checkStyleSheet() { String charset = attrs.get("charset"); if (charset.isEmpty()) - charset = document()->frame()->loader()->writer()->encoding(); + charset = document()->charset(); m_cachedSheet = document()->cachedResourceLoader()->requestCSSStyleSheet(url, charset); } diff --git a/Source/WebCore/dom/Range.cpp b/Source/WebCore/dom/Range.cpp index a41fc49..e224843 100644 --- a/Source/WebCore/dom/Range.cpp +++ b/Source/WebCore/dom/Range.cpp @@ -594,6 +594,21 @@ bool Range::intersectsNode(Node* refNode, ExceptionCode& ec) return true; // all other cases } +static inline Node* highestAncestorUnderCommonRoot(Node* node, Node* commonRoot) +{ + if (node == commonRoot) + return 0; + + ASSERT(commonRoot->contains(node)); + + while (node->parentNode() != commonRoot) + node = node->parentNode(); + + return node; +} + +static inline unsigned lengthOfContentsInNode() { return numeric_limits<unsigned>::max(); } + PassRefPtr<DocumentFragment> Range::processContents(ActionType action, ExceptionCode& ec) { typedef Vector<RefPtr<Node> > NodeVector; @@ -601,7 +616,7 @@ PassRefPtr<DocumentFragment> Range::processContents(ActionType action, Exception RefPtr<DocumentFragment> fragment; if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) fragment = DocumentFragment::create(m_ownerDocument.get()); - + ec = 0; if (collapsed(ec)) return fragment.release(); @@ -613,68 +628,16 @@ PassRefPtr<DocumentFragment> Range::processContents(ActionType action, Exception return 0; ASSERT(commonRoot); - // what is the highest node that partially selects the start of the range? - Node* partialStart = 0; - if (m_start.container() != commonRoot) { - partialStart = m_start.container(); - while (partialStart->parentNode() != commonRoot) - partialStart = partialStart->parentNode(); - } - - // what is the highest node that partially selects the end of the range? - Node* partialEnd = 0; - if (m_end.container() != commonRoot) { - partialEnd = m_end.container(); - while (partialEnd->parentNode() != commonRoot) - partialEnd = partialEnd->parentNode(); - } - - // Simple case: the start and end containers are the same. We just grab - // everything >= start offset and < end offset if (m_start.container() == m_end.container()) { - Node::NodeType startNodeType = m_start.container()->nodeType(); - if (startNodeType == Node::TEXT_NODE || startNodeType == Node::CDATA_SECTION_NODE || startNodeType == Node::COMMENT_NODE) { - if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { - RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_start.container()->cloneNode(true)); - c->deleteData(m_end.offset(), c->length() - m_end.offset(), ec); - c->deleteData(0, m_start.offset(), ec); - fragment->appendChild(c.release(), ec); - } - if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) - static_cast<CharacterData*>(m_start.container())->deleteData(m_start.offset(), m_end.offset() - m_start.offset(), ec); - } else if (startNodeType == Node::PROCESSING_INSTRUCTION_NODE) { - if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { - RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_start.container()->cloneNode(true)); - c->setData(c->data().substring(m_start.offset(), m_end.offset() - m_start.offset()), ec); - fragment->appendChild(c.release(), ec); - } - if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) { - ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(m_start.container()); - String data(pi->data()); - data.remove(m_start.offset(), m_end.offset() - m_start.offset()); - pi->setData(data, ec); - } - } else { - RefPtr<Node> n = m_start.container()->firstChild(); - int i; - for (i = 0; n && i < m_start.offset(); i++) // skip until start offset - n = n->nextSibling(); - int endOffset = m_end.offset(); - RefPtr<Node> next; - for (; n && i < endOffset; n = next, i++) { // delete until end offset - next = n->nextSibling(); - if (action == EXTRACT_CONTENTS) - fragment->appendChild(n, ec); // will remove n from its parent - else if (action == CLONE_CONTENTS) - fragment->appendChild(n->cloneNode(true), ec); - else - toContainerNode(m_start.container())->removeChild(n.get(), ec); - } - } - return fragment.release(); + processContentsBetweenOffsets(action, fragment, m_start.container(), m_start.offset(), m_end.offset(), ec); + return fragment; } - // Complex case: Start and end containers are different. + // what is the highest node that partially selects the start / end of the range? + Node* partialStart = highestAncestorUnderCommonRoot(m_start.container(), commonRoot); + Node* partialEnd = highestAncestorUnderCommonRoot(m_end.container(), commonRoot); + + // Start and end containers are different. // There are three possibilities here: // 1. Start container == commonRoot (End container must be a descendant) // 2. End container == commonRoot (Start container must be a descendant) @@ -693,49 +656,7 @@ PassRefPtr<DocumentFragment> Range::processContents(ActionType action, Exception RefPtr<Node> leftContents; if (m_start.container() != commonRoot) { - // process the left-hand side of the range, up until the last ancestor of - // start container before commonRoot - Node::NodeType startNodeType = m_start.container()->nodeType(); - if (startNodeType == Node::TEXT_NODE || startNodeType == Node::CDATA_SECTION_NODE || startNodeType == Node::COMMENT_NODE) { - if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { - RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_start.container()->cloneNode(true)); - c->deleteData(0, m_start.offset(), ec); - leftContents = c.release(); - } - if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) - static_cast<CharacterData*>(m_start.container())->deleteData( - m_start.offset(), static_cast<CharacterData*>(m_start.container())->length() - m_start.offset(), ec); - } else if (startNodeType == Node::PROCESSING_INSTRUCTION_NODE) { - if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { - RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_start.container()->cloneNode(true)); - c->setData(c->data().substring(m_start.offset()), ec); - leftContents = c.release(); - } - if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) { - ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(m_start.container()); - String data(pi->data()); - pi->setData(data.left(m_start.offset()), ec); - } - } else { - if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) - leftContents = m_start.container()->cloneNode(false); - NodeVector nodes; - Node* n = m_start.container()->firstChild(); - for (int i = 0; n; n = n->nextSibling(), i++) { - if (i < m_start.offset()) - continue; // Skip until start offset. - nodes.append(n); - } - for (NodeVector::const_iterator it = nodes.begin(); it != nodes.end(); it++) { - Node* n = it->get(); - if (action == EXTRACT_CONTENTS) - leftContents->appendChild(n, ec); // Will remove n from start container. - else if (action == CLONE_CONTENTS) - leftContents->appendChild(n->cloneNode(true), ec); - else - toContainerNode(m_start.container())->removeChild(n, ec); - } - } + leftContents = processContentsBetweenOffsets(action, 0, m_start.container(), m_start.offset(), lengthOfContentsInNode(), ec); NodeVector ancestorNodes; for (ContainerNode* n = m_start.container()->parentNode(); n && n != commonRoot; n = n->parentNode()) @@ -767,46 +688,7 @@ PassRefPtr<DocumentFragment> Range::processContents(ActionType action, Exception RefPtr<Node> rightContents; if (m_end.container() != commonRoot) { - // delete the right-hand side of the range, up until the last ancestor of - // end container before commonRoot - Node::NodeType endNodeType = m_end.container()->nodeType(); - if (endNodeType == Node::TEXT_NODE || endNodeType == Node::CDATA_SECTION_NODE || endNodeType == Node::COMMENT_NODE) { - if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { - RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_end.container()->cloneNode(true)); - c->deleteData(m_end.offset(), static_cast<CharacterData*>(m_end.container())->length() - m_end.offset(), ec); - rightContents = c; - } - if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) - static_cast<CharacterData*>(m_end.container())->deleteData(0, m_end.offset(), ec); - } else if (endNodeType == Node::PROCESSING_INSTRUCTION_NODE) { - if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { - RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_end.container()->cloneNode(true)); - c->setData(c->data().left(m_end.offset()), ec); - rightContents = c.release(); - } - if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) { - ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(m_end.container()); - pi->setData(pi->data().substring(m_end.offset()), ec); - } - } else { - if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) - rightContents = m_end.container()->cloneNode(false); - Node* n = m_end.container()->firstChild(); - if (n && m_end.offset()) { - NodeVector nodes; - for (int i = 0; i < m_end.offset() && n; i++, n = n->nextSibling()) - nodes.append(n); - for (int i = nodes.size() - 1; i >= 0; i--) { - n = nodes[i].get(); - if (action == EXTRACT_CONTENTS) - rightContents->insertBefore(n, rightContents->firstChild(), ec); // will remove n from its parent - else if (action == CLONE_CONTENTS) - rightContents->insertBefore(n->cloneNode(true), rightContents->firstChild(), ec); - else - toContainerNode(m_end.container())->removeChild(n, ec); - } - } - } + rightContents = processContentsBetweenOffsets(action, 0, m_end.container(), 0, m_end.offset(), ec); ContainerNode* rightParent = m_end.container()->parentNode(); Node* n = m_end.container()->previousSibling(); @@ -892,6 +774,98 @@ PassRefPtr<DocumentFragment> Range::processContents(ActionType action, Exception return fragment.release(); } +PassRefPtr<Node> Range::processContentsBetweenOffsets(ActionType action, PassRefPtr<DocumentFragment> fragment, + Node* container, unsigned startOffset, unsigned endOffset, ExceptionCode& ec) +{ + ASSERT(container); + ASSERT(startOffset <= endOffset); + + RefPtr<Node> result; + switch (container->nodeType()) { + case Node::TEXT_NODE: + case Node::CDATA_SECTION_NODE: + case Node::COMMENT_NODE: + ASSERT(endOffset <= static_cast<CharacterData*>(container)->length() || endOffset == lengthOfContentsInNode()); + if (endOffset == lengthOfContentsInNode()) + endOffset = static_cast<CharacterData*>(container)->length(); + if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { + RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(container->cloneNode(true)); + if (c->length() - endOffset) + c->deleteData(endOffset, c->length() - endOffset, ec); + if (startOffset) + c->deleteData(0, startOffset, ec); + if (fragment) { + result = fragment; + result->appendChild(c.release(), ec); + } else + result = c.release(); + } + if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) + static_cast<CharacterData*>(container)->deleteData(startOffset, endOffset - startOffset, ec); + break; + case Node::PROCESSING_INSTRUCTION_NODE: + ASSERT(endOffset <= static_cast<ProcessingInstruction*>(container)->data().length() || endOffset == lengthOfContentsInNode()); + if (endOffset == lengthOfContentsInNode()) + endOffset = static_cast<ProcessingInstruction*>(container)->data().length(); + if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { + RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(container->cloneNode(true)); + c->setData(c->data().substring(startOffset, endOffset - startOffset), ec); + if (fragment) { + result = fragment; + result->appendChild(c.release(), ec); + } else + result = c.release(); + } + if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) { + ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(container); + String data(pi->data()); + data.remove(startOffset, endOffset - startOffset); + pi->setData(data, ec); + } + break; + case Node::ELEMENT_NODE: + case Node::ATTRIBUTE_NODE: + case Node::ENTITY_REFERENCE_NODE: + case Node::ENTITY_NODE: + case Node::DOCUMENT_NODE: + case Node::DOCUMENT_TYPE_NODE: + case Node::DOCUMENT_FRAGMENT_NODE: + case Node::NOTATION_NODE: + case Node::XPATH_NAMESPACE_NODE: + // FIXME: Should we assert that some nodes never appear here? + if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) { + if (fragment) + result = fragment; + else + result = container->cloneNode(false); + } + + Node* n = container->firstChild(); + Vector<RefPtr<Node> > nodes; + for (unsigned i = startOffset; n && i; i--) + n = n->nextSibling(); + for (unsigned i = startOffset; n && i < endOffset; i++, n = n->nextSibling()) + nodes.append(n); + + for (unsigned i = 0; i < nodes.size(); i++) { + switch (action) { + case DELETE_CONTENTS: + container->removeChild(nodes[i].get(), ec); + break; + case EXTRACT_CONTENTS: + result->appendChild(nodes[i].release(), ec); // will remove n from its parent + break; + case CLONE_CONTENTS: + result->appendChild(nodes[i]->cloneNode(true), ec); + break; + } + } + break; + } + + return result; +} + PassRefPtr<DocumentFragment> Range::extractContents(ExceptionCode& ec) { checkDeleteExtract(ec); @@ -1079,7 +1053,7 @@ PassRefPtr<DocumentFragment> Range::createContextualFragment(const String& marku // Logic from deprecatedCreateContextualFragment should just be moved into // this function. Range::createContextualFragment semantics do not make // sense for the rest of the DOM implementation to use. - RefPtr<DocumentFragment> fragment = static_cast<HTMLElement*>(element)->deprecatedCreateContextualFragment(markup); + RefPtr<DocumentFragment> fragment = toHTMLElement(element)->deprecatedCreateContextualFragment(markup); if (!fragment) { ec = NOT_SUPPORTED_ERR; return 0; diff --git a/Source/WebCore/dom/Range.h b/Source/WebCore/dom/Range.h index aea76e1..86c1354 100644 --- a/Source/WebCore/dom/Range.h +++ b/Source/WebCore/dom/Range.h @@ -147,6 +147,7 @@ private: enum ActionType { DELETE_CONTENTS, EXTRACT_CONTENTS, CLONE_CONTENTS }; PassRefPtr<DocumentFragment> processContents(ActionType, ExceptionCode&); + PassRefPtr<Node> processContentsBetweenOffsets(ActionType, PassRefPtr<DocumentFragment>, Node*, unsigned startOffset, unsigned endOffset, ExceptionCode&); RefPtr<Document> m_ownerDocument; RangeBoundaryPoint m_start; diff --git a/Source/WebCore/dom/RequestAnimationFrameCallback.h b/Source/WebCore/dom/RequestAnimationFrameCallback.h index 819e495..3edeb9e 100644 --- a/Source/WebCore/dom/RequestAnimationFrameCallback.h +++ b/Source/WebCore/dom/RequestAnimationFrameCallback.h @@ -40,7 +40,7 @@ namespace WebCore { class RequestAnimationFrameCallback : public RefCounted<RequestAnimationFrameCallback> { public: virtual ~RequestAnimationFrameCallback() { } - virtual bool handleEvent() = 0; + virtual bool handleEvent(DOMTimeStamp) = 0; RefPtr<Element> m_element; int m_id; diff --git a/Source/WebCore/dom/RequestAnimationFrameCallback.idl b/Source/WebCore/dom/RequestAnimationFrameCallback.idl index 8d232e5..1905193 100644 --- a/Source/WebCore/dom/RequestAnimationFrameCallback.idl +++ b/Source/WebCore/dom/RequestAnimationFrameCallback.idl @@ -32,6 +32,6 @@ module core { interface [ Callback=FunctionOnly,Conditional=REQUEST_ANIMATION_FRAME ] RequestAnimationFrameCallback{ - boolean handleEvent(); + boolean handleEvent(in DOMTimeStamp time); }; } diff --git a/Source/WebCore/dom/ScriptElement.cpp b/Source/WebCore/dom/ScriptElement.cpp index 747f7a1..1939a08 100644 --- a/Source/WebCore/dom/ScriptElement.cpp +++ b/Source/WebCore/dom/ScriptElement.cpp @@ -292,10 +292,8 @@ String ScriptElement::scriptCharset() const String charset = charsetAttributeValue().stripWhiteSpace(); // If charset has not been declared in script tag, fall back to frame encoding. - if (charset.isEmpty()) { - if (Frame* frame = m_element->document()->frame()) - charset = frame->loader()->writer()->encoding(); - } + if (charset.isEmpty()) + charset = m_element->document()->charset(); return charset; } diff --git a/Source/WebCore/dom/ScriptExecutionContext.cpp b/Source/WebCore/dom/ScriptExecutionContext.cpp index 9fdf85e..19267c6 100644 --- a/Source/WebCore/dom/ScriptExecutionContext.cpp +++ b/Source/WebCore/dom/ScriptExecutionContext.cpp @@ -30,6 +30,7 @@ #include "ActiveDOMObject.h" #include "Blob.h" #include "BlobURL.h" +#include "DOMURL.h" #include "Database.h" #include "DatabaseTask.h" #include "DatabaseThread.h" @@ -83,7 +84,9 @@ public: }; ScriptExecutionContext::ScriptExecutionContext() - : m_inDispatchErrorEvent(false) + : m_iteratingActiveDOMObjects(false) + , m_inDestructor(false) + , m_inDispatchErrorEvent(false) #if ENABLE(DATABASE) , m_hasOpenDatabases(false) #endif @@ -92,10 +95,12 @@ ScriptExecutionContext::ScriptExecutionContext() ScriptExecutionContext::~ScriptExecutionContext() { - HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end(); - for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) { - ASSERT(iter->first->scriptExecutionContext() == this); - iter->first->contextDestroyed(); + m_inDestructor = true; + for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != m_activeDOMObjects.end(); iter = m_activeDOMObjects.begin()) { + ActiveDOMObject* object = iter->first; + m_activeDOMObjects.remove(iter); + ASSERT(object->scriptExecutionContext() == this); + object->contextDestroyed(); } HashSet<MessagePort*>::iterator messagePortsEnd = m_messagePorts.end(); @@ -120,6 +125,12 @@ ScriptExecutionContext::~ScriptExecutionContext() HashSet<String>::iterator publicBlobURLsEnd = m_publicBlobURLs.end(); for (HashSet<String>::iterator iter = m_publicBlobURLs.begin(); iter != publicBlobURLsEnd; ++iter) ThreadableBlobRegistry::unregisterBlobURL(KURL(ParsedURLString, *iter)); + + HashSet<DOMURL*>::iterator domUrlsEnd = m_domUrls.end(); + for (HashSet<DOMURL*>::iterator iter = m_domUrls.begin(); iter != domUrlsEnd; ++iter) { + ASSERT((*iter)->scriptExecutionContext() == this); + (*iter)->contextDestroyed(); + } #endif } @@ -194,46 +205,70 @@ void ScriptExecutionContext::destroyedMessagePort(MessagePort* port) m_messagePorts.remove(port); } +#if ENABLE(BLOB) +void ScriptExecutionContext::createdDomUrl(DOMURL* url) +{ + ASSERT(url); + m_domUrls.add(url); +} + +void ScriptExecutionContext::destroyedDomUrl(DOMURL* url) +{ + ASSERT(url); + m_domUrls.remove(url); +} +#endif + bool ScriptExecutionContext::canSuspendActiveDOMObjects() { // No protection against m_activeDOMObjects changing during iteration: canSuspend() shouldn't execute arbitrary JS. + m_iteratingActiveDOMObjects = true; HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end(); for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) { ASSERT(iter->first->scriptExecutionContext() == this); - if (!iter->first->canSuspend()) + if (!iter->first->canSuspend()) { + m_iteratingActiveDOMObjects = false; return false; - } + } + } + m_iteratingActiveDOMObjects = false; return true; } void ScriptExecutionContext::suspendActiveDOMObjects(ActiveDOMObject::ReasonForSuspension why) { // No protection against m_activeDOMObjects changing during iteration: suspend() shouldn't execute arbitrary JS. + m_iteratingActiveDOMObjects = true; HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end(); for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) { ASSERT(iter->first->scriptExecutionContext() == this); iter->first->suspend(why); } + m_iteratingActiveDOMObjects = false; } void ScriptExecutionContext::resumeActiveDOMObjects() { // No protection against m_activeDOMObjects changing during iteration: resume() shouldn't execute arbitrary JS. + m_iteratingActiveDOMObjects = true; HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end(); for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) { ASSERT(iter->first->scriptExecutionContext() == this); iter->first->resume(); } + m_iteratingActiveDOMObjects = false; } void ScriptExecutionContext::stopActiveDOMObjects() { // No protection against m_activeDOMObjects changing during iteration: stop() shouldn't execute arbitrary JS. + m_iteratingActiveDOMObjects = true; HashMap<ActiveDOMObject*, void*>::iterator activeObjectsEnd = m_activeDOMObjects.end(); for (HashMap<ActiveDOMObject*, void*>::iterator iter = m_activeDOMObjects.begin(); iter != activeObjectsEnd; ++iter) { ASSERT(iter->first->scriptExecutionContext() == this); iter->first->stop(); } + m_iteratingActiveDOMObjects = false; // Also close MessagePorts. If they were ActiveDOMObjects (they could be) then they could be stopped instead. closeMessagePorts(); @@ -243,12 +278,17 @@ void ScriptExecutionContext::createdActiveDOMObject(ActiveDOMObject* object, voi { ASSERT(object); ASSERT(upcastPointer); + ASSERT(!m_inDestructor); + if (m_iteratingActiveDOMObjects) + CRASH(); m_activeDOMObjects.add(object, upcastPointer); } void ScriptExecutionContext::destroyedActiveDOMObject(ActiveDOMObject* object) { ASSERT(object); + if (m_iteratingActiveDOMObjects) + CRASH(); m_activeDOMObjects.remove(object); } @@ -265,6 +305,17 @@ void ScriptExecutionContext::setSecurityOrigin(PassRefPtr<SecurityOrigin> securi m_securityOrigin = securityOrigin; } +bool ScriptExecutionContext::sanitizeScriptError(String& errorMessage, int& lineNumber, String& sourceURL) +{ + KURL targetURL = completeURL(sourceURL); + if (securityOrigin()->canRequest(targetURL)) + return false; + errorMessage = "Script error."; + sourceURL = String(); + lineNumber = 0; + return true; +} + void ScriptExecutionContext::reportException(const String& errorMessage, int lineNumber, const String& sourceURL, PassRefPtr<ScriptCallStack> callStack) { if (m_inDispatchErrorEvent) { @@ -294,9 +345,14 @@ bool ScriptExecutionContext::dispatchErrorEvent(const String& errorMessage, int if (!target) return false; + String message = errorMessage; + int line = lineNumber; + String sourceName = sourceURL; + sanitizeScriptError(message, line, sourceName); + ASSERT(!m_inDispatchErrorEvent); m_inDispatchErrorEvent = true; - RefPtr<ErrorEvent> errorEvent = ErrorEvent::create(errorMessage, sourceURL, lineNumber); + RefPtr<ErrorEvent> errorEvent = ErrorEvent::create(message, sourceName, line); target->dispatchEvent(errorEvent); m_inDispatchErrorEvent = false; return errorEvent->defaultPrevented(); diff --git a/Source/WebCore/dom/ScriptExecutionContext.h b/Source/WebCore/dom/ScriptExecutionContext.h index b57b75a..642906c 100644 --- a/Source/WebCore/dom/ScriptExecutionContext.h +++ b/Source/WebCore/dom/ScriptExecutionContext.h @@ -60,6 +60,7 @@ namespace WebCore { class FileThread; #endif class MessagePort; + class DOMURL; class SecurityOrigin; class ScriptCallStack; @@ -90,6 +91,7 @@ namespace WebCore { SecurityOrigin* securityOrigin() const { return m_securityOrigin.get(); } + bool sanitizeScriptError(String& errorMessage, int& lineNumber, String& sourceURL); void reportException(const String& errorMessage, int lineNumber, const String& sourceURL, PassRefPtr<ScriptCallStack>); virtual void addMessage(MessageSource, MessageType, MessageLevel, const String& message, unsigned lineNumber, const String& sourceURL, PassRefPtr<ScriptCallStack>) = 0; @@ -112,6 +114,11 @@ namespace WebCore { void destroyedMessagePort(MessagePort*); const HashSet<MessagePort*>& messagePorts() const { return m_messagePorts; } +#if ENABLE(BLOB) + void createdDomUrl(DOMURL*); + void destroyedDomUrl(DOMURL*); + const HashSet<DOMURL*>& domUrls() const { return m_domUrls; } +#endif void ref() { refScriptExecutionContext(); } void deref() { derefScriptExecutionContext(); } @@ -166,11 +173,14 @@ namespace WebCore { HashSet<MessagePort*> m_messagePorts; HashMap<ActiveDOMObject*, void*> m_activeDOMObjects; + bool m_iteratingActiveDOMObjects; + bool m_inDestructor; HashMap<int, DOMTimer*> m_timeouts; #if ENABLE(BLOB) HashSet<String> m_publicBlobURLs; + HashSet<DOMURL*> m_domUrls; #endif virtual void refScriptExecutionContext() = 0; diff --git a/Source/WebCore/dom/ScriptableDocumentParser.cpp b/Source/WebCore/dom/ScriptableDocumentParser.cpp index 0712a15..708dc1d 100644 --- a/Source/WebCore/dom/ScriptableDocumentParser.cpp +++ b/Source/WebCore/dom/ScriptableDocumentParser.cpp @@ -30,7 +30,7 @@ namespace WebCore { ScriptableDocumentParser::ScriptableDocumentParser(Document* document) : DecodedDataDocumentParser(document) - , m_xssAuditor(0) + , m_wasCreatedByScript(false) { } diff --git a/Source/WebCore/dom/ScriptableDocumentParser.h b/Source/WebCore/dom/ScriptableDocumentParser.h index d9bf85c..35c2767 100644 --- a/Source/WebCore/dom/ScriptableDocumentParser.h +++ b/Source/WebCore/dom/ScriptableDocumentParser.h @@ -31,8 +31,6 @@ namespace WebCore { -class XSSAuditor; - class ScriptableDocumentParser : public DecodedDataDocumentParser { public: // Only used by Document::open for deciding if its safe to act on a @@ -49,8 +47,8 @@ public: virtual int lineNumber() const = 0; virtual TextPosition0 textPosition() const = 0; - XSSAuditor* xssAuditor() const { return m_xssAuditor; } - void setXSSAuditor(XSSAuditor* auditor) { m_xssAuditor = auditor; } + void setWasCreatedByScript(bool wasCreatedByScript) { m_wasCreatedByScript = wasCreatedByScript; } + bool wasCreatedByScript() const { return m_wasCreatedByScript; } protected: explicit ScriptableDocumentParser(Document*); @@ -58,8 +56,8 @@ protected: private: virtual ScriptableDocumentParser* asScriptableDocumentParser() { return this; } - // The XSSAuditor associated with this document parser. - XSSAuditor* m_xssAuditor; + // http://www.whatwg.org/specs/web-apps/current-work/#script-created-parser + bool m_wasCreatedByScript; }; } diff --git a/Source/WebCore/dom/SelectElement.cpp b/Source/WebCore/dom/SelectElement.cpp index 661ba88..a4da0ae 100644 --- a/Source/WebCore/dom/SelectElement.cpp +++ b/Source/WebCore/dom/SelectElement.cpp @@ -22,7 +22,6 @@ #include "SelectElement.h" #include "Attribute.h" -#include "CharacterNames.h" #include "Chrome.h" #include "ChromeClient.h" #include "Element.h" @@ -31,7 +30,6 @@ #include "FormDataList.h" #include "Frame.h" #include "HTMLFormElement.h" -#include "HTMLKeygenElement.h" #include "HTMLNames.h" #include "HTMLSelectElement.h" #include "KeyboardEvent.h" @@ -43,6 +41,7 @@ #include "RenderMenuList.h" #include "SpatialNavigation.h" #include <wtf/Assertions.h> +#include <wtf/unicode/CharacterNames.h> #if ENABLE(WML) #include "WMLNames.h" @@ -315,11 +314,14 @@ int SelectElement::selectedIndex(const SelectElementData& data, const Element* e void SelectElement::setSelectedIndex(SelectElementData& data, Element* element, int optionIndex, bool deselect, bool fireOnChangeNow, bool userDrivenChange) { - const Vector<Element*>& items = data.listItems(element); - int listIndex = optionToListIndex(data, element, optionIndex); + if (optionIndex == -1 && !deselect && !data.multiple()) + optionIndex = nextSelectableListIndex(data, element, -1); if (!data.multiple()) deselect = true; + const Vector<Element*>& items = data.listItems(element); + int listIndex = optionToListIndex(data, element, optionIndex); + Element* excludeElement = 0; if (OptionElement* optionElement = (listIndex >= 0 ? toOptionElement(items[listIndex]) : 0)) { excludeElement = items[listIndex]; @@ -1024,12 +1026,8 @@ const Vector<Element*>& SelectElementData::listItems(const Element* element) con SelectElement* toSelectElement(Element* element) { - if (element->isHTMLElement()) { - if (element->hasTagName(HTMLNames::selectTag)) - return static_cast<HTMLSelectElement*>(element); - if (element->hasTagName(HTMLNames::keygenTag)) - return static_cast<HTMLKeygenElement*>(element); - } + if (element->isHTMLElement() && element->hasTagName(HTMLNames::selectTag)) + return static_cast<HTMLSelectElement*>(element); #if ENABLE(WML) if (element->isWMLElement() && element->hasTagName(WMLNames::selectTag)) diff --git a/Source/WebCore/dom/SelectorNodeList.cpp b/Source/WebCore/dom/SelectorNodeList.cpp index 039a29f..7611488 100644 --- a/Source/WebCore/dom/SelectorNodeList.cpp +++ b/Source/WebCore/dom/SelectorNodeList.cpp @@ -50,8 +50,8 @@ PassRefPtr<StaticNodeList> createSelectorNodeList(Node* rootNode, const CSSSelec CSSStyleSelector::SelectorChecker selectorChecker(document, strictParsing); - if (strictParsing && rootNode->inDocument() && onlySelector && onlySelector->m_match == CSSSelector::Id && !document->containsMultipleElementsWithId(onlySelector->m_value)) { - Element* element = document->getElementById(onlySelector->m_value); + if (strictParsing && rootNode->inDocument() && onlySelector && onlySelector->m_match == CSSSelector::Id && !document->containsMultipleElementsWithId(onlySelector->value())) { + Element* element = document->getElementById(onlySelector->value()); if (element && (rootNode->isDocumentNode() || element->isDescendantOf(rootNode)) && selectorChecker.checkSelector(onlySelector, element)) nodes.append(element); } else { diff --git a/Source/WebCore/dom/Text.cpp b/Source/WebCore/dom/Text.cpp index 47c532e..34266f1 100644 --- a/Source/WebCore/dom/Text.cpp +++ b/Source/WebCore/dom/Text.cpp @@ -23,6 +23,7 @@ #include "Text.h" #include "ExceptionCode.h" +#include "RenderCombineText.h" #include "RenderText.h" #include "TextBreakIterator.h" #include <wtf/text/CString.h> @@ -237,7 +238,7 @@ bool Text::rendererIsNeeded(RenderStyle *style) return true; } -RenderObject* Text::createRenderer(RenderArena* arena, RenderStyle*) +RenderObject* Text::createRenderer(RenderArena* arena, RenderStyle* style) { #if ENABLE(SVG) Node* parentOrHost = parentOrHostNode(); @@ -248,7 +249,10 @@ RenderObject* Text::createRenderer(RenderArena* arena, RenderStyle*) ) return new (arena) RenderSVGInlineText(this, dataImpl()); #endif - + + if (style->hasTextCombine()) + return new (arena) RenderCombineText(this, dataImpl()); + return new (arena) RenderText(this, dataImpl()); } diff --git a/Source/WebCore/dom/TextEvent.h b/Source/WebCore/dom/TextEvent.h index d770d38..26c8b93 100644 --- a/Source/WebCore/dom/TextEvent.h +++ b/Source/WebCore/dom/TextEvent.h @@ -51,6 +51,7 @@ namespace WebCore { virtual bool isTextEvent() const; bool isLineBreak() const { return m_inputType == TextEventInputLineBreak; } + bool isComposition() const { return m_inputType == TextEventInputComposition; } bool isBackTab() const { return m_inputType == TextEventInputBackTab; } bool isPaste() const { return m_inputType == TextEventInputPaste; } bool isDrop() const { return m_inputType == TextEventInputDrop; } diff --git a/Source/WebCore/dom/TextEventInputType.h b/Source/WebCore/dom/TextEventInputType.h index 2522ec4..f5a05eb 100644 --- a/Source/WebCore/dom/TextEventInputType.h +++ b/Source/WebCore/dom/TextEventInputType.h @@ -31,6 +31,7 @@ namespace WebCore { enum TextEventInputType { TextEventInputKeyboard, // any newline characters in the text are line breaks only, not paragraph separators. TextEventInputLineBreak, // any tab characters in the text are backtabs. + TextEventInputComposition, TextEventInputBackTab, TextEventInputPaste, TextEventInputDrop, diff --git a/Source/WebCore/dom/ViewportArguments.cpp b/Source/WebCore/dom/ViewportArguments.cpp index d3026e7..6dd1b8a 100644 --- a/Source/WebCore/dom/ViewportArguments.cpp +++ b/Source/WebCore/dom/ViewportArguments.cpp @@ -50,30 +50,6 @@ ViewportAttributes computeViewportAttributes(ViewportArguments args, int desktop ASSERT(availableWidth > 0 && availableHeight > 0); - switch (int(args.width)) { - case ViewportArguments::ValueDesktopWidth: - args.width = desktopWidth; - break; - case ViewportArguments::ValueDeviceWidth: - args.width = deviceWidth; - break; - case ViewportArguments::ValueDeviceHeight: - args.width = deviceHeight; - break; - } - - switch (int(args.height)) { - case ViewportArguments::ValueDesktopWidth: - args.height = desktopWidth; - break; - case ViewportArguments::ValueDeviceWidth: - args.height = deviceWidth; - break; - case ViewportArguments::ValueDeviceHeight: - args.height = deviceHeight; - break; - } - switch (int(args.targetDensityDpi)) { case ViewportArguments::ValueDeviceDPI: args.targetDensityDpi = deviceDPI; @@ -98,11 +74,30 @@ ViewportAttributes computeViewportAttributes(ViewportArguments args, int desktop availableHeight /= result.devicePixelRatio; deviceWidth /= result.devicePixelRatio; deviceHeight /= result.devicePixelRatio; + } - if (args.width != ViewportArguments::ValueAuto) - args.width /= result.devicePixelRatio; - if (args.height != ViewportArguments::ValueAuto) - args.height /= result.devicePixelRatio; + switch (int(args.width)) { + case ViewportArguments::ValueDesktopWidth: + args.width = desktopWidth; + break; + case ViewportArguments::ValueDeviceWidth: + args.width = deviceWidth; + break; + case ViewportArguments::ValueDeviceHeight: + args.width = deviceHeight; + break; + } + + switch (int(args.height)) { + case ViewportArguments::ValueDesktopWidth: + args.height = desktopWidth; + break; + case ViewportArguments::ValueDeviceWidth: + args.height = deviceWidth; + break; + case ViewportArguments::ValueDeviceHeight: + args.height = deviceHeight; + break; } // Clamp values to range defined by spec and resolve minimum-scale and maximum-scale values |