diff options
Diffstat (limited to 'webkit/glue/webframe_impl.cc')
-rw-r--r-- | webkit/glue/webframe_impl.cc | 1598 |
1 files changed, 799 insertions, 799 deletions
diff --git a/webkit/glue/webframe_impl.cc b/webkit/glue/webframe_impl.cc index 4f784f2..2c4eb12 100644 --- a/webkit/glue/webframe_impl.cc +++ b/webkit/glue/webframe_impl.cc @@ -359,9 +359,11 @@ class ChromePrintContext : public WebCore::PrintContext { DISALLOW_COPY_AND_ASSIGN(ChromePrintContext); }; -// WebFrameImpl ---------------------------------------------------------------- +static WebDataSource* DataSourceForDocLoader(DocumentLoader* loader) { + return loader ? WebDataSourceImpl::FromLoader(loader) : NULL; +} -int WebFrameImpl::live_object_count_ = 0; +// WebFrame ------------------------------------------------------------------- // static WebFrame* WebFrame::frameForEnteredContext() { @@ -383,123 +385,8 @@ WebFrame* WebFrame::frameForCurrentContext() { return NULL; } -WebFrameImpl::WebFrameImpl() - : ALLOW_THIS_IN_INITIALIZER_LIST(frame_loader_client_(this)), - ALLOW_THIS_IN_INITIALIZER_LIST(scope_matches_factory_(this)), - plugin_delegate_(NULL), - active_match_frame_(NULL), - active_match_index_(-1), - locating_active_rect_(false), - resume_scoping_from_range_(NULL), - last_match_count_(-1), - total_matchcount_(-1), - frames_scoping_count_(-1), - scoping_complete_(false), - next_invalidate_after_(0) { - StatsCounter(kWebFrameActiveCount).Increment(); - live_object_count_++; -} - -WebFrameImpl::~WebFrameImpl() { - StatsCounter(kWebFrameActiveCount).Decrement(); - live_object_count_--; - - cancelPendingScopingEffort(); - ClearPasswordListeners(); -} - -// WebFrame ------------------------------------------------------------------- - -void WebFrameImpl::InitMainFrame(WebViewImpl* webview_impl) { - RefPtr<Frame> frame = - Frame::create(webview_impl->page(), 0, &frame_loader_client_); - frame_ = frame.get(); - - // Add reference on behalf of FrameLoader. See comments in - // WebFrameLoaderClient::frameLoaderDestroyed for more info. - AddRef(); - - // We must call init() after frame_ is assigned because it is referenced - // during init(). - frame_->init(); -} - -void WebFrameImpl::reload() { - frame_->loader()->saveDocumentAndScrollState(); - - stopLoading(); // Make sure existing activity stops. - frame_->loader()->reload(); -} - -void WebFrameImpl::loadRequest(const WebURLRequest& request) { - const ResourceRequest* resource_request = - webkit_glue::WebURLRequestToResourceRequest(&request); - DCHECK(resource_request); - - if (resource_request->url().protocolIs("javascript")) { - LoadJavaScriptURL(resource_request->url()); - return; - } - - stopLoading(); // Make sure existing activity stops. - frame_->loader()->load(*resource_request, false); -} - -void WebFrameImpl::loadHistoryItem(const WebHistoryItem& item) { - RefPtr<HistoryItem> history_item = - webkit_glue::WebHistoryItemToHistoryItem(item); - DCHECK(history_item.get()); - - stopLoading(); // Make sure existing activity stops. - - // If there is no current_item, which happens when we are navigating in - // session history after a crash, we need to manufacture one otherwise WebKit - // hoarks. This is probably the wrong thing to do, but it seems to work. - RefPtr<HistoryItem> current_item = frame_->loader()->currentHistoryItem(); - if (!current_item) { - current_item = HistoryItem::create(); - current_item->setLastVisitWasFailure(true); - frame_->loader()->setCurrentHistoryItem(current_item); - GetWebViewImpl()->SetCurrentHistoryItem(current_item.get()); - } - - frame_->loader()->goToItem(history_item.get(), - WebCore::FrameLoadTypeIndexedBackForward); -} - -void WebFrameImpl::loadData(const WebData& data, - const WebString& mime_type, - const WebString& text_encoding, - const WebURL& base_url, - const WebURL& unreachable_url, - bool replace) { - SubstituteData subst_data( - webkit_glue::WebDataToSharedBuffer(data), - webkit_glue::WebStringToString(mime_type), - webkit_glue::WebStringToString(text_encoding), - webkit_glue::WebURLToKURL(unreachable_url)); - DCHECK(subst_data.isValid()); - - stopLoading(); // Make sure existing activity stops. - frame_->loader()->load(ResourceRequest(webkit_glue::WebURLToKURL(base_url)), - subst_data, false); - if (replace) { - // Do this to force WebKit to treat the load as replacing the currently - // loaded page. - frame_->loader()->setReplacing(); - } -} - -void WebFrameImpl::loadHTMLString(const WebData& data, - const WebURL& base_url, - const WebURL& unreachable_url, - bool replace) { - loadData(data, - WebString::fromUTF8("text/html"), - WebString::fromUTF8("UTF-8"), - base_url, - unreachable_url, - replace); +WebString WebFrameImpl::name() const { + return webkit_glue::StringToWebString(frame_->tree()->name()); } WebURL WebFrameImpl::url() const { @@ -544,6 +431,18 @@ WebURL WebFrameImpl::openSearchDescriptionURL() const { return WebURL(); } +WebSize WebFrameImpl::scrollOffset() const { + WebCore::FrameView* view = frameview(); + if (view) + return webkit_glue::IntSizeToWebSize(view->scrollOffset()); + + return WebSize(); +} + +WebSize WebFrameImpl::contentsSize() const { + return webkit_glue::IntSizeToWebSize(frame()->view()->contentsSize()); +} + int WebFrameImpl::contentsPreferredWidth() const { if ((frame_->document() != NULL) && (frame_->document()->renderView() != NULL)) { @@ -553,63 +452,13 @@ int WebFrameImpl::contentsPreferredWidth() const { } } -WebHistoryItem WebFrameImpl::previousHistoryItem() const { - // We use the previous item here because documentState (filled-out forms) - // only get saved to history when it becomes the previous item. The caller - // is expected to query the history item after a navigation occurs, after - // the desired history item has become the previous entry. - return webkit_glue::HistoryItemToWebHistoryItem( - GetWebViewImpl()->GetPreviousHistoryItem()); -} - -WebHistoryItem WebFrameImpl::currentHistoryItem() const { - frame_->loader()->saveDocumentAndScrollState(); - - return webkit_glue::HistoryItemToWebHistoryItem( - frame_->page()->backForwardList()->currentItem()); -} - -static WebDataSource* DataSourceForDocLoader(DocumentLoader* loader) { - return loader ? WebDataSourceImpl::FromLoader(loader) : NULL; -} - -WebDataSource* WebFrameImpl::dataSource() const { - return DataSourceForDocLoader(frame_->loader()->documentLoader()); -} - -WebDataSourceImpl* WebFrameImpl::GetDataSourceImpl() const { - return static_cast<WebDataSourceImpl*>(dataSource()); -} - -WebDataSource* WebFrameImpl::provisionalDataSource() const { - FrameLoader* frame_loader = frame_->loader(); - - // We regard the policy document loader as still provisional. - DocumentLoader* doc_loader = frame_loader->provisionalDocumentLoader(); - if (!doc_loader) - doc_loader = frame_loader->policyDocumentLoader(); - - return DataSourceForDocLoader(doc_loader); -} - -WebDataSourceImpl* WebFrameImpl::GetProvisionalDataSourceImpl() const { - return static_cast<WebDataSourceImpl*>(provisionalDataSource()); -} - -void WebFrameImpl::stopLoading() { - if (!frame_) - return; - - // TODO(darin): Figure out what we should really do here. It seems like a - // bug that FrameLoader::stopLoading doesn't call stopAllLoaders. - frame_->loader()->stopAllLoaders(); - frame_->loader()->stopLoading(false); +bool WebFrameImpl::hasVisibleContent() const { + return frame()->view()->visibleWidth() > 0 && + frame()->view()->visibleHeight() > 0; } -bool WebFrameImpl::isLoading() const { - if (!frame_) - return false; - return frame_->loader()->isLoading(); +WebView* WebFrameImpl::view() const { + return GetWebViewImpl(); } WebFrame* WebFrameImpl::opener() const { @@ -637,20 +486,60 @@ WebFrame* WebFrameImpl::top() const { return NULL; } -void WebFrameImpl::enableViewSourceMode(bool enable) { - if (frame_) - frame_->setInViewSourceMode(enable); +WebFrame* WebFrameImpl::firstChild() const { + return FromFrame(frame()->tree()->firstChild()); } -bool WebFrameImpl::isViewSourceModeEnabled() const { - if (frame_) - return frame_->inViewSourceMode(); +WebFrame* WebFrameImpl::lastChild() const { + return FromFrame(frame()->tree()->lastChild()); +} - return false; +WebFrame* WebFrameImpl::nextSibling() const { + return FromFrame(frame()->tree()->nextSibling()); } -WebView* WebFrameImpl::view() const { - return GetWebViewImpl(); +WebFrame* WebFrameImpl::previousSibling() const { + return FromFrame(frame()->tree()->previousSibling()); +} + +WebFrame* WebFrameImpl::traverseNext(bool wrap) const { + return FromFrame(frame()->tree()->traverseNextWithWrap(wrap)); +} + +WebFrame* WebFrameImpl::traversePrevious(bool wrap) const { + return FromFrame(frame()->tree()->traversePreviousWithWrap(wrap)); +} + +WebFrame* WebFrameImpl::findChildByName(const WebKit::WebString& name) const { + return FromFrame(frame()->tree()->child( + webkit_glue::WebStringToString(name))); +} + +WebFrame* WebFrameImpl::findChildByExpression( + const WebKit::WebString& xpath) const { + if (xpath.isEmpty()) + return NULL; + + Document* document = frame_->document(); + + ExceptionCode ec = 0; + PassRefPtr<XPathResult> xpath_result = + document->evaluate(webkit_glue::WebStringToString(xpath), + document, + NULL, /* namespace */ + XPathResult::ORDERED_NODE_ITERATOR_TYPE, + NULL, /* XPathResult object */ + ec); + if (!xpath_result.get()) + return NULL; + + Node* node = xpath_result->iterateNext(ec); + + if (!node || !node->isFrameOwnerElement()) + return NULL; + HTMLFrameOwnerElement* frame_element = + static_cast<HTMLFrameOwnerElement*>(node); + return FromFrame(frame_element->contentFrame()); } void WebFrameImpl::forms(WebVector<WebForm>& results) const { @@ -681,6 +570,20 @@ WebString WebFrameImpl::securityOrigin() const { return WebString::fromUTF8("null"); } +void WebFrameImpl::grantUniversalAccess() { + DCHECK(frame_ && frame_->document()); + if (frame_ && frame_->document()) { + frame_->document()->securityOrigin()->grantUniversalAccess(); + } +} + +NPObject* WebFrameImpl::windowObject() const { + if (!frame_) + return NULL; + + return frame_->script()->windowScriptNPObject(); +} + void WebFrameImpl::bindToWindowObject(const WebString& name, NPObject* object) { DCHECK(frame_); @@ -707,8 +610,72 @@ void WebFrameImpl::bindToWindowObject(const WebString& name, #endif } +void WebFrameImpl::executeScript(const WebScriptSource& source) { + frame_->loader()->executeScript( + WebCore::ScriptSourceCode( + webkit_glue::WebStringToString(source.code), + webkit_glue::WebURLToKURL(source.url), + source.startLine)); +} + +void WebFrameImpl::executeScriptInNewContext( + const WebScriptSource* sources_in, unsigned num_sources, + int extension_group) { + Vector<WebCore::ScriptSourceCode> sources; + + for (unsigned i = 0; i < num_sources; ++i) { + sources.append(WebCore::ScriptSourceCode( + webkit_glue::WebStringToString(sources_in[i].code), + webkit_glue::WebURLToKURL(sources_in[i].url), + sources_in[i].startLine)); + } + + frame_->script()->evaluateInNewContext(sources, extension_group); +} + +void WebFrameImpl::executeScriptInNewWorld( + const WebScriptSource* sources_in, unsigned num_sources, + int extension_group) { + Vector<WebCore::ScriptSourceCode> sources; + + for (unsigned i = 0; i < num_sources; ++i) { + sources.append(WebCore::ScriptSourceCode( + webkit_glue::WebStringToString(sources_in[i].code), + webkit_glue::WebURLToKURL(sources_in[i].url), + sources_in[i].startLine)); + } + + frame_->script()->evaluateInNewWorld(sources, extension_group); +} + +void WebFrameImpl::addMessageToConsole(const WebConsoleMessage& message) { + ASSERT(frame()); + + WebCore::MessageLevel webcore_message_level; + switch (message.level) { + case WebConsoleMessage::LevelTip: + webcore_message_level = WebCore::TipMessageLevel; + break; + case WebConsoleMessage::LevelLog: + webcore_message_level = WebCore::LogMessageLevel; + break; + case WebConsoleMessage::LevelWarning: + webcore_message_level = WebCore::WarningMessageLevel; + break; + case WebConsoleMessage::LevelError: + webcore_message_level = WebCore::ErrorMessageLevel; + break; + default: + NOTREACHED(); + return; + } + + frame()->domWindow()->console()->addMessage( + WebCore::OtherMessageSource, WebCore::LogMessageType, + webcore_message_level, webkit_glue::WebStringToString(message.text), + 1, String()); +} -// Call JavaScript garbage collection. void WebFrameImpl::collectGarbage() { if (!frame_) return; @@ -720,96 +687,388 @@ void WebFrameImpl::collectGarbage() { #endif } -void WebFrameImpl::grantUniversalAccess() { - DCHECK(frame_ && frame_->document()); - if (frame_ && frame_->document()) { - frame_->document()->securityOrigin()->grantUniversalAccess(); +#if USE(V8) + // Returns the V8 context for this frame, or an empty handle if there is + // none. +v8::Local<v8::Context> WebFrameImpl::mainWorldScriptContext() const { + if (!frame_) + return v8::Local<v8::Context>(); + + return WebCore::V8Proxy::mainWorldContext(frame_); +} +#endif + +bool WebFrameImpl::insertStyleText(const WebString& css) { + Document* document = frame()->document(); + if (!document) + return false; + WebCore::Element* document_element = document->documentElement(); + if (!document_element) + return false; + + RefPtr<WebCore::Element> stylesheet = document->createElement( + WebCore::HTMLNames::styleTag, false); + ExceptionCode err = 0; + stylesheet->setTextContent(webkit_glue::WebStringToString(css), err); + DCHECK(!err) << "Failed to set style element content"; + WebCore::Node* first = document_element->firstChild(); + bool success = document_element->insertBefore(stylesheet, first, err); + DCHECK(success) << "Failed to insert stylesheet"; + return success; +} + +void WebFrameImpl::reload() { + frame_->loader()->saveDocumentAndScrollState(); + + stopLoading(); // Make sure existing activity stops. + frame_->loader()->reload(); +} + +void WebFrameImpl::loadRequest(const WebURLRequest& request) { + const ResourceRequest* resource_request = + webkit_glue::WebURLRequestToResourceRequest(&request); + DCHECK(resource_request); + + if (resource_request->url().protocolIs("javascript")) { + LoadJavaScriptURL(resource_request->url()); + return; } + + stopLoading(); // Make sure existing activity stops. + frame_->loader()->load(*resource_request, false); } -WebString WebFrameImpl::contentAsText(size_t max_chars) const { - if (!frame_) - return WebString(); +void WebFrameImpl::loadHistoryItem(const WebHistoryItem& item) { + RefPtr<HistoryItem> history_item = + webkit_glue::WebHistoryItemToHistoryItem(item); + DCHECK(history_item.get()); - std::wstring text; - FrameContentAsPlainText(max_chars, frame_, &text); - // TODO(darin): Too many string copies!!! - return WideToUTF16Hack(text); + stopLoading(); // Make sure existing activity stops. + + // If there is no current_item, which happens when we are navigating in + // session history after a crash, we need to manufacture one otherwise WebKit + // hoarks. This is probably the wrong thing to do, but it seems to work. + RefPtr<HistoryItem> current_item = frame_->loader()->currentHistoryItem(); + if (!current_item) { + current_item = HistoryItem::create(); + current_item->setLastVisitWasFailure(true); + frame_->loader()->setCurrentHistoryItem(current_item); + GetWebViewImpl()->SetCurrentHistoryItem(current_item.get()); + } + + frame_->loader()->goToItem(history_item.get(), + WebCore::FrameLoadTypeIndexedBackForward); } -NPObject* WebFrameImpl::windowObject() const { - if (!frame_) - return NULL; +void WebFrameImpl::loadData(const WebData& data, + const WebString& mime_type, + const WebString& text_encoding, + const WebURL& base_url, + const WebURL& unreachable_url, + bool replace) { + SubstituteData subst_data( + webkit_glue::WebDataToSharedBuffer(data), + webkit_glue::WebStringToString(mime_type), + webkit_glue::WebStringToString(text_encoding), + webkit_glue::WebURLToKURL(unreachable_url)); + DCHECK(subst_data.isValid()); - return frame_->script()->windowScriptNPObject(); + stopLoading(); // Make sure existing activity stops. + frame_->loader()->load(ResourceRequest(webkit_glue::WebURLToKURL(base_url)), + subst_data, false); + if (replace) { + // Do this to force WebKit to treat the load as replacing the currently + // loaded page. + frame_->loader()->setReplacing(); + } } -#if USE(V8) - // Returns the V8 context for this frame, or an empty handle if there is - // none. -v8::Local<v8::Context> WebFrameImpl::mainWorldScriptContext() const { +void WebFrameImpl::loadHTMLString(const WebData& data, + const WebURL& base_url, + const WebURL& unreachable_url, + bool replace) { + loadData(data, + WebString::fromUTF8("text/html"), + WebString::fromUTF8("UTF-8"), + base_url, + unreachable_url, + replace); +} + +bool WebFrameImpl::isLoading() const { if (!frame_) - return v8::Local<v8::Context>(); + return false; + return frame_->loader()->isLoading(); +} - return WebCore::V8Proxy::mainWorldContext(frame_); +void WebFrameImpl::stopLoading() { + if (!frame_) + return; + + // TODO(darin): Figure out what we should really do here. It seems like a + // bug that FrameLoader::stopLoading doesn't call stopAllLoaders. + frame_->loader()->stopAllLoaders(); + frame_->loader()->stopLoading(false); } -#endif -void WebFrameImpl::InvalidateArea(AreaToInvalidate area) { - ASSERT(frame() && frame()->view()); - FrameView* view = frame()->view(); +WebDataSource* WebFrameImpl::provisionalDataSource() const { + FrameLoader* frame_loader = frame_->loader(); - if ((area & INVALIDATE_ALL) == INVALIDATE_ALL) { - view->invalidateRect(view->frameRect()); - } else { - if ((area & INVALIDATE_CONTENT_AREA) == INVALIDATE_CONTENT_AREA) { - IntRect content_area( - view->x(), view->y(), view->visibleWidth(), view->visibleHeight()); - view->invalidateRect(content_area); - } + // We regard the policy document loader as still provisional. + DocumentLoader* doc_loader = frame_loader->provisionalDocumentLoader(); + if (!doc_loader) + doc_loader = frame_loader->policyDocumentLoader(); - if ((area & INVALIDATE_SCROLLBAR) == INVALIDATE_SCROLLBAR) { - // Invalidate the vertical scroll bar region for the view. - IntRect scroll_bar_vert( - view->x() + view->visibleWidth(), view->y(), - WebCore::ScrollbarTheme::nativeTheme()->scrollbarThickness(), - view->visibleHeight()); - view->invalidateRect(scroll_bar_vert); + return DataSourceForDocLoader(doc_loader); +} + +WebDataSource* WebFrameImpl::dataSource() const { + return DataSourceForDocLoader(frame_->loader()->documentLoader()); +} + +WebHistoryItem WebFrameImpl::previousHistoryItem() const { + // We use the previous item here because documentState (filled-out forms) + // only get saved to history when it becomes the previous item. The caller + // is expected to query the history item after a navigation occurs, after + // the desired history item has become the previous entry. + return webkit_glue::HistoryItemToWebHistoryItem( + GetWebViewImpl()->GetPreviousHistoryItem()); +} + +WebHistoryItem WebFrameImpl::currentHistoryItem() const { + frame_->loader()->saveDocumentAndScrollState(); + + return webkit_glue::HistoryItemToWebHistoryItem( + frame_->page()->backForwardList()->currentItem()); +} + +void WebFrameImpl::enableViewSourceMode(bool enable) { + if (frame_) + frame_->setInViewSourceMode(enable); +} + +bool WebFrameImpl::isViewSourceModeEnabled() const { + if (frame_) + return frame_->inViewSourceMode(); + + return false; +} + +void WebFrameImpl::dispatchWillSendRequest(WebURLRequest& request) { + ResourceResponse response; + frame_->loader()->client()->dispatchWillSendRequest(NULL, 0, + *webkit_glue::WebURLRequestToMutableResourceRequest(&request), + response); +} + +void WebFrameImpl::commitDocumentData(const char* data, size_t data_len) { + DocumentLoader* document_loader = frame_->loader()->documentLoader(); + + // Set the text encoding. This calls begin() for us. It is safe to call + // this multiple times (Mac does: page/mac/WebCoreFrameBridge.mm). + bool user_chosen = true; + String encoding = document_loader->overrideEncoding(); + if (encoding.isNull()) { + user_chosen = false; + encoding = document_loader->response().textEncodingName(); + } + frame_->loader()->setEncoding(encoding, user_chosen); + + // NOTE: mac only does this if there is a document + frame_->loader()->addData(data, data_len); +} + +unsigned WebFrameImpl::unloadListenerCount() const { + return frame()->domWindow()->pendingUnloadEventListeners(); +} + +void WebFrameImpl::replaceSelection(const WebString& wtext) { + String text = webkit_glue::WebStringToString(wtext); + RefPtr<DocumentFragment> fragment = createFragmentFromText( + frame()->selection()->toNormalizedRange().get(), text); + WebCore::applyCommand(WebCore::ReplaceSelectionCommand::create( + frame()->document(), fragment.get(), false, true, true)); +} + +void WebFrameImpl::insertText(const WebString& text) { + frame()->editor()->insertText(webkit_glue::WebStringToString(text), NULL); +} + +void WebFrameImpl::setMarkedText( + const WebString& text, unsigned location, unsigned length) { + WebCore::Editor* editor = frame()->editor(); + WebCore::String str = webkit_glue::WebStringToString(text); + + editor->confirmComposition(str); + + WTF::Vector<WebCore::CompositionUnderline> decorations; + editor->setComposition(str, decorations, location, length); +} + +void WebFrameImpl::unmarkText() { + frame()->editor()->confirmCompositionWithoutDisturbingSelection(); +} + +bool WebFrameImpl::hasMarkedText() const { + return frame()->editor()->hasComposition(); +} + +WebRange WebFrameImpl::markedRange() const { + return webkit_glue::RangeToWebRange(frame()->editor()->compositionRange()); +} + +bool WebFrameImpl::executeCommand(const WebString& name) { + ASSERT(frame()); + + if (name.length() <= 2) + return false; + + // Since we don't have NSControl, we will convert the format of command + // string and call the function on Editor directly. + string16 command = name; + + // Make sure the first letter is upper case. + command.replace(0, 1, 1, toupper(command.at(0))); + + // Remove the trailing ':' if existing. + if (command.at(command.length() - 1) == ':') + command.erase(command.length() - 1, 1); + + bool rv = true; + + // Specially handling commands that Editor::execCommand does not directly + // support. + if (EqualsASCII(command, "DeleteToEndOfParagraph")) { + WebCore::Editor* editor = frame()->editor(); + if (!editor->deleteWithDirection(WebCore::SelectionController::FORWARD, + WebCore::ParagraphBoundary, + true, + false)) { + editor->deleteWithDirection(WebCore::SelectionController::FORWARD, + WebCore::CharacterGranularity, + true, + false); } + } else if (EqualsASCII(command, "Indent")) { + frame()->editor()->indent(); + } else if (EqualsASCII(command, "Outdent")) { + frame()->editor()->outdent(); + } else if (EqualsASCII(command, "DeleteBackward")) { + rv = frame()->editor()->command(AtomicString("BackwardDelete")).execute(); + } else if (EqualsASCII(command, "DeleteForward")) { + rv = frame()->editor()->command(AtomicString("ForwardDelete")).execute(); + } else { + rv = frame()->editor()->command(AtomicString(command.c_str())).execute(); } + return rv; } -void WebFrameImpl::increaseMatchCount(int count, int request_id) { - // This function should only be called on the mainframe. - DCHECK(!parent()); +bool WebFrameImpl::executeCommand(const WebString& name, + const WebString& value) { + ASSERT(frame()); + return frame()->editor()->command(webkit_glue::WebStringToString(name)). + execute(webkit_glue::WebStringToString(value)); +} - total_matchcount_ += count; +bool WebFrameImpl::isCommandEnabled(const WebString& name) const { + ASSERT(frame()); + return frame()->editor()->command(webkit_glue::WebStringToString(name)). + isEnabled(); +} - // Update the UI with the latest findings. - WebViewDelegate* webview_delegate = GetWebViewImpl()->GetDelegate(); - DCHECK(webview_delegate); - if (webview_delegate) - webview_delegate->ReportFindInPageMatchCount(total_matchcount_, request_id, - frames_scoping_count_ == 0); +void WebFrameImpl::enableContinuousSpellChecking(bool enable) { + if (enable == isContinuousSpellCheckingEnabled()) + return; + frame()->editor()->toggleContinuousSpellChecking(); } -void WebFrameImpl::reportFindInPageSelection(const WebRect& selection_rect, - int active_match_ordinal, - int request_id) { - // Update the UI with the latest selection rect. - WebViewDelegate* webview_delegate = GetWebViewImpl()->GetDelegate(); - DCHECK(webview_delegate); - if (webview_delegate) { - webview_delegate->ReportFindInPageSelection( - request_id, - OrdinalOfFirstMatchForFrame(this) + active_match_ordinal, - selection_rect); +bool WebFrameImpl::isContinuousSpellCheckingEnabled() const { + return frame()->editor()->isContinuousSpellCheckingEnabled(); +} + +void WebFrameImpl::selectAll() { + frame()->selection()->selectAll(); + + WebViewDelegate* d = GetWebViewImpl()->GetDelegate(); + if (d) + d->UserMetricsRecordAction(L"SelectAll"); +} + +void WebFrameImpl::clearSelection() { + frame()->selection()->clear(); +} + +bool WebFrameImpl::hasSelection() const { + // frame()->selection()->isNone() never returns true. + return (frame()->selection()->start() != frame()->selection()->end()); +} + +WebRange WebFrameImpl::selectionRange() const { + return webkit_glue::RangeToWebRange( + frame()->selection()->toNormalizedRange()); +} + +WebString WebFrameImpl::selectionAsText() const { + RefPtr<Range> range = frame()->selection()->toNormalizedRange(); + if (!range.get()) + return WebString(); + + String text = range->text(); +#if defined(OS_WIN) + WebCore::replaceNewlinesWithWindowsStyleNewlines(text); +#endif + WebCore::replaceNBSPWithSpace(text); + return webkit_glue::StringToWebString(text); +} + +WebString WebFrameImpl::selectionAsMarkup() const { + RefPtr<Range> range = frame()->selection()->toNormalizedRange(); + if (!range.get()) + return WebString(); + + String markup = WebCore::createMarkup(range.get(), 0); + return webkit_glue::StringToWebString(markup); +} + +int WebFrameImpl::printBegin(const WebSize& page_size) { + DCHECK_EQ(frame()->document()->isFrameSet(), false); + + print_context_.reset(new ChromePrintContext(frame())); + WebCore::FloatRect rect(0, 0, + static_cast<float>(page_size.width), + static_cast<float>(page_size.height)); + print_context_->begin(rect.width()); + float page_height; + // We ignore the overlays calculation for now since they are generated in the + // browser. page_height is actually an output parameter. + print_context_->computePageRects(rect, 0, 0, 1.0, page_height); + return print_context_->pageCount(); +} + +float WebFrameImpl::printPage(int page, WebCanvas* canvas) { + // Ensure correct state. + if (!print_context_.get() || page < 0 || !frame() || !frame()->document()) { + NOTREACHED(); + return 0; } + +#if defined(OS_WIN) || defined(OS_LINUX) + PlatformContextSkia context(canvas); + GraphicsContext spool(&context); +#elif defined(OS_MACOSX) + CGContextRef context = canvas->beginPlatformPaint(); + GraphicsContext spool(context); + WebCore::LocalCurrentGraphicsContext localContext(&spool); +#endif + + return print_context_->spoolPage(spool, page); } -void WebFrameImpl::resetMatchCount() { - total_matchcount_ = 0; - frames_scoping_count_ = 0; +void WebFrameImpl::printEnd() { + DCHECK(print_context_.get()); + if (print_context_.get()) + print_context_->end(); + print_context_.reset(NULL); } bool WebFrameImpl::find(int request_id, @@ -913,105 +1172,18 @@ bool WebFrameImpl::find(int request_id, return found; } -int WebFrameImpl::OrdinalOfFirstMatchForFrame(WebFrameImpl* frame) const { - int ordinal = 0; - WebViewImpl* web_view = GetWebViewImpl(); - WebFrameImpl* const main_frame_impl = GetWebViewImpl()->main_frame(); - // Iterate from the main frame up to (but not including) |frame| and - // add up the number of matches found so far. - for (WebFrameImpl* it = main_frame_impl; - it != frame; - it = static_cast<WebFrameImpl*>( - web_view->GetNextFrameAfter(it, true))) { - if (it->last_match_count_ > 0) - ordinal += it->last_match_count_; - } - - return ordinal; -} - -bool WebFrameImpl::ShouldScopeMatches(const string16& search_text) { - // Don't scope if we can't find a frame or if the frame is not visible. - // The user may have closed the tab/application, so abort. - if (!frame() || !hasVisibleContent()) - return false; - - DCHECK(frame()->document() && frame()->view()); - - // If the frame completed the scoping operation and found 0 matches the last - // time it was searched, then we don't have to search it again if the user is - // just adding to the search string or sending the same search string again. - if (scoping_complete_ && - !last_search_string_.empty() && last_match_count_ == 0) { - // Check to see if the search string prefixes match. - string16 previous_search_prefix = - search_text.substr(0, last_search_string_.length()); - - if (previous_search_prefix == last_search_string_) { - return false; // Don't search this frame, it will be fruitless. - } - } - - return true; -} - -void WebFrameImpl::InvalidateIfNecessary() { - if (last_match_count_ > next_invalidate_after_) { - // TODO(finnur): (http://b/1088165) Optimize the drawing of the - // tickmarks and remove this. This calculation sets a milestone for when - // next to invalidate the scrollbar and the content area. We do this so that - // we don't spend too much time drawing the scrollbar over and over again. - // Basically, up until the first 500 matches there is no throttle. After the - // first 500 matches, we set set the milestone further and further out (750, - // 1125, 1688, 2K, 3K). - static const int start_slowing_down_after = 500; - static const int slowdown = 750; - int i = (last_match_count_ / start_slowing_down_after); - next_invalidate_after_ += i * slowdown; - - InvalidateArea(INVALIDATE_SCROLLBAR); - } -} - -void WebFrameImpl::AddMarker(WebCore::Range* range, bool active_match) { - // Use a TextIterator to visit the potentially multiple nodes the range - // covers. - TextIterator markedText(range); - for (; !markedText.atEnd(); markedText.advance()) { - RefPtr<Range> textPiece = markedText.range(); - int exception = 0; - - WebCore::DocumentMarker marker = { - WebCore::DocumentMarker::TextMatch, - textPiece->startOffset(exception), - textPiece->endOffset(exception), - "", - active_match }; - - if (marker.endOffset > marker.startOffset) { - // Find the node to add a marker to and add it. - Node* node = textPiece->startContainer(exception); - frame()->document()->addMarker(node, marker); - - // Rendered rects for markers in WebKit are not populated until each time - // the markers are painted. However, we need it to happen sooner, because - // the whole purpose of tickmarks on the scrollbar is to show where - // matches off-screen are (that haven't been painted yet). - Vector<WebCore::DocumentMarker> markers = - frame()->document()->markersForNode(node); - frame()->document()->setRenderedRectForMarker( - textPiece->startContainer(exception), - markers[markers.size() - 1], - range->boundingBox()); - } - } -} +void WebFrameImpl::stopFinding(bool clear_selection) { + if (!clear_selection) + SetFindEndstateFocusAndSelection(); + cancelPendingScopingEffort(); -void WebFrameImpl::SetMarkerActive(WebCore::Range* range, bool active) { - if (!range) - return; + // Remove all markers for matches found and turn off the highlighting. + if (!parent()) + frame()->document()->removeMarkers(WebCore::DocumentMarker::TextMatch); + frame()->setMarkedTextMatchesAreHighlighted(false); - frame()->document()->setMarkersActive(range, active); + // Let the frame know that we don't want tickmarks or highlighting anymore. + InvalidateArea(INVALIDATE_ALL); } void WebFrameImpl::scopeStringMatches(int request_id, @@ -1207,147 +1379,177 @@ void WebFrameImpl::cancelPendingScopingEffort() { active_match_index_ = -1; } -void WebFrameImpl::SetFindEndstateFocusAndSelection() { - WebFrameImpl* main_frame_impl = GetWebViewImpl()->main_frame(); +void WebFrameImpl::increaseMatchCount(int count, int request_id) { + // This function should only be called on the mainframe. + DCHECK(!parent()); - if (this == main_frame_impl->active_match_frame() && - active_match_.get()) { - // If the user has set the selection since the match was found, we - // don't focus anything. - VisibleSelection selection(frame()->selection()->selection()); - if (!selection.isNone()) - return; + total_matchcount_ += count; - // Try to find the first focusable node up the chain, which will, for - // example, focus links if we have found text within the link. - Node* node = active_match_->firstNode(); - while (node && !node->isFocusable() && node != frame()->document()) - node = node->parent(); + // Update the UI with the latest findings. + WebViewDelegate* webview_delegate = GetWebViewImpl()->GetDelegate(); + DCHECK(webview_delegate); + if (webview_delegate) + webview_delegate->ReportFindInPageMatchCount(total_matchcount_, request_id, + frames_scoping_count_ == 0); +} - if (node && node != frame()->document()) { - // Found a focusable parent node. Set focus to it. - frame()->document()->setFocusedNode(node); - } else { - // Iterate over all the nodes in the range until we find a focusable node. - // This, for example, sets focus to the first link if you search for - // text and text that is within one or more links. - node = active_match_->firstNode(); - while (node && node != active_match_->pastLastNode()) { - if (node->isFocusable()) { - frame()->document()->setFocusedNode(node); - break; - } - node = node->traverseNextNode(); - } - } +void WebFrameImpl::reportFindInPageSelection(const WebRect& selection_rect, + int active_match_ordinal, + int request_id) { + // Update the UI with the latest selection rect. + WebViewDelegate* webview_delegate = GetWebViewImpl()->GetDelegate(); + DCHECK(webview_delegate); + if (webview_delegate) { + webview_delegate->ReportFindInPageSelection( + request_id, + OrdinalOfFirstMatchForFrame(this) + active_match_ordinal, + selection_rect); } } -void WebFrameImpl::stopFinding(bool clear_selection) { - if (!clear_selection) - SetFindEndstateFocusAndSelection(); - cancelPendingScopingEffort(); - - // Remove all markers for matches found and turn off the highlighting. - if (!parent()) - frame()->document()->removeMarkers(WebCore::DocumentMarker::TextMatch); - frame()->setMarkedTextMatchesAreHighlighted(false); - - // Let the frame know that we don't want tickmarks or highlighting anymore. - InvalidateArea(INVALIDATE_ALL); +void WebFrameImpl::resetMatchCount() { + total_matchcount_ = 0; + frames_scoping_count_ = 0; } -void WebFrameImpl::selectAll() { - frame()->selection()->selectAll(); +WebString WebFrameImpl::contentAsText(size_t max_chars) const { + if (!frame_) + return WebString(); - WebViewDelegate* d = GetWebViewImpl()->GetDelegate(); - if (d) - d->UserMetricsRecordAction(L"SelectAll"); + std::wstring text; + FrameContentAsPlainText(max_chars, frame_, &text); + // TODO(darin): Too many string copies!!! + return WideToUTF16Hack(text); } -WebRange WebFrameImpl::selectionRange() const { - return webkit_glue::RangeToWebRange( - frame()->selection()->toNormalizedRange()); +WebString WebFrameImpl::contentAsMarkup() const { + return webkit_glue::StringToWebString(createFullMarkup(frame_->document())); } -WebString WebFrameImpl::selectionAsText() const { - RefPtr<Range> range = frame()->selection()->toNormalizedRange(); - if (!range.get()) - return WebString(); +// WebFrameImpl public --------------------------------------------------------- - String text = range->text(); -#if defined(OS_WIN) - WebCore::replaceNewlinesWithWindowsStyleNewlines(text); -#endif - WebCore::replaceNBSPWithSpace(text); - return webkit_glue::StringToWebString(text); +int WebFrameImpl::live_object_count_ = 0; + +WebFrameImpl::WebFrameImpl() + : ALLOW_THIS_IN_INITIALIZER_LIST(frame_loader_client_(this)), + ALLOW_THIS_IN_INITIALIZER_LIST(scope_matches_factory_(this)), + plugin_delegate_(NULL), + active_match_frame_(NULL), + active_match_index_(-1), + locating_active_rect_(false), + resume_scoping_from_range_(NULL), + last_match_count_(-1), + total_matchcount_(-1), + frames_scoping_count_(-1), + scoping_complete_(false), + next_invalidate_after_(0) { + StatsCounter(kWebFrameActiveCount).Increment(); + live_object_count_++; } -WebString WebFrameImpl::selectionAsMarkup() const { - RefPtr<Range> range = frame()->selection()->toNormalizedRange(); - if (!range.get()) - return WebString(); +WebFrameImpl::~WebFrameImpl() { + StatsCounter(kWebFrameActiveCount).Decrement(); + live_object_count_--; - String markup = WebCore::createMarkup(range.get(), 0); - return webkit_glue::StringToWebString(markup); + cancelPendingScopingEffort(); + ClearPasswordListeners(); } -void WebFrameImpl::replaceSelection(const WebString& wtext) { - String text = webkit_glue::WebStringToString(wtext); - RefPtr<DocumentFragment> fragment = createFragmentFromText( - frame()->selection()->toNormalizedRange().get(), text); - WebCore::applyCommand(WebCore::ReplaceSelectionCommand::create( - frame()->document(), fragment.get(), false, true, true)); -} +void WebFrameImpl::InitMainFrame(WebViewImpl* webview_impl) { + RefPtr<Frame> frame = + Frame::create(webview_impl->page(), 0, &frame_loader_client_); + frame_ = frame.get(); -void WebFrameImpl::insertText(const WebString& text) { - frame()->editor()->insertText(webkit_glue::WebStringToString(text), NULL); + // Add reference on behalf of FrameLoader. See comments in + // WebFrameLoaderClient::frameLoaderDestroyed for more info. + AddRef(); + + // We must call init() after frame_ is assigned because it is referenced + // during init(). + frame_->init(); } -void WebFrameImpl::setMarkedText( - const WebString& text, unsigned location, unsigned length) { - WebCore::Editor* editor = frame()->editor(); - WebCore::String str = webkit_glue::WebStringToString(text); +PassRefPtr<Frame> WebFrameImpl::CreateChildFrame( + const FrameLoadRequest& request, HTMLFrameOwnerElement* owner_element) { + // TODO(darin): share code with initWithName() - editor->confirmComposition(str); + scoped_refptr<WebFrameImpl> webframe = new WebFrameImpl(); - WTF::Vector<WebCore::CompositionUnderline> decorations; - editor->setComposition(str, decorations, location, length); -} + // Add an extra ref on behalf of the Frame/FrameLoader, which references the + // WebFrame via the FrameLoaderClient interface. See the comment at the top + // of this file for more info. + webframe->AddRef(); -void WebFrameImpl::unmarkText() { - frame()->editor()->confirmCompositionWithoutDisturbingSelection(); -} + RefPtr<Frame> child_frame = Frame::create( + frame_->page(), owner_element, &webframe->frame_loader_client_); + webframe->frame_ = child_frame.get(); -bool WebFrameImpl::hasMarkedText() const { - return frame()->editor()->hasComposition(); -} + child_frame->tree()->setName(request.frameName()); -WebRange WebFrameImpl::markedRange() const { - return webkit_glue::RangeToWebRange(frame()->editor()->compositionRange()); -} + frame_->tree()->appendChild(child_frame); -void WebFrameImpl::enableContinuousSpellChecking(bool enable) { - if (enable == isContinuousSpellCheckingEnabled()) - return; - frame()->editor()->toggleContinuousSpellChecking(); -} + // Frame::init() can trigger onload event in the parent frame, + // which may detach this frame and trigger a null-pointer access + // in FrameTree::removeChild. Move init() after appendChild call + // so that webframe->frame_ is in the tree before triggering + // onload event handler. + // Because the event handler may set webframe->frame_ to null, + // it is necessary to check the value after calling init() and + // return without loading URL. + // (b:791612) + child_frame->init(); // create an empty document + if (!child_frame->tree()->parent()) + return NULL; -bool WebFrameImpl::isContinuousSpellCheckingEnabled() const { - return frame()->editor()->isContinuousSpellCheckingEnabled(); -} + frame_->loader()->loadURLIntoChildFrame( + request.resourceRequest().url(), + request.resourceRequest().httpReferrer(), + child_frame.get()); -void WebFrameImpl::clearSelection() { - frame()->selection()->clear(); + // A synchronous navigation (about:blank) would have already processed + // onload, so it is possible for the frame to have already been destroyed by + // script in the page. + if (!child_frame->tree()->parent()) + return NULL; + + return child_frame.release(); } -bool WebFrameImpl::hasSelection() const { - // frame()->selection()->isNone() never returns true. - return (frame()->selection()->start() != frame()->selection()->end()); +void WebFrameImpl::Layout() { + // layout this frame + FrameView* view = frame_->view(); + if (view) + view->layout(); + + // recursively layout child frames + Frame* child = frame_->tree()->firstChild(); + for (; child; child = child->tree()->nextSibling()) + FromFrame(child)->Layout(); } -WebString WebFrameImpl::contentAsMarkup() const { - return webkit_glue::StringToWebString(createFullMarkup(frame_->document())); +void WebFrameImpl::Paint(skia::PlatformCanvas* canvas, const WebRect& rect) { + static StatsRate rendering("WebFramePaintTime"); + StatsScope<StatsRate> rendering_scope(rendering); + + if (!rect.isEmpty()) { + IntRect dirty_rect(webkit_glue::WebRectToIntRect(rect)); +#if defined(OS_MACOSX) + CGContextRef context = canvas->getTopPlatformDevice().GetBitmapContext(); + GraphicsContext gc(context); + WebCore::LocalCurrentGraphicsContext localContext(&gc); +#else + PlatformContextSkia context(canvas); + + // PlatformGraphicsContext is actually a pointer to PlatformContextSkia + GraphicsContext gc(reinterpret_cast<PlatformGraphicsContext*>(&context)); +#endif + if (frame_->document() && frameview()) { + frameview()->paint(&gc, dirty_rect); + frame_->page()->inspectorController()->drawNodeHighlight(gc); + } else { + gc.fillRect(dirty_rect, Color::white); + } + } } void WebFrameImpl::CreateFrameView() { @@ -1412,49 +1614,50 @@ WebViewImpl* WebFrameImpl::GetWebViewImpl() const { frame_->page()->chrome()->client())->webview(); } -// WebFrame -------------------------------------------------------------------- - -void WebFrameImpl::Layout() { - // layout this frame - FrameView* view = frame_->view(); - if (view) - view->layout(); +WebDataSourceImpl* WebFrameImpl::GetDataSourceImpl() const { + return static_cast<WebDataSourceImpl*>(dataSource()); +} - // recursively layout child frames - Frame* child = frame_->tree()->firstChild(); - for (; child; child = child->tree()->nextSibling()) - FromFrame(child)->Layout(); +WebDataSourceImpl* WebFrameImpl::GetProvisionalDataSourceImpl() const { + return static_cast<WebDataSourceImpl*>(provisionalDataSource()); } -void WebFrameImpl::Paint(skia::PlatformCanvas* canvas, const WebRect& rect) { - static StatsRate rendering("WebFramePaintTime"); - StatsScope<StatsRate> rendering_scope(rendering); +void WebFrameImpl::SetFindEndstateFocusAndSelection() { + WebFrameImpl* main_frame_impl = GetWebViewImpl()->main_frame(); - if (!rect.isEmpty()) { - IntRect dirty_rect(webkit_glue::WebRectToIntRect(rect)); -#if defined(OS_MACOSX) - CGContextRef context = canvas->getTopPlatformDevice().GetBitmapContext(); - GraphicsContext gc(context); - WebCore::LocalCurrentGraphicsContext localContext(&gc); -#else - PlatformContextSkia context(canvas); + if (this == main_frame_impl->active_match_frame() && + active_match_.get()) { + // If the user has set the selection since the match was found, we + // don't focus anything. + VisibleSelection selection(frame()->selection()->selection()); + if (!selection.isNone()) + return; - // PlatformGraphicsContext is actually a pointer to PlatformContextSkia - GraphicsContext gc(reinterpret_cast<PlatformGraphicsContext*>(&context)); -#endif - if (frame_->document() && frameview()) { - frameview()->paint(&gc, dirty_rect); - frame_->page()->inspectorController()->drawNodeHighlight(gc); + // Try to find the first focusable node up the chain, which will, for + // example, focus links if we have found text within the link. + Node* node = active_match_->firstNode(); + while (node && !node->isFocusable() && node != frame()->document()) + node = node->parent(); + + if (node && node != frame()->document()) { + // Found a focusable parent node. Set focus to it. + frame()->document()->setFocusedNode(node); } else { - gc.fillRect(dirty_rect, Color::white); + // Iterate over all the nodes in the range until we find a focusable node. + // This, for example, sets focus to the first link if you search for + // text and text that is within one or more links. + node = active_match_->firstNode(); + while (node && node != active_match_->pastLastNode()) { + if (node->isFocusable()) { + frame()->document()->setFocusedNode(node); + break; + } + node = node->traverseNextNode(); + } } } } -void WebFrameImpl::Closing() { - frame_ = NULL; -} - void WebFrameImpl::DidFail(const ResourceError& error, bool was_provisional) { WebViewImpl* web_view = GetWebViewImpl(); WebViewDelegate* delegate = web_view->delegate(); @@ -1469,357 +1672,154 @@ void WebFrameImpl::DidFail(const ResourceError& error, bool was_provisional) { } } -void WebFrameImpl::dispatchWillSendRequest(WebURLRequest& request) { - ResourceResponse response; - frame_->loader()->client()->dispatchWillSendRequest(NULL, 0, - *webkit_glue::WebURLRequestToMutableResourceRequest(&request), - response); +void WebFrameImpl::SetAllowsScrolling(bool flag) { + frame_->view()->setCanHaveScrollbars(flag); } -void WebFrameImpl::commitDocumentData(const char* data, size_t data_len) { - DocumentLoader* document_loader = frame_->loader()->documentLoader(); - - // Set the text encoding. This calls begin() for us. It is safe to call - // this multiple times (Mac does: page/mac/WebCoreFrameBridge.mm). - bool user_chosen = true; - String encoding = document_loader->overrideEncoding(); - if (encoding.isNull()) { - user_chosen = false; - encoding = document_loader->response().textEncodingName(); - } - frame_->loader()->setEncoding(encoding, user_chosen); - - // NOTE: mac only does this if there is a document - frame_->loader()->addData(data, data_len); +void WebFrameImpl::RegisterPasswordListener( + PassRefPtr<WebCore::HTMLInputElement> input_element, + webkit_glue::PasswordAutocompleteListener* listener) { + RefPtr<WebCore::HTMLInputElement> element = input_element; + DCHECK(password_listeners_.find(element) == password_listeners_.end()); + password_listeners_.set(element, listener); } -void WebFrameImpl::executeScript(const WebScriptSource& source) { - frame_->loader()->executeScript( - WebCore::ScriptSourceCode( - webkit_glue::WebStringToString(source.code), - webkit_glue::WebURLToKURL(source.url), - source.startLine)); +webkit_glue::PasswordAutocompleteListener* WebFrameImpl::GetPasswordListener( + WebCore::HTMLInputElement* input_element) { + return password_listeners_.get(input_element); } -bool WebFrameImpl::insertStyleText(const WebString& css) { - Document* document = frame()->document(); - if (!document) - return false; - WebCore::Element* document_element = document->documentElement(); - if (!document_element) - return false; +// WebFrameImpl protected ------------------------------------------------------ - RefPtr<WebCore::Element> stylesheet = document->createElement( - WebCore::HTMLNames::styleTag, false); - ExceptionCode err = 0; - stylesheet->setTextContent(webkit_glue::WebStringToString(css), err); - DCHECK(!err) << "Failed to set style element content"; - WebCore::Node* first = document_element->firstChild(); - bool success = document_element->insertBefore(stylesheet, first, err); - DCHECK(success) << "Failed to insert stylesheet"; - return success; +void WebFrameImpl::Closing() { + frame_ = NULL; } -void WebFrameImpl::executeScriptInNewContext( - const WebScriptSource* sources_in, unsigned num_sources, - int extension_group) { - Vector<WebCore::ScriptSourceCode> sources; +// WebFrameImpl private -------------------------------------------------------- - for (unsigned i = 0; i < num_sources; ++i) { - sources.append(WebCore::ScriptSourceCode( - webkit_glue::WebStringToString(sources_in[i].code), - webkit_glue::WebURLToKURL(sources_in[i].url), - sources_in[i].startLine)); - } - - frame_->script()->evaluateInNewContext(sources, extension_group); -} +void WebFrameImpl::InvalidateArea(AreaToInvalidate area) { + ASSERT(frame() && frame()->view()); + FrameView* view = frame()->view(); -void WebFrameImpl::executeScriptInNewWorld( - const WebScriptSource* sources_in, unsigned num_sources, - int extension_group) { - Vector<WebCore::ScriptSourceCode> sources; + if ((area & INVALIDATE_ALL) == INVALIDATE_ALL) { + view->invalidateRect(view->frameRect()); + } else { + if ((area & INVALIDATE_CONTENT_AREA) == INVALIDATE_CONTENT_AREA) { + IntRect content_area( + view->x(), view->y(), view->visibleWidth(), view->visibleHeight()); + view->invalidateRect(content_area); + } - for (unsigned i = 0; i < num_sources; ++i) { - sources.append(WebCore::ScriptSourceCode( - webkit_glue::WebStringToString(sources_in[i].code), - webkit_glue::WebURLToKURL(sources_in[i].url), - sources_in[i].startLine)); + if ((area & INVALIDATE_SCROLLBAR) == INVALIDATE_SCROLLBAR) { + // Invalidate the vertical scroll bar region for the view. + IntRect scroll_bar_vert( + view->x() + view->visibleWidth(), view->y(), + WebCore::ScrollbarTheme::nativeTheme()->scrollbarThickness(), + view->visibleHeight()); + view->invalidateRect(scroll_bar_vert); + } } - - frame_->script()->evaluateInNewWorld(sources, extension_group); -} - -WebString WebFrameImpl::name() const { - return webkit_glue::StringToWebString(frame_->tree()->name()); -} - -bool WebFrameImpl::hasVisibleContent() const { - return frame()->view()->visibleWidth() > 0 && - frame()->view()->visibleHeight() > 0; } -PassRefPtr<Frame> WebFrameImpl::CreateChildFrame( - const FrameLoadRequest& request, HTMLFrameOwnerElement* owner_element) { - // TODO(darin): share code with initWithName() - - scoped_refptr<WebFrameImpl> webframe = new WebFrameImpl(); - - // Add an extra ref on behalf of the Frame/FrameLoader, which references the - // WebFrame via the FrameLoaderClient interface. See the comment at the top - // of this file for more info. - webframe->AddRef(); - - RefPtr<Frame> child_frame = Frame::create( - frame_->page(), owner_element, &webframe->frame_loader_client_); - webframe->frame_ = child_frame.get(); - - child_frame->tree()->setName(request.frameName()); - - frame_->tree()->appendChild(child_frame); - - // Frame::init() can trigger onload event in the parent frame, - // which may detach this frame and trigger a null-pointer access - // in FrameTree::removeChild. Move init() after appendChild call - // so that webframe->frame_ is in the tree before triggering - // onload event handler. - // Because the event handler may set webframe->frame_ to null, - // it is necessary to check the value after calling init() and - // return without loading URL. - // (b:791612) - child_frame->init(); // create an empty document - if (!child_frame->tree()->parent()) - return NULL; - - frame_->loader()->loadURLIntoChildFrame( - request.resourceRequest().url(), - request.resourceRequest().httpReferrer(), - child_frame.get()); - - // A synchronous navigation (about:blank) would have already processed - // onload, so it is possible for the frame to have already been destroyed by - // script in the page. - if (!child_frame->tree()->parent()) - return NULL; - - return child_frame.release(); -} - -bool WebFrameImpl::executeCommand(const WebString& name) { - ASSERT(frame()); - - if (name.length() <= 2) - return false; - - // Since we don't have NSControl, we will convert the format of command - // string and call the function on Editor directly. - string16 command = name; - - // Make sure the first letter is upper case. - command.replace(0, 1, 1, toupper(command.at(0))); +void WebFrameImpl::AddMarker(WebCore::Range* range, bool active_match) { + // Use a TextIterator to visit the potentially multiple nodes the range + // covers. + TextIterator markedText(range); + for (; !markedText.atEnd(); markedText.advance()) { + RefPtr<Range> textPiece = markedText.range(); + int exception = 0; - // Remove the trailing ':' if existing. - if (command.at(command.length() - 1) == ':') - command.erase(command.length() - 1, 1); + WebCore::DocumentMarker marker = { + WebCore::DocumentMarker::TextMatch, + textPiece->startOffset(exception), + textPiece->endOffset(exception), + "", + active_match }; - bool rv = true; + if (marker.endOffset > marker.startOffset) { + // Find the node to add a marker to and add it. + Node* node = textPiece->startContainer(exception); + frame()->document()->addMarker(node, marker); - // Specially handling commands that Editor::execCommand does not directly - // support. - if (EqualsASCII(command, "DeleteToEndOfParagraph")) { - WebCore::Editor* editor = frame()->editor(); - if (!editor->deleteWithDirection(WebCore::SelectionController::FORWARD, - WebCore::ParagraphBoundary, - true, - false)) { - editor->deleteWithDirection(WebCore::SelectionController::FORWARD, - WebCore::CharacterGranularity, - true, - false); + // Rendered rects for markers in WebKit are not populated until each time + // the markers are painted. However, we need it to happen sooner, because + // the whole purpose of tickmarks on the scrollbar is to show where + // matches off-screen are (that haven't been painted yet). + Vector<WebCore::DocumentMarker> markers = + frame()->document()->markersForNode(node); + frame()->document()->setRenderedRectForMarker( + textPiece->startContainer(exception), + markers[markers.size() - 1], + range->boundingBox()); } - } else if (EqualsASCII(command, "Indent")) { - frame()->editor()->indent(); - } else if (EqualsASCII(command, "Outdent")) { - frame()->editor()->outdent(); - } else if (EqualsASCII(command, "DeleteBackward")) { - rv = frame()->editor()->command(AtomicString("BackwardDelete")).execute(); - } else if (EqualsASCII(command, "DeleteForward")) { - rv = frame()->editor()->command(AtomicString("ForwardDelete")).execute(); - } else { - rv = frame()->editor()->command(AtomicString(command.c_str())).execute(); } - return rv; } -bool WebFrameImpl::executeCommand(const WebString& name, - const WebString& value) { - ASSERT(frame()); - return frame()->editor()->command(webkit_glue::WebStringToString(name)). - execute(webkit_glue::WebStringToString(value)); -} +void WebFrameImpl::SetMarkerActive(WebCore::Range* range, bool active) { + if (!range) + return; -bool WebFrameImpl::isCommandEnabled(const WebString& name) const { - ASSERT(frame()); - return frame()->editor()->command(webkit_glue::WebStringToString(name)). - isEnabled(); + frame()->document()->setMarkersActive(range, active); } -void WebFrameImpl::addMessageToConsole(const WebConsoleMessage& message) { - ASSERT(frame()); - - WebCore::MessageLevel webcore_message_level; - switch (message.level) { - case WebConsoleMessage::LevelTip: - webcore_message_level = WebCore::TipMessageLevel; - break; - case WebConsoleMessage::LevelLog: - webcore_message_level = WebCore::LogMessageLevel; - break; - case WebConsoleMessage::LevelWarning: - webcore_message_level = WebCore::WarningMessageLevel; - break; - case WebConsoleMessage::LevelError: - webcore_message_level = WebCore::ErrorMessageLevel; - break; - default: - NOTREACHED(); - return; +int WebFrameImpl::OrdinalOfFirstMatchForFrame(WebFrameImpl* frame) const { + int ordinal = 0; + WebViewImpl* web_view = GetWebViewImpl(); + WebFrameImpl* const main_frame_impl = GetWebViewImpl()->main_frame(); + // Iterate from the main frame up to (but not including) |frame| and + // add up the number of matches found so far. + for (WebFrameImpl* it = main_frame_impl; + it != frame; + it = static_cast<WebFrameImpl*>( + web_view->GetNextFrameAfter(it, true))) { + if (it->last_match_count_ > 0) + ordinal += it->last_match_count_; } - frame()->domWindow()->console()->addMessage( - WebCore::OtherMessageSource, WebCore::LogMessageType, - webcore_message_level, webkit_glue::WebStringToString(message.text), - 1, String()); -} - -WebSize WebFrameImpl::scrollOffset() const { - WebCore::FrameView* view = frameview(); - if (view) - return webkit_glue::IntSizeToWebSize(view->scrollOffset()); - - return WebSize(); -} - -WebSize WebFrameImpl::contentsSize() const { - return webkit_glue::IntSizeToWebSize(frame()->view()->contentsSize()); -} - -WebFrame* WebFrameImpl::firstChild() const { - return FromFrame(frame()->tree()->firstChild()); -} - -WebFrame* WebFrameImpl::lastChild() const { - return FromFrame(frame()->tree()->lastChild()); -} - -WebFrame* WebFrameImpl::nextSibling() const { - return FromFrame(frame()->tree()->nextSibling()); -} - -WebFrame* WebFrameImpl::previousSibling() const { - return FromFrame(frame()->tree()->previousSibling()); -} - -WebFrame* WebFrameImpl::traverseNext(bool wrap) const { - return FromFrame(frame()->tree()->traverseNextWithWrap(wrap)); -} - -WebFrame* WebFrameImpl::traversePrevious(bool wrap) const { - return FromFrame(frame()->tree()->traversePreviousWithWrap(wrap)); -} - -WebFrame* WebFrameImpl::findChildByName(const WebKit::WebString& name) const { - return FromFrame(frame()->tree()->child( - webkit_glue::WebStringToString(name))); -} - -WebFrame* WebFrameImpl::findChildByExpression( - const WebKit::WebString& xpath) const { - if (xpath.isEmpty()) - return NULL; - - Document* document = frame_->document(); - - ExceptionCode ec = 0; - PassRefPtr<XPathResult> xpath_result = - document->evaluate(webkit_glue::WebStringToString(xpath), - document, - NULL, /* namespace */ - XPathResult::ORDERED_NODE_ITERATOR_TYPE, - NULL, /* XPathResult object */ - ec); - if (!xpath_result.get()) - return NULL; - - Node* node = xpath_result->iterateNext(ec); - - if (!node || !node->isFrameOwnerElement()) - return NULL; - HTMLFrameOwnerElement* frame_element = - static_cast<HTMLFrameOwnerElement*>(node); - return FromFrame(frame_element->contentFrame()); + return ordinal; } -void WebFrameImpl::SetAllowsScrolling(bool flag) { - frame_->view()->setCanHaveScrollbars(flag); -} +bool WebFrameImpl::ShouldScopeMatches(const string16& search_text) { + // Don't scope if we can't find a frame or if the frame is not visible. + // The user may have closed the tab/application, so abort. + if (!frame() || !hasVisibleContent()) + return false; -int WebFrameImpl::printBegin(const WebSize& page_size) { - DCHECK_EQ(frame()->document()->isFrameSet(), false); + DCHECK(frame()->document() && frame()->view()); - print_context_.reset(new ChromePrintContext(frame())); - WebCore::FloatRect rect(0, 0, - static_cast<float>(page_size.width), - static_cast<float>(page_size.height)); - print_context_->begin(rect.width()); - float page_height; - // We ignore the overlays calculation for now since they are generated in the - // browser. page_height is actually an output parameter. - print_context_->computePageRects(rect, 0, 0, 1.0, page_height); - return print_context_->pageCount(); -} + // If the frame completed the scoping operation and found 0 matches the last + // time it was searched, then we don't have to search it again if the user is + // just adding to the search string or sending the same search string again. + if (scoping_complete_ && + !last_search_string_.empty() && last_match_count_ == 0) { + // Check to see if the search string prefixes match. + string16 previous_search_prefix = + search_text.substr(0, last_search_string_.length()); -float WebFrameImpl::printPage(int page, WebCanvas* canvas) { - // Ensure correct state. - if (!print_context_.get() || page < 0 || !frame() || !frame()->document()) { - NOTREACHED(); - return 0; + if (previous_search_prefix == last_search_string_) { + return false; // Don't search this frame, it will be fruitless. + } } -#if defined(OS_WIN) || defined(OS_LINUX) - PlatformContextSkia context(canvas); - GraphicsContext spool(&context); -#elif defined(OS_MACOSX) - CGContextRef context = canvas->beginPlatformPaint(); - GraphicsContext spool(context); - WebCore::LocalCurrentGraphicsContext localContext(&spool); -#endif - - return print_context_->spoolPage(spool, page); -} - -void WebFrameImpl::printEnd() { - DCHECK(print_context_.get()); - if (print_context_.get()) - print_context_->end(); - print_context_.reset(NULL); -} - -unsigned WebFrameImpl::unloadListenerCount() const { - return frame()->domWindow()->pendingUnloadEventListeners(); + return true; } -void WebFrameImpl::RegisterPasswordListener( - PassRefPtr<WebCore::HTMLInputElement> input_element, - webkit_glue::PasswordAutocompleteListener* listener) { - RefPtr<WebCore::HTMLInputElement> element = input_element; - DCHECK(password_listeners_.find(element) == password_listeners_.end()); - password_listeners_.set(element, listener); -} +void WebFrameImpl::InvalidateIfNecessary() { + if (last_match_count_ > next_invalidate_after_) { + // TODO(finnur): (http://b/1088165) Optimize the drawing of the + // tickmarks and remove this. This calculation sets a milestone for when + // next to invalidate the scrollbar and the content area. We do this so that + // we don't spend too much time drawing the scrollbar over and over again. + // Basically, up until the first 500 matches there is no throttle. After the + // first 500 matches, we set set the milestone further and further out (750, + // 1125, 1688, 2K, 3K). + static const int start_slowing_down_after = 500; + static const int slowdown = 750; + int i = (last_match_count_ / start_slowing_down_after); + next_invalidate_after_ += i * slowdown; -webkit_glue::PasswordAutocompleteListener* WebFrameImpl::GetPasswordListener( - WebCore::HTMLInputElement* input_element) { - return password_listeners_.get(input_element); + InvalidateArea(INVALIDATE_SCROLLBAR); + } } void WebFrameImpl::ClearPasswordListeners() { |