diff options
Diffstat (limited to 'Source/WebKit/chromium/src/WebFrameImpl.cpp')
-rw-r--r-- | Source/WebKit/chromium/src/WebFrameImpl.cpp | 259 |
1 files changed, 229 insertions, 30 deletions
diff --git a/Source/WebKit/chromium/src/WebFrameImpl.cpp b/Source/WebKit/chromium/src/WebFrameImpl.cpp index fb2a29540..0a9855f15 100644 --- a/Source/WebKit/chromium/src/WebFrameImpl.cpp +++ b/Source/WebKit/chromium/src/WebFrameImpl.cpp @@ -89,6 +89,7 @@ #include "EventHandler.h" #include "EventListenerWrapper.h" #include "FileSystemType.h" +#include "FindInPageCoordinates.h" #include "FocusController.h" #include "FontCache.h" #include "FormState.h" @@ -118,6 +119,7 @@ #include "PlatformSupport.h" #include "PluginDocument.h" #include "PrintContext.h" +#include "RenderBox.h" #include "RenderFrame.h" #include "RenderLayer.h" #include "RenderObject.h" @@ -192,6 +194,7 @@ #include "V8DirectoryEntry.h" #include "V8DOMFileSystem.h" #include "V8FileEntry.h" +#include "V8GCController.h" #include <public/WebFileSystem.h> #endif @@ -516,6 +519,12 @@ static WebDataSource* DataSourceForDocLoader(DocumentLoader* loader) return loader ? WebDataSourceImpl::fromDocumentLoader(loader) : 0; } +WebFrameImpl::FindMatch::FindMatch(PassRefPtr<Range> range, int ordinal) + : m_range(range) + , m_ordinal(ordinal) +{ +} + // WebFrame ------------------------------------------------------------------- class WebFrameImpl::DeferredScopeStringMatches { @@ -574,8 +583,8 @@ WebFrame* WebFrame::frameForCurrentContext() #if WEBKIT_USING_V8 WebFrame* WebFrame::frameForContext(v8::Handle<v8::Context> context) -{ - return WebFrameImpl::fromFrame(V8Proxy::retrieveFrame(context)); +{ + return WebFrameImpl::fromFrame(toFrameIfNotDetached(context)); } #endif @@ -801,10 +810,10 @@ WebAnimationController* WebFrameImpl::animationController() WebPerformance WebFrameImpl::performance() const { - if (!m_frame || !m_frame->domWindow()) + if (!m_frame) return WebPerformance(); - return WebPerformance(m_frame->domWindow()->performance()); + return WebPerformance(m_frame->document()->domWindow()->performance()); } NPObject* WebFrameImpl::windowObject() const @@ -879,7 +888,7 @@ void WebFrameImpl::addMessageToConsole(const WebConsoleMessage& message) return; } - frame()->domWindow()->console()->addMessage(OtherMessageSource, LogMessageType, webCoreMessageLevel, message.text); + frame()->document()->domWindow()->console()->addMessage(OtherMessageSource, LogMessageType, webCoreMessageLevel, message.text); } void WebFrameImpl::collectGarbage() @@ -890,7 +899,7 @@ void WebFrameImpl::collectGarbage() return; // FIXME: Move this to the ScriptController and make it JS neutral. #if USE(V8) - m_frame->script()->collectGarbage(); + V8GCController::collectGarbage(); #else notImplemented(); #endif @@ -952,7 +961,7 @@ v8::Local<v8::Context> WebFrameImpl::mainWorldScriptContext() const if (!m_frame) return v8::Local<v8::Context>(); - return V8Proxy::mainWorldContext(m_frame); + return ScriptController::mainWorldContext(m_frame); } v8::Handle<v8::Value> WebFrameImpl::createFileSystem(WebFileSystem::Type type, @@ -1172,7 +1181,7 @@ void WebFrameImpl::commitDocumentData(const char* data, size_t length) unsigned WebFrameImpl::unloadListenerCount() const { - return frame()->domWindow()->pendingUnloadEventListeners(); + return frame()->document()->domWindow()->pendingUnloadEventListeners(); } bool WebFrameImpl::isProcessingUserGesture() const @@ -1495,7 +1504,7 @@ VisiblePosition WebFrameImpl::visiblePositionForWindowPoint(const WebPoint& poin frame()->document()->renderView()->layer()->hitTest(request, result); - Node* node = EventHandler::targetNode(result); + Node* node = result.targetNode(); if (!node) return VisiblePosition(); @@ -1654,10 +1663,18 @@ bool WebFrameImpl::find(int identifier, m_activeMatch = frame()->editor()->findStringAndScrollToVisible(searchText, m_activeMatch.get(), findOptions); if (!m_activeMatch) { + // If we're finding next the next active match might not be in the current frame. + // In this case we don't want to clear the matches cache. + if (!options.findNext) + clearFindMatchesCache(); invalidateArea(InvalidateAll); return false; } +#if OS(ANDROID) + viewImpl()->zoomToFindInPageRect(frameView()->contentsToWindow(enclosingIntRect(RenderObject::absoluteBoundingBoxRectForRange(m_activeMatch.get())))); +#endif + setMarkerActive(m_activeMatch.get(), true); WebFrameImpl* oldActiveFrame = mainFrameImpl->m_currentActiveMatchFrame; mainFrameImpl->m_currentActiveMatchFrame = this; @@ -1705,6 +1722,7 @@ void WebFrameImpl::stopFinding(bool clearSelection) // Remove all markers for matches found and turn off the highlighting. frame()->document()->markers()->removeMarkers(DocumentMarker::TextMatch); frame()->editor()->setMarkedTextMatchesAreHighlighted(false); + clearFindMatchesCache(); // Let the frame know that we don't want tickmarks or highlighting anymore. invalidateArea(InvalidateAll); @@ -1727,6 +1745,10 @@ void WebFrameImpl::scopeStringMatches(int identifier, // Clear highlighting for this frame. if (frame()->editor()->markedTextMatchesAreHighlighted()) frame()->page()->unmarkAllTextMatches(); + + // Clear the tickmarks and results cache. + clearFindMatchesCache(); + // Clear the counters from last operation. m_lastMatchCount = 0; m_nextInvalidateAfter = 0; @@ -1825,6 +1847,8 @@ void WebFrameImpl::scopeStringMatches(int identifier, addMarker(resultRange.get(), foundActiveMatch); + m_findMatchesCache.append(FindMatch(resultRange.get(), m_lastMatchCount + matchCount)); + // Set the new start for the search range to be the end of the previous // result range. There is no need to use a VisiblePosition here, // since findPlainText will use a TextIterator to go over the visible @@ -1895,6 +1919,9 @@ void WebFrameImpl::increaseMatchCount(int count, int identifier) // This function should only be called on the mainframe. ASSERT(!parent()); + if (count) + ++m_findMatchMarkersVersion; + m_totalMatchCount += count; // Update the UI with the latest findings. @@ -1913,6 +1940,9 @@ void WebFrameImpl::reportFindInPageSelection(const WebRect& selectionRect, void WebFrameImpl::resetMatchCount() { + if (m_totalMatchCount > 0) + ++m_findMatchMarkersVersion; + m_totalMatchCount = 0; m_framesScopingCount = 0; } @@ -1927,57 +1957,215 @@ void WebFrameImpl::sendOrientationChangeEvent(int orientation) void WebFrameImpl::addEventListener(const WebString& eventType, WebDOMEventListener* listener, bool useCapture) { - DOMWindow* window = m_frame->domWindow(); - - EventListenerWrapper* listenerWrapper = - listener->createEventListenerWrapper(eventType, useCapture, window); - - m_frame->domWindow()->addEventListener(eventType, adoptRef(listenerWrapper), useCapture); + DOMWindow* window = m_frame->document()->domWindow(); + EventListenerWrapper* listenerWrapper = listener->createEventListenerWrapper(eventType, useCapture, window); + window->addEventListener(eventType, adoptRef(listenerWrapper), useCapture); } void WebFrameImpl::removeEventListener(const WebString& eventType, WebDOMEventListener* listener, bool useCapture) { - DOMWindow* window = m_frame->domWindow(); - - EventListenerWrapper* listenerWrapper = - listener->getEventListenerWrapper(eventType, useCapture, window); + DOMWindow* window = m_frame->document()->domWindow(); + EventListenerWrapper* listenerWrapper = listener->getEventListenerWrapper(eventType, useCapture, window); window->removeEventListener(eventType, listenerWrapper, useCapture); } bool WebFrameImpl::dispatchEvent(const WebDOMEvent& event) { ASSERT(!event.isNull()); - return m_frame->domWindow()->dispatchEvent(event); + return m_frame->document()->domWindow()->dispatchEvent(event); } void WebFrameImpl::dispatchMessageEventWithOriginCheck(const WebSecurityOrigin& intendedTargetOrigin, const WebDOMEvent& event) { ASSERT(!event.isNull()); // Pass an empty call stack, since we don't have the one from the other process. - m_frame->domWindow()->dispatchMessageEventWithOriginCheck(intendedTargetOrigin.get(), event, 0); + m_frame->document()->domWindow()->dispatchMessageEventWithOriginCheck(intendedTargetOrigin.get(), event, 0); } int WebFrameImpl::findMatchMarkersVersion() const { - // FIXME: Implement this as part of https://bugs.webkit.org/show_bug.cgi?id=93111. - return 0; + ASSERT(!parent()); + return m_findMatchMarkersVersion; +} + +void WebFrameImpl::clearFindMatchesCache() +{ + if (!m_findMatchesCache.isEmpty()) + viewImpl()->mainFrameImpl()->m_findMatchMarkersVersion++; + + m_findMatchesCache.clear(); + m_findMatchRectsAreValid = false; +} + +bool WebFrameImpl::isActiveMatchFrameValid() const +{ + WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl(); + WebFrameImpl* activeMatchFrame = mainFrameImpl->activeMatchFrame(); + return activeMatchFrame && activeMatchFrame->m_activeMatch + && activeMatchFrame->frame()->tree()->isDescendantOf(mainFrameImpl->frame()); +} + +void WebFrameImpl::updateFindMatchRects() +{ + IntSize currentContentsSize = contentsSize(); + if (m_contentsSizeForCurrentFindMatchRects != currentContentsSize) { + m_contentsSizeForCurrentFindMatchRects = currentContentsSize; + m_findMatchRectsAreValid = false; + } + + size_t deadMatches = 0; + for (Vector<FindMatch>::iterator it = m_findMatchesCache.begin(); it != m_findMatchesCache.end(); ++it) { + if (!it->m_range->boundaryPointsValid() || !it->m_range->startContainer()->inDocument()) + it->m_rect = FloatRect(); + else if (!m_findMatchRectsAreValid) + it->m_rect = findInPageRectFromRange(it->m_range.get()); + + if (it->m_rect.isEmpty()) + ++deadMatches; + } + + // Remove any invalid matches from the cache. + if (deadMatches) { + Vector<FindMatch> filteredMatches; + filteredMatches.reserveCapacity(m_findMatchesCache.size() - deadMatches); + + for (Vector<FindMatch>::const_iterator it = m_findMatchesCache.begin(); it != m_findMatchesCache.end(); ++it) + if (!it->m_rect.isEmpty()) + filteredMatches.append(*it); + + m_findMatchesCache.swap(filteredMatches); + } + + // Invalidate the rects in child frames. Will be updated later during traversal. + if (!m_findMatchRectsAreValid) + for (WebFrame* child = firstChild(); child; child = child->nextSibling()) + static_cast<WebFrameImpl*>(child)->m_findMatchRectsAreValid = false; + + m_findMatchRectsAreValid = true; } WebFloatRect WebFrameImpl::activeFindMatchRect() { - // FIXME: Implement this as part of https://bugs.webkit.org/show_bug.cgi?id=93111. - return WebFloatRect(); + ASSERT(!parent()); + + if (!isActiveMatchFrameValid()) + return WebFloatRect(); + + return WebFloatRect(findInPageRectFromRange(m_currentActiveMatchFrame->m_activeMatch.get())); } void WebFrameImpl::findMatchRects(WebVector<WebFloatRect>& outputRects) { - // FIXME: Implement this as part of https://bugs.webkit.org/show_bug.cgi?id=93111. + ASSERT(!parent()); + + Vector<WebFloatRect> matchRects; + for (WebFrameImpl* frame = this; frame; frame = static_cast<WebFrameImpl*>(frame->traverseNext(false))) + frame->appendFindMatchRects(matchRects); + + outputRects = matchRects; +} + +void WebFrameImpl::appendFindMatchRects(Vector<WebFloatRect>& frameRects) +{ + updateFindMatchRects(); + frameRects.reserveCapacity(frameRects.size() + m_findMatchesCache.size()); + for (Vector<FindMatch>::const_iterator it = m_findMatchesCache.begin(); it != m_findMatchesCache.end(); ++it) { + ASSERT(!it->m_rect.isEmpty()); + frameRects.append(it->m_rect); + } } int WebFrameImpl::selectNearestFindMatch(const WebFloatPoint& point, WebRect* selectionRect) { - // FIXME: Implement this as part of https://bugs.webkit.org/show_bug.cgi?id=93111. - return 0; + ASSERT(!parent()); + + WebFrameImpl* bestFrame = 0; + int indexInBestFrame = -1; + float distanceInBestFrame = FLT_MAX; + + for (WebFrameImpl* frame = this; frame; frame = static_cast<WebFrameImpl*>(frame->traverseNext(false))) { + float distanceInFrame; + int indexInFrame = frame->nearestFindMatch(point, distanceInFrame); + if (distanceInFrame < distanceInBestFrame) { + bestFrame = frame; + indexInBestFrame = indexInFrame; + distanceInBestFrame = distanceInFrame; + } + } + + if (indexInBestFrame != -1) + return bestFrame->selectFindMatch(static_cast<unsigned>(indexInBestFrame), selectionRect); + + return -1; +} + +int WebFrameImpl::nearestFindMatch(const FloatPoint& point, float& distanceSquared) +{ + updateFindMatchRects(); + + int nearest = -1; + distanceSquared = FLT_MAX; + for (size_t i = 0; i < m_findMatchesCache.size(); ++i) { + ASSERT(!m_findMatchesCache[i].m_rect.isEmpty()); + FloatSize offset = point - m_findMatchesCache[i].m_rect.center(); + float width = offset.width(); + float height = offset.height(); + float currentDistanceSquared = width * width + height * height; + if (currentDistanceSquared < distanceSquared) { + nearest = i; + distanceSquared = currentDistanceSquared; + } + } + return nearest; +} + +int WebFrameImpl::selectFindMatch(unsigned index, WebRect* selectionRect) +{ + ASSERT(index < m_findMatchesCache.size()); + + RefPtr<Range> range = m_findMatchesCache[index].m_range; + if (!range->boundaryPointsValid() || !range->startContainer()->inDocument()) + return -1; + + // Check if the match is already selected. + WebFrameImpl* activeMatchFrame = viewImpl()->mainFrameImpl()->m_currentActiveMatchFrame; + if (this != activeMatchFrame || !m_activeMatch || !areRangesEqual(m_activeMatch.get(), range.get())) { + if (isActiveMatchFrameValid()) + activeMatchFrame->setMarkerActive(activeMatchFrame->m_activeMatch.get(), false); + + m_activeMatchIndexInCurrentFrame = m_findMatchesCache[index].m_ordinal - 1; + + // Set this frame as the active frame (the one with the active highlight). + viewImpl()->mainFrameImpl()->m_currentActiveMatchFrame = this; + viewImpl()->setFocusedFrame(this); + + m_activeMatch = range.release(); + setMarkerActive(m_activeMatch.get(), true); + + // Clear any user selection, to make sure Find Next continues on from the match we just activated. + frame()->selection()->clear(); + + // Make sure no node is focused. See http://crbug.com/38700. + frame()->document()->setFocusedNode(0); + } + + IntRect activeMatchRect; + IntRect activeMatchBoundingBox = enclosingIntRect(RenderObject::absoluteBoundingBoxRectForRange(m_activeMatch.get())); + + if (!activeMatchBoundingBox.isEmpty()) { + if (m_activeMatch->firstNode() && m_activeMatch->firstNode()->renderer()) + m_activeMatch->firstNode()->renderer()->scrollRectToVisible(activeMatchBoundingBox, + ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded); + + // Zoom to the active match. + activeMatchRect = frameView()->contentsToWindow(activeMatchBoundingBox); + viewImpl()->zoomToFindInPageRect(activeMatchRect); + } + + if (selectionRect) + *selectionRect = activeMatchRect; + + return ordinalOfFirstMatchForFrame(this) + m_activeMatchIndexInCurrentFrame + 1; } void WebFrameImpl::deliverIntent(const WebIntent& intent, WebMessagePortChannelArray* ports, WebDeliveredIntentClient* intentClient) @@ -1998,11 +2186,11 @@ void WebFrameImpl::deliverIntent(const WebIntent& intent, WebMessagePortChannelA (*channels)[i] = MessagePortChannel::create(platformChannel); } } - OwnPtr<MessagePortArray> portArray = WebCore::MessagePort::entanglePorts(*(m_frame->domWindow()->scriptExecutionContext()), channels.release()); + OwnPtr<MessagePortArray> portArray = WebCore::MessagePort::entanglePorts(*(m_frame->document()), channels.release()); RefPtr<DeliveredIntent> deliveredIntent = DeliveredIntent::create(m_frame, client.release(), intent.action(), intent.type(), intentData, portArray.release(), webcoreIntent->extras()); - DOMWindowIntents::from(m_frame->domWindow())->deliver(deliveredIntent.release()); + DOMWindowIntents::from(m_frame->document()->domWindow())->deliver(deliveredIntent.release()); #endif } @@ -2097,6 +2285,8 @@ WebFrameImpl::WebFrameImpl(WebFrameClient* client) , m_framesScopingCount(-1) , m_scopingComplete(false) , m_nextInvalidateAfter(0) + , m_findMatchMarkersVersion(0) + , m_findMatchRectsAreValid(false) , m_animationController(this) , m_identifier(generateFrameIdentifier()) , m_inSameDocumentHistoryLoad(false) @@ -2175,6 +2365,15 @@ PassRefPtr<Frame> WebFrameImpl::createChildFrame( return childFrame.release(); } +void WebFrameImpl::didChangeContentsSize(const IntSize& size) +{ + // This is only possible on the main frame. + if (m_totalMatchCount > 0) { + ASSERT(!parent()); + ++m_findMatchMarkersVersion; + } +} + void WebFrameImpl::createFrameView() { ASSERT(m_frame); // If m_frame doesn't exist, we probably didn't init properly. |