Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(152)

Side by Side Diff: webkit/glue/webframe_impl.cc

Issue 341030: Moves webview_impl.cc, webframe_impl.cc and webframeloaderclient_impl.cc into... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/glue/webframe_impl.h ('k') | webkit/glue/webframeloaderclient_impl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
3 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 // How ownership works
28 // -------------------
29 //
30 // Big oh represents a refcounted relationship: owner O--- ownee
31 //
32 // WebView (for the toplevel frame only)
33 // O
34 // |
35 // Page O------- Frame (m_mainFrame) O-------O FrameView
36 // ||
37 // ||
38 // FrameLoader O-------- WebFrame (via FrameLoaderClient)
39 //
40 // FrameLoader and Frame are formerly one object that was split apart because
41 // it got too big. They basically have the same lifetime, hence the double line.
42 //
43 // WebFrame is refcounted and has one ref on behalf of the FrameLoader/Frame.
44 // This is not a normal reference counted pointer because that would require
45 // changing WebKit code that we don't control. Instead, it is created with this
46 // ref initially and it is removed when the FrameLoader is getting destroyed.
47 //
48 // WebFrames are created in two places, first in WebViewImpl when the root
49 // frame is created, and second in WebFrame::CreateChildFrame when sub-frames
50 // are created. WebKit will hook up this object to the FrameLoader/Frame
51 // and the refcount will be correct.
52 //
53 // How frames are destroyed
54 // ------------------------
55 //
56 // The main frame is never destroyed and is re-used. The FrameLoader is re-used
57 // and a reference to the main frame is kept by the Page.
58 //
59 // When frame content is replaced, all subframes are destroyed. This happens
60 // in FrameLoader::detachFromParent for each subframe.
61 //
62 // Frame going away causes the FrameLoader to get deleted. In FrameLoader's
63 // destructor, it notifies its client with frameLoaderDestroyed. This calls
64 // WebFrame::Closing and then derefs the WebFrame and will cause it to be
65 // deleted (unless an external someone is also holding a reference).
66
67 #include "config.h"
68
69 #include <algorithm>
70 #include <string>
71
72 #include "HTMLFormElement.h" // need this before Document.h
73 #include "Chrome.h"
74 #include "ChromiumBridge.h"
75 #include "ClipboardUtilitiesChromium.h"
76 #include "Console.h"
77 #include "Document.h"
78 #include "DocumentFragment.h" // Only needed for ReplaceSelectionCommand.h :(
79 #include "DocumentLoader.h"
80 #include "DocumentMarker.h"
81 #include "DOMWindow.h"
82 #include "Editor.h"
83 #include "EventHandler.h"
84 #include "FormState.h"
85 #include "FrameChromium.h"
86 #include "FrameLoader.h"
87 #include "FrameLoadRequest.h"
88 #include "FrameTree.h"
89 #include "FrameView.h"
90 #include "GraphicsContext.h"
91 #include "HTMLCollection.h"
92 #include "HTMLHeadElement.h"
93 #include "HTMLInputElement.h"
94 #include "HTMLFrameOwnerElement.h"
95 #include "HTMLLinkElement.h"
96 #include "HTMLNames.h"
97 #include "HistoryItem.h"
98 #include "InspectorController.h"
99 #if PLATFORM(DARWIN)
100 #include "LocalCurrentGraphicsContext.h"
101 #endif
102 #include "markup.h"
103 #include "Page.h"
104 #include "PlatformContextSkia.h"
105 #include "PrintContext.h"
106 #include "RenderFrame.h"
107 #if PLATFORM(WIN_OS)
108 #include "RenderThemeChromiumWin.h"
109 #endif
110 #include "RenderView.h"
111 #include "RenderWidget.h"
112 #include "ReplaceSelectionCommand.h"
113 #include "ResourceHandle.h"
114 #include "ResourceRequest.h"
115 #include "ScriptController.h"
116 #include "ScriptSourceCode.h"
117 #include "ScriptValue.h"
118 #include "ScrollbarTheme.h"
119 #include "ScrollTypes.h"
120 #include "SelectionController.h"
121 #include "Settings.h"
122 #include "SkiaUtils.h"
123 #include "SubstituteData.h"
124 #include "TextIterator.h"
125 #include "TextAffinity.h"
126 #include "XPathResult.h"
127 #include <wtf/CurrentTime.h>
128 #undef LOG
129
130 #include "webkit/api/public/WebConsoleMessage.h"
131 #include "webkit/api/public/WebFindOptions.h"
132 #include "webkit/api/public/WebForm.h"
133 #include "webkit/api/public/WebFrameClient.h"
134 #include "webkit/api/public/WebHistoryItem.h"
135 #include "webkit/api/public/WebRange.h"
136 #include "webkit/api/public/WebRect.h"
137 #include "webkit/api/public/WebScriptSource.h"
138 #include "webkit/api/public/WebSecurityOrigin.h"
139 #include "webkit/api/public/WebSize.h"
140 #include "webkit/api/public/WebURLError.h"
141 #include "webkit/api/public/WebVector.h"
142 #include "webkit/api/src/DOMUtilitiesPrivate.h"
143 #include "webkit/api/src/PasswordAutocompleteListener.h"
144 #include "webkit/api/src/WebDataSourceImpl.h"
145 #include "webkit/glue/glue_util.h"
146 #include "webkit/glue/webframe_impl.h"
147 #include "webkit/glue/webview_impl.h"
148
149 #if PLATFORM(LINUX)
150 #include <gdk/gdk.h>
151 #endif
152
153 using WebCore::AtomicString;
154 using WebCore::ChromiumBridge;
155 using WebCore::Color;
156 using WebCore::Document;
157 using WebCore::DocumentFragment;
158 using WebCore::DocumentLoader;
159 using WebCore::ExceptionCode;
160 using WebCore::GraphicsContext;
161 using WebCore::HTMLFrameOwnerElement;
162 using WebCore::HTMLInputElement;
163 using WebCore::Frame;
164 using WebCore::FrameLoader;
165 using WebCore::FrameLoadRequest;
166 using WebCore::FrameLoadType;
167 using WebCore::FrameTree;
168 using WebCore::FrameView;
169 using WebCore::HistoryItem;
170 using WebCore::HTMLFormElement;
171 using WebCore::IntRect;
172 using WebCore::KURL;
173 using WebCore::Node;
174 using WebCore::Range;
175 using WebCore::ReloadIgnoringCacheData;
176 using WebCore::RenderObject;
177 using WebCore::ResourceError;
178 using WebCore::ResourceHandle;
179 using WebCore::ResourceRequest;
180 using WebCore::ResourceResponse;
181 using WebCore::VisibleSelection;
182 using WebCore::ScriptValue;
183 using WebCore::SecurityOrigin;
184 using WebCore::SharedBuffer;
185 using WebCore::String;
186 using WebCore::SubstituteData;
187 using WebCore::TextIterator;
188 using WebCore::Timer;
189 using WebCore::VisiblePosition;
190 using WebCore::XPathResult;
191
192 using WebKit::PasswordAutocompleteListener;
193 using WebKit::WebCanvas;
194 using WebKit::WebConsoleMessage;
195 using WebKit::WebData;
196 using WebKit::WebDataSource;
197 using WebKit::WebDataSourceImpl;
198 using WebKit::WebFindOptions;
199 using WebKit::WebFrame;
200 using WebKit::WebFrameClient;
201 using WebKit::WebHistoryItem;
202 using WebKit::WebForm;
203 using WebKit::WebRange;
204 using WebKit::WebRect;
205 using WebKit::WebScriptSource;
206 using WebKit::WebSecurityOrigin;
207 using WebKit::WebSize;
208 using WebKit::WebString;
209 using WebKit::WebURL;
210 using WebKit::WebURLError;
211 using WebKit::WebURLRequest;
212 using WebKit::WebURLResponse;
213 using WebKit::WebVector;
214 using WebKit::WebView;
215
216 // Key for a StatsCounter tracking how many WebFrames are active.
217 static const char* const kWebFrameActiveCount = "WebFrameActiveCount";
218
219 static const char* const kOSDType = "application/opensearchdescription+xml";
220 static const char* const kOSDRel = "search";
221
222 // The separator between frames when the frames are converted to plain text.
223 static const wchar_t kFrameSeparator[] = L"\n\n";
224 static const size_t kFrameSeparatorLen = arraysize(kFrameSeparator) - 1;
225
226 // Backend for contentAsPlainText, this is a recursive function that gets
227 // the text for the current frame and all of its subframes. It will append
228 // the text of each frame in turn to the |output| up to |max_chars| length.
229 //
230 // The |frame| must be non-NULL.
231 static void FrameContentAsPlainText(size_t max_chars, Frame* frame,
232 Vector<UChar>* output) {
233 Document* doc = frame->document();
234 if (!doc)
235 return;
236
237 if (!frame->view())
238 return;
239
240 // TextIterator iterates over the visual representation of the DOM. As such,
241 // it requires you to do a layout before using it (otherwise it'll crash).
242 if (frame->view()->needsLayout())
243 frame->view()->layout();
244
245 // Select the document body.
246 RefPtr<Range> range(doc->createRange());
247 ExceptionCode exception = 0;
248 range->selectNodeContents(doc->body(), exception);
249
250 if (exception == 0) {
251 // The text iterator will walk nodes giving us text. This is similar to
252 // the plainText() function in TextIterator.h, but we implement the maximum
253 // size and also copy the results directly into a wstring, avoiding the
254 // string conversion.
255 for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
256 const UChar* chars = it.characters();
257 if (!chars) {
258 if (it.length() != 0) {
259 // It appears from crash reports that an iterator can get into a state
260 // where the character count is nonempty but the character pointer is
261 // NULL. advance()ing it will then just add that many to the NULL
262 // pointer which won't be caught in a NULL check but will crash.
263 //
264 // A NULL pointer and 0 length is common for some nodes.
265 //
266 // IF YOU CATCH THIS IN A DEBUGGER please let brettw know. We don't
267 // currently understand the conditions for this to occur. Ideally, the
268 // iterators would never get into the condition so we should fix them
269 // if we can.
270 ASSERT_NOT_REACHED();
271 break;
272 }
273
274 // Just got a NULL node, we can forge ahead!
275 continue;
276 }
277 size_t to_append = std::min(static_cast<size_t>(it.length()),
278 max_chars - output->size());
279 output->append(chars, to_append);
280 if (output->size() >= max_chars)
281 return; // Filled up the buffer.
282 }
283 }
284
285 // Recursively walk the children.
286 FrameTree* frame_tree = frame->tree();
287 for (Frame* cur_child = frame_tree->firstChild(); cur_child;
288 cur_child = cur_child->tree()->nextSibling()) {
289 // Make sure the frame separator won't fill up the buffer, and give up if
290 // it will. The danger is if the separator will make the buffer longer than
291 // max_chars. This will cause the computation above:
292 // max_chars - output->size()
293 // to be a negative number which will crash when the subframe is added.
294 if (output->size() >= max_chars - kFrameSeparatorLen)
295 return;
296
297 output->append(kFrameSeparator, kFrameSeparatorLen);
298 FrameContentAsPlainText(max_chars, cur_child, output);
299 if (output->size() >= max_chars)
300 return; // Filled up the buffer.
301 }
302 }
303
304 // Simple class to override some of PrintContext behavior.
305 class ChromePrintContext : public WebCore::PrintContext {
306 public:
307 ChromePrintContext(Frame* frame)
308 : PrintContext(frame),
309 printed_page_width_(0) {
310 }
311 void begin(float width) {
312 ASSERT(!printed_page_width_);
313 printed_page_width_ = width;
314 WebCore::PrintContext::begin(printed_page_width_);
315 }
316 float getPageShrink(int pageNumber) const {
317 IntRect pageRect = m_pageRects[pageNumber];
318 return printed_page_width_ / pageRect.width();
319 }
320 // Spools the printed page, a subrect of m_frame.
321 // Skip the scale step. NativeTheme doesn't play well with scaling. Scaling
322 // is done browser side instead.
323 // Returns the scale to be applied.
324 float spoolPage(GraphicsContext& ctx, int pageNumber) {
325 IntRect pageRect = m_pageRects[pageNumber];
326 float scale = printed_page_width_ / pageRect.width();
327
328 ctx.save();
329 ctx.translate(static_cast<float>(-pageRect.x()),
330 static_cast<float>(-pageRect.y()));
331 ctx.clip(pageRect);
332 m_frame->view()->paintContents(&ctx, pageRect);
333 ctx.restore();
334 return scale;
335 }
336 protected:
337 // Set when printing.
338 float printed_page_width_;
339
340 private:
341 DISALLOW_COPY_AND_ASSIGN(ChromePrintContext);
342 };
343
344 static WebDataSource* DataSourceForDocLoader(DocumentLoader* loader) {
345 return loader ? WebDataSourceImpl::fromDocumentLoader(loader) : NULL;
346 }
347
348
349 // WebFrame -------------------------------------------------------------------
350
351 class WebFrameImpl::DeferredScopeStringMatches {
352 public:
353 DeferredScopeStringMatches(WebFrameImpl* webframe,
354 int identifier,
355 const WebString& search_text,
356 const WebFindOptions& options,
357 bool reset)
358 : ALLOW_THIS_IN_INITIALIZER_LIST(
359 timer_(this, &DeferredScopeStringMatches::DoTimeout)),
360 webframe_(webframe),
361 identifier_(identifier),
362 search_text_(search_text),
363 options_(options),
364 reset_(reset) {
365 timer_.startOneShot(0.0);
366 }
367
368 private:
369 void DoTimeout(Timer<DeferredScopeStringMatches>*) {
370 webframe_->CallScopeStringMatches(
371 this, identifier_, search_text_, options_, reset_);
372 }
373
374 Timer<DeferredScopeStringMatches> timer_;
375 RefPtr<WebFrameImpl> webframe_;
376 int identifier_;
377 WebString search_text_;
378 WebFindOptions options_;
379 bool reset_;
380 };
381
382
383 // WebFrame -------------------------------------------------------------------
384
385 // static
386 WebFrame* WebFrame::frameForEnteredContext() {
387 Frame* frame =
388 WebCore::ScriptController::retrieveFrameForEnteredContext();
389 return WebFrameImpl::FromFrame(frame);
390 }
391
392 // static
393 WebFrame* WebFrame::frameForCurrentContext() {
394 Frame* frame =
395 WebCore::ScriptController::retrieveFrameForCurrentContext();
396 return WebFrameImpl::FromFrame(frame);
397 }
398
399 WebString WebFrameImpl::name() const {
400 return webkit_glue::StringToWebString(frame_->tree()->name());
401 }
402
403 WebURL WebFrameImpl::url() const {
404 const WebDataSource* ds = dataSource();
405 if (!ds)
406 return WebURL();
407 return ds->request().url();
408 }
409
410 WebURL WebFrameImpl::favIconURL() const {
411 WebCore::FrameLoader* frame_loader = frame_->loader();
412 // The URL to the favicon may be in the header. As such, only
413 // ask the loader for the favicon if it's finished loading.
414 if (frame_loader->state() == WebCore::FrameStateComplete) {
415 const KURL& url = frame_loader->iconURL();
416 if (!url.isEmpty()) {
417 return webkit_glue::KURLToWebURL(url);
418 }
419 }
420 return WebURL();
421 }
422
423 WebURL WebFrameImpl::openSearchDescriptionURL() const {
424 WebCore::FrameLoader* frame_loader = frame_->loader();
425 if (frame_loader->state() == WebCore::FrameStateComplete &&
426 frame_->document() && frame_->document()->head() &&
427 !frame_->tree()->parent()) {
428 WebCore::HTMLHeadElement* head = frame_->document()->head();
429 if (head) {
430 RefPtr<WebCore::HTMLCollection> children = head->children();
431 for (Node* child = children->firstItem(); child != NULL;
432 child = children->nextItem()) {
433 WebCore::HTMLLinkElement* link_element =
434 WebKit::toHTMLLinkElement(child);
435 if (link_element && link_element->type() == kOSDType &&
436 link_element->rel() == kOSDRel && !link_element->href().isEmpty()) {
437 return webkit_glue::KURLToWebURL(link_element->href());
438 }
439 }
440 }
441 }
442 return WebURL();
443 }
444
445 WebSize WebFrameImpl::scrollOffset() const {
446 WebCore::FrameView* view = frameview();
447 if (view)
448 return webkit_glue::IntSizeToWebSize(view->scrollOffset());
449
450 return WebSize();
451 }
452
453 WebSize WebFrameImpl::contentsSize() const {
454 return webkit_glue::IntSizeToWebSize(frame()->view()->contentsSize());
455 }
456
457 int WebFrameImpl::contentsPreferredWidth() const {
458 if ((frame_->document() != NULL) &&
459 (frame_->document()->renderView() != NULL)) {
460 return frame_->document()->renderView()->minPrefWidth();
461 } else {
462 return 0;
463 }
464 }
465
466 bool WebFrameImpl::hasVisibleContent() const {
467 return frame()->view()->visibleWidth() > 0 &&
468 frame()->view()->visibleHeight() > 0;
469 }
470
471 WebView* WebFrameImpl::view() const {
472 return GetWebViewImpl();
473 }
474
475 WebFrame* WebFrameImpl::opener() const {
476 Frame* opener = NULL;
477 if (frame_)
478 opener = frame_->loader()->opener();
479 return FromFrame(opener);
480 }
481
482 WebFrame* WebFrameImpl::parent() const {
483 Frame *parent = NULL;
484 if (frame_)
485 parent = frame_->tree()->parent();
486 return FromFrame(parent);
487 }
488
489 WebFrame* WebFrameImpl::top() const {
490 if (frame_)
491 return FromFrame(frame_->tree()->top());
492
493 return NULL;
494 }
495
496 WebFrame* WebFrameImpl::firstChild() const {
497 return FromFrame(frame()->tree()->firstChild());
498 }
499
500 WebFrame* WebFrameImpl::lastChild() const {
501 return FromFrame(frame()->tree()->lastChild());
502 }
503
504 WebFrame* WebFrameImpl::nextSibling() const {
505 return FromFrame(frame()->tree()->nextSibling());
506 }
507
508 WebFrame* WebFrameImpl::previousSibling() const {
509 return FromFrame(frame()->tree()->previousSibling());
510 }
511
512 WebFrame* WebFrameImpl::traverseNext(bool wrap) const {
513 return FromFrame(frame()->tree()->traverseNextWithWrap(wrap));
514 }
515
516 WebFrame* WebFrameImpl::traversePrevious(bool wrap) const {
517 return FromFrame(frame()->tree()->traversePreviousWithWrap(wrap));
518 }
519
520 WebFrame* WebFrameImpl::findChildByName(const WebKit::WebString& name) const {
521 return FromFrame(frame()->tree()->child(
522 webkit_glue::WebStringToString(name)));
523 }
524
525 WebFrame* WebFrameImpl::findChildByExpression(
526 const WebKit::WebString& xpath) const {
527 if (xpath.isEmpty())
528 return NULL;
529
530 Document* document = frame_->document();
531
532 ExceptionCode ec = 0;
533 PassRefPtr<XPathResult> xpath_result =
534 document->evaluate(webkit_glue::WebStringToString(xpath),
535 document,
536 NULL, /* namespace */
537 XPathResult::ORDERED_NODE_ITERATOR_TYPE,
538 NULL, /* XPathResult object */
539 ec);
540 if (!xpath_result.get())
541 return NULL;
542
543 Node* node = xpath_result->iterateNext(ec);
544
545 if (!node || !node->isFrameOwnerElement())
546 return NULL;
547 HTMLFrameOwnerElement* frame_element =
548 static_cast<HTMLFrameOwnerElement*>(node);
549 return FromFrame(frame_element->contentFrame());
550 }
551
552 void WebFrameImpl::forms(WebVector<WebForm>& results) const {
553 if (!frame_)
554 return;
555
556 RefPtr<WebCore::HTMLCollection> forms = frame_->document()->forms();
557 size_t form_count = forms->length();
558
559 WebVector<WebForm> temp(form_count);
560 for (size_t i = 0; i < form_count; ++i) {
561 Node* node = forms->item(i);
562 // Strange but true, sometimes item can be NULL.
563 if (node) {
564 temp[i] = webkit_glue::HTMLFormElementToWebForm(
565 static_cast<HTMLFormElement*>(node));
566 }
567 }
568 results.swap(temp);
569 }
570
571 WebSecurityOrigin WebFrameImpl::securityOrigin() const {
572 if (!frame_ || !frame_->document())
573 return WebSecurityOrigin();
574
575 return webkit_glue::SecurityOriginToWebSecurityOrigin(
576 frame_->document()->securityOrigin());
577 }
578
579 void WebFrameImpl::grantUniversalAccess() {
580 ASSERT(frame_ && frame_->document());
581 if (frame_ && frame_->document()) {
582 frame_->document()->securityOrigin()->grantUniversalAccess();
583 }
584 }
585
586 NPObject* WebFrameImpl::windowObject() const {
587 if (!frame_)
588 return NULL;
589
590 return frame_->script()->windowScriptNPObject();
591 }
592
593 void WebFrameImpl::bindToWindowObject(const WebString& name,
594 NPObject* object) {
595 ASSERT(frame_);
596 if (!frame_ || !frame_->script()->isEnabled())
597 return;
598
599 String key = webkit_glue::WebStringToString(name);
600 #if USE(V8)
601 frame_->script()->bindToWindowObject(frame_, key, object);
602 #else
603 notImplemented();
604 #endif
605 }
606
607 void WebFrameImpl::executeScript(const WebScriptSource& source) {
608 frame_->script()->executeScript(
609 WebCore::ScriptSourceCode(
610 webkit_glue::WebStringToString(source.code),
611 webkit_glue::WebURLToKURL(source.url),
612 source.startLine));
613 }
614
615 void WebFrameImpl::executeScriptInNewContext(
616 const WebScriptSource* sources_in, unsigned num_sources,
617 int extension_group) {
618 Vector<WebCore::ScriptSourceCode> sources;
619
620 for (unsigned i = 0; i < num_sources; ++i) {
621 sources.append(WebCore::ScriptSourceCode(
622 webkit_glue::WebStringToString(sources_in[i].code),
623 webkit_glue::WebURLToKURL(sources_in[i].url),
624 sources_in[i].startLine));
625 }
626
627 frame_->script()->evaluateInNewContext(sources, extension_group);
628 }
629
630 void WebFrameImpl::executeScriptInIsolatedWorld(
631 int world_id, const WebScriptSource* sources_in, unsigned num_sources,
632 int extension_group) {
633 Vector<WebCore::ScriptSourceCode> sources;
634
635 for (unsigned i = 0; i < num_sources; ++i) {
636 sources.append(WebCore::ScriptSourceCode(
637 webkit_glue::WebStringToString(sources_in[i].code),
638 webkit_glue::WebURLToKURL(sources_in[i].url),
639 sources_in[i].startLine));
640 }
641
642 frame_->script()->evaluateInIsolatedWorld(world_id, sources, extension_group);
643 }
644
645 void WebFrameImpl::addMessageToConsole(const WebConsoleMessage& message) {
646 ASSERT(frame());
647
648 WebCore::MessageLevel webcore_message_level;
649 switch (message.level) {
650 case WebConsoleMessage::LevelTip:
651 webcore_message_level = WebCore::TipMessageLevel;
652 break;
653 case WebConsoleMessage::LevelLog:
654 webcore_message_level = WebCore::LogMessageLevel;
655 break;
656 case WebConsoleMessage::LevelWarning:
657 webcore_message_level = WebCore::WarningMessageLevel;
658 break;
659 case WebConsoleMessage::LevelError:
660 webcore_message_level = WebCore::ErrorMessageLevel;
661 break;
662 default:
663 ASSERT_NOT_REACHED();
664 return;
665 }
666
667 frame()->domWindow()->console()->addMessage(
668 WebCore::OtherMessageSource, WebCore::LogMessageType,
669 webcore_message_level, webkit_glue::WebStringToString(message.text),
670 1, String());
671 }
672
673 void WebFrameImpl::collectGarbage() {
674 if (!frame_)
675 return;
676 if (!frame_->settings()->isJavaScriptEnabled())
677 return;
678 // TODO(mbelshe): Move this to the ScriptController and make it JS neutral.
679 #if USE(V8)
680 frame_->script()->collectGarbage();
681 #else
682 notImplemented();
683 #endif
684 }
685
686 #if USE(V8)
687 // Returns the V8 context for this frame, or an empty handle if there is none.
688 v8::Local<v8::Context> WebFrameImpl::mainWorldScriptContext() const {
689 if (!frame_)
690 return v8::Local<v8::Context>();
691
692 return WebCore::V8Proxy::mainWorldContext(frame_);
693 }
694 #endif
695
696 bool WebFrameImpl::insertStyleText(
697 const WebString& css, const WebString& id) {
698 Document* document = frame()->document();
699 if (!document)
700 return false;
701 WebCore::Element* document_element = document->documentElement();
702 if (!document_element)
703 return false;
704
705 ExceptionCode err = 0;
706
707 if (!id.isEmpty()) {
708 WebCore::Element* old_element =
709 document->getElementById(webkit_glue::WebStringToString(id));
710 if (old_element) {
711 Node* parent = old_element->parent();
712 if (!parent)
713 return false;
714 parent->removeChild(old_element, err);
715 }
716 }
717
718 RefPtr<WebCore::Element> stylesheet = document->createElement(
719 WebCore::HTMLNames::styleTag, false);
720 if (!id.isEmpty())
721 stylesheet->setAttribute(WebCore::HTMLNames::idAttr,
722 webkit_glue::WebStringToString(id));
723 stylesheet->setTextContent(webkit_glue::WebStringToString(css), err);
724 ASSERT(!err);
725 WebCore::Node* first = document_element->firstChild();
726 bool success = document_element->insertBefore(stylesheet, first, err);
727 ASSERT(success);
728 return success;
729 }
730
731 void WebFrameImpl::reload() {
732 frame_->loader()->history()->saveDocumentAndScrollState();
733
734 stopLoading(); // Make sure existing activity stops.
735 frame_->loader()->reload();
736 }
737
738 void WebFrameImpl::loadRequest(const WebURLRequest& request) {
739 const ResourceRequest* resource_request =
740 webkit_glue::WebURLRequestToResourceRequest(&request);
741 ASSERT(resource_request);
742
743 if (resource_request->url().protocolIs("javascript")) {
744 LoadJavaScriptURL(resource_request->url());
745 return;
746 }
747
748 stopLoading(); // Make sure existing activity stops.
749 frame_->loader()->load(*resource_request, false);
750 }
751
752 void WebFrameImpl::loadHistoryItem(const WebHistoryItem& item) {
753 RefPtr<HistoryItem> history_item =
754 webkit_glue::WebHistoryItemToHistoryItem(item);
755 ASSERT(history_item.get());
756
757 stopLoading(); // Make sure existing activity stops.
758
759 // If there is no current_item, which happens when we are navigating in
760 // session history after a crash, we need to manufacture one otherwise WebKit
761 // hoarks. This is probably the wrong thing to do, but it seems to work.
762 RefPtr<HistoryItem> current_item = frame_->loader()->history()->currentItem();
763 if (!current_item) {
764 current_item = HistoryItem::create();
765 current_item->setLastVisitWasFailure(true);
766 frame_->loader()->history()->setCurrentItem(current_item.get());
767 GetWebViewImpl()->SetCurrentHistoryItem(current_item.get());
768 }
769
770 frame_->loader()->history()->goToItem(history_item.get(),
771 WebCore::FrameLoadTypeIndexedBackForward );
772 }
773
774 void WebFrameImpl::loadData(const WebData& data,
775 const WebString& mime_type,
776 const WebString& text_encoding,
777 const WebURL& base_url,
778 const WebURL& unreachable_url,
779 bool replace) {
780 SubstituteData subst_data(
781 webkit_glue::WebDataToSharedBuffer(data),
782 webkit_glue::WebStringToString(mime_type),
783 webkit_glue::WebStringToString(text_encoding),
784 webkit_glue::WebURLToKURL(unreachable_url));
785 ASSERT(subst_data.isValid());
786
787 stopLoading(); // Make sure existing activity stops.
788 frame_->loader()->load(ResourceRequest(webkit_glue::WebURLToKURL(base_url)),
789 subst_data, false);
790 if (replace) {
791 // Do this to force WebKit to treat the load as replacing the currently
792 // loaded page.
793 frame_->loader()->setReplacing();
794 }
795 }
796
797 void WebFrameImpl::loadHTMLString(const WebData& data,
798 const WebURL& base_url,
799 const WebURL& unreachable_url,
800 bool replace) {
801 loadData(data,
802 WebString::fromUTF8("text/html"),
803 WebString::fromUTF8("UTF-8"),
804 base_url,
805 unreachable_url,
806 replace);
807 }
808
809 bool WebFrameImpl::isLoading() const {
810 if (!frame_)
811 return false;
812 return frame_->loader()->isLoading();
813 }
814
815 void WebFrameImpl::stopLoading() {
816 if (!frame_)
817 return;
818
819 // TODO(darin): Figure out what we should really do here. It seems like a
820 // bug that FrameLoader::stopLoading doesn't call stopAllLoaders.
821 frame_->loader()->stopAllLoaders();
822 frame_->loader()->stopLoading(WebCore::UnloadEventPolicyNone);
823 }
824
825 WebDataSource* WebFrameImpl::provisionalDataSource() const {
826 FrameLoader* frame_loader = frame_->loader();
827
828 // We regard the policy document loader as still provisional.
829 DocumentLoader* doc_loader = frame_loader->provisionalDocumentLoader();
830 if (!doc_loader)
831 doc_loader = frame_loader->policyDocumentLoader();
832
833 return DataSourceForDocLoader(doc_loader);
834 }
835
836 WebDataSource* WebFrameImpl::dataSource() const {
837 return DataSourceForDocLoader(frame_->loader()->documentLoader());
838 }
839
840 WebHistoryItem WebFrameImpl::previousHistoryItem() const {
841 // We use the previous item here because documentState (filled-out forms)
842 // only get saved to history when it becomes the previous item. The caller
843 // is expected to query the history item after a navigation occurs, after
844 // the desired history item has become the previous entry.
845 return webkit_glue::HistoryItemToWebHistoryItem(
846 GetWebViewImpl()->GetPreviousHistoryItem());
847 }
848
849 WebHistoryItem WebFrameImpl::currentHistoryItem() const {
850 frame_->loader()->history()->saveDocumentAndScrollState();
851
852 return webkit_glue::HistoryItemToWebHistoryItem(
853 frame_->page()->backForwardList()->currentItem());
854 }
855
856 void WebFrameImpl::enableViewSourceMode(bool enable) {
857 if (frame_)
858 frame_->setInViewSourceMode(enable);
859 }
860
861 bool WebFrameImpl::isViewSourceModeEnabled() const {
862 if (frame_)
863 return frame_->inViewSourceMode();
864
865 return false;
866 }
867
868 void WebFrameImpl::setReferrerForRequest(
869 WebURLRequest& request, const WebURL& referrer_url) {
870 String referrer;
871 if (referrer_url.isEmpty()) {
872 referrer = frame_->loader()->outgoingReferrer();
873 } else {
874 referrer = webkit_glue::WebStringToString(referrer_url.spec().utf16());
875 }
876 if (SecurityOrigin::shouldHideReferrer(
877 webkit_glue::WebURLToKURL(request.url()), referrer))
878 return;
879 request.setHTTPHeaderField(WebString::fromUTF8("Referer"),
880 webkit_glue::StringToWebString(referrer));
881 }
882
883 void WebFrameImpl::dispatchWillSendRequest(WebURLRequest& request) {
884 ResourceResponse response;
885 frame_->loader()->client()->dispatchWillSendRequest(NULL, 0,
886 *webkit_glue::WebURLRequestToMutableResourceRequest(&request),
887 response);
888 }
889
890 void WebFrameImpl::commitDocumentData(const char* data, size_t data_len) {
891 DocumentLoader* document_loader = frame_->loader()->documentLoader();
892
893 // Set the text encoding. This calls begin() for us. It is safe to call
894 // this multiple times (Mac does: page/mac/WebCoreFrameBridge.mm).
895 bool user_chosen = true;
896 String encoding = document_loader->overrideEncoding();
897 if (encoding.isNull()) {
898 user_chosen = false;
899 encoding = document_loader->response().textEncodingName();
900 }
901 frame_->loader()->setEncoding(encoding, user_chosen);
902
903 // NOTE: mac only does this if there is a document
904 frame_->loader()->addData(data, data_len);
905 }
906
907 unsigned WebFrameImpl::unloadListenerCount() const {
908 return frame()->domWindow()->pendingUnloadEventListeners();
909 }
910
911 bool WebFrameImpl::isProcessingUserGesture() const {
912 return frame()->loader()->isProcessingUserGesture();
913 }
914
915 bool WebFrameImpl::willSuppressOpenerInNewFrame() const {
916 return frame()->loader()->suppressOpenerInNewFrame();
917 }
918
919 void WebFrameImpl::replaceSelection(const WebString& wtext) {
920 String text = webkit_glue::WebStringToString(wtext);
921 RefPtr<DocumentFragment> fragment = createFragmentFromText(
922 frame()->selection()->toNormalizedRange().get(), text);
923 WebCore::applyCommand(WebCore::ReplaceSelectionCommand::create(
924 frame()->document(), fragment.get(), false, true, true));
925 }
926
927 void WebFrameImpl::insertText(const WebString& text) {
928 frame()->editor()->insertText(webkit_glue::WebStringToString(text), NULL);
929 }
930
931 void WebFrameImpl::setMarkedText(
932 const WebString& text, unsigned location, unsigned length) {
933 WebCore::Editor* editor = frame()->editor();
934 WebCore::String str = webkit_glue::WebStringToString(text);
935
936 editor->confirmComposition(str);
937
938 WTF::Vector<WebCore::CompositionUnderline> decorations;
939 editor->setComposition(str, decorations, location, length);
940 }
941
942 void WebFrameImpl::unmarkText() {
943 frame()->editor()->confirmCompositionWithoutDisturbingSelection();
944 }
945
946 bool WebFrameImpl::hasMarkedText() const {
947 return frame()->editor()->hasComposition();
948 }
949
950 WebRange WebFrameImpl::markedRange() const {
951 return webkit_glue::RangeToWebRange(frame()->editor()->compositionRange());
952 }
953
954 bool WebFrameImpl::executeCommand(const WebString& name) {
955 ASSERT(frame());
956
957 if (name.length() <= 2)
958 return false;
959
960 // Since we don't have NSControl, we will convert the format of command
961 // string and call the function on Editor directly.
962 String command = webkit_glue::WebStringToString(name);
963
964 // Make sure the first letter is upper case.
965 command.replace(0, 1, command.substring(0, 1).upper());
966
967 // Remove the trailing ':' if existing.
968 if (command[command.length() - 1] == UChar(':'))
969 command = command.substring(0, command.length() - 1);
970
971 bool rv = true;
972
973 // Specially handling commands that Editor::execCommand does not directly
974 // support.
975 if (command == "DeleteToEndOfParagraph") {
976 WebCore::Editor* editor = frame()->editor();
977 if (!editor->deleteWithDirection(WebCore::SelectionController::FORWARD,
978 WebCore::ParagraphBoundary,
979 true,
980 false)) {
981 editor->deleteWithDirection(WebCore::SelectionController::FORWARD,
982 WebCore::CharacterGranularity,
983 true,
984 false);
985 }
986 } else if (command == "Indent") {
987 frame()->editor()->indent();
988 } else if (command == "Outdent") {
989 frame()->editor()->outdent();
990 } else if (command == "DeleteBackward") {
991 rv = frame()->editor()->command(AtomicString("BackwardDelete")).execute();
992 } else if (command == "DeleteForward") {
993 rv = frame()->editor()->command(AtomicString("ForwardDelete")).execute();
994 } else if (command == "AdvanceToNextMisspelling") {
995 // False must be passed here, or the currently selected word will never be
996 // skipped.
997 frame()->editor()->advanceToNextMisspelling(false);
998 } else if (command == "ToggleSpellPanel") {
999 frame()->editor()->showSpellingGuessPanel();
1000 } else {
1001 rv = frame()->editor()->command(command).execute();
1002 }
1003 return rv;
1004 }
1005
1006 bool WebFrameImpl::executeCommand(const WebString& name,
1007 const WebString& value) {
1008 ASSERT(frame());
1009 WebCore::String web_name = webkit_glue::WebStringToString(name);
1010
1011 // moveToBeginningOfDocument and moveToEndfDocument are only handled by WebKit
1012 // for editable nodes.
1013 if (!frame()->editor()->canEdit() &&
1014 web_name == "moveToBeginningOfDocument") {
1015 return GetWebViewImpl()->PropagateScroll(WebCore::ScrollUp,
1016 WebCore::ScrollByDocument);
1017 } else if (!frame()->editor()->canEdit() &&
1018 web_name == "moveToEndOfDocument") {
1019 return GetWebViewImpl()->PropagateScroll(WebCore::ScrollDown,
1020 WebCore::ScrollByDocument);
1021 } else {
1022 return frame()->editor()->command(web_name).
1023 execute(webkit_glue::WebStringToString(value));
1024 }
1025 }
1026
1027 bool WebFrameImpl::isCommandEnabled(const WebString& name) const {
1028 ASSERT(frame());
1029 return frame()->editor()->command(webkit_glue::WebStringToString(name)).
1030 isEnabled();
1031 }
1032
1033 void WebFrameImpl::enableContinuousSpellChecking(bool enable) {
1034 if (enable == isContinuousSpellCheckingEnabled())
1035 return;
1036 frame()->editor()->toggleContinuousSpellChecking();
1037 }
1038
1039 bool WebFrameImpl::isContinuousSpellCheckingEnabled() const {
1040 return frame()->editor()->isContinuousSpellCheckingEnabled();
1041 }
1042
1043 bool WebFrameImpl::hasSelection() const {
1044 // frame()->selection()->isNone() never returns true.
1045 return (frame()->selection()->start() != frame()->selection()->end());
1046 }
1047
1048 WebRange WebFrameImpl::selectionRange() const {
1049 return webkit_glue::RangeToWebRange(
1050 frame()->selection()->toNormalizedRange());
1051 }
1052
1053 WebString WebFrameImpl::selectionAsText() const {
1054 RefPtr<Range> range = frame()->selection()->toNormalizedRange();
1055 if (!range.get())
1056 return WebString();
1057
1058 String text = range->text();
1059 #if PLATFORM(WIN_OS)
1060 WebCore::replaceNewlinesWithWindowsStyleNewlines(text);
1061 #endif
1062 WebCore::replaceNBSPWithSpace(text);
1063 return webkit_glue::StringToWebString(text);
1064 }
1065
1066 WebString WebFrameImpl::selectionAsMarkup() const {
1067 RefPtr<Range> range = frame()->selection()->toNormalizedRange();
1068 if (!range.get())
1069 return WebString();
1070
1071 String markup = WebCore::createMarkup(range.get(), 0);
1072 return webkit_glue::StringToWebString(markup);
1073 }
1074
1075 int WebFrameImpl::printBegin(const WebSize& page_size) {
1076 ASSERT(!frame()->document()->isFrameSet());
1077
1078 print_context_.set(new ChromePrintContext(frame()));
1079 WebCore::FloatRect rect(0, 0,
1080 static_cast<float>(page_size.width),
1081 static_cast<float>(page_size.height));
1082 print_context_->begin(rect.width());
1083 float page_height;
1084 // We ignore the overlays calculation for now since they are generated in the
1085 // browser. page_height is actually an output parameter.
1086 print_context_->computePageRects(rect, 0, 0, 1.0, page_height);
1087 return print_context_->pageCount();
1088 }
1089
1090 float WebFrameImpl::getPrintPageShrink(int page) {
1091 // Ensure correct state.
1092 if (!print_context_.get() || page < 0) {
1093 ASSERT_NOT_REACHED();
1094 return 0;
1095 }
1096
1097 return print_context_->getPageShrink(page);
1098 }
1099
1100 float WebFrameImpl::printPage(int page, WebCanvas* canvas) {
1101 // Ensure correct state.
1102 if (!print_context_.get() || page < 0 || !frame() || !frame()->document()) {
1103 ASSERT_NOT_REACHED();
1104 return 0;
1105 }
1106
1107 #if PLATFORM(WIN_OS) || PLATFORM(LINUX) || PLATFORM(FREEBSD)
1108 PlatformContextSkia context(canvas);
1109 GraphicsContext spool(&context);
1110 #elif PLATFORM(DARWIN)
1111 GraphicsContext spool(canvas);
1112 WebCore::LocalCurrentGraphicsContext localContext(&spool);
1113 #endif
1114
1115 return print_context_->spoolPage(spool, page);
1116 }
1117
1118 void WebFrameImpl::printEnd() {
1119 ASSERT(print_context_.get());
1120 if (print_context_.get())
1121 print_context_->end();
1122 print_context_.clear();
1123 }
1124
1125 bool WebFrameImpl::find(int request_id,
1126 const WebString& search_text,
1127 const WebFindOptions& options,
1128 bool wrap_within_frame,
1129 WebRect* selection_rect) {
1130 WebCore::String webcore_string = webkit_glue::WebStringToString(search_text);
1131
1132 WebFrameImpl* const main_frame_impl = GetWebViewImpl()->main_frame();
1133
1134 if (!options.findNext)
1135 frame()->page()->unmarkAllTextMatches();
1136 else
1137 SetMarkerActive(active_match_.get(), false); // Active match is changing.
1138
1139 // Starts the search from the current selection.
1140 bool start_in_selection = true;
1141
1142 // If the user has selected something since the last Find operation we want
1143 // to start from there. Otherwise, we start searching from where the last Find
1144 // operation left off (either a Find or a FindNext operation).
1145 VisibleSelection selection(frame()->selection()->selection());
1146 if (selection.isNone() && active_match_) {
1147 selection = VisibleSelection(active_match_.get());
1148 frame()->selection()->setSelection(selection);
1149 }
1150
1151 ASSERT(frame() && frame()->view());
1152 bool found = frame()->findString(webcore_string, options.forward,
1153 options.matchCase, wrap_within_frame,
1154 start_in_selection);
1155 if (found) {
1156 // Store which frame was active. This will come in handy later when we
1157 // change the active match ordinal below.
1158 WebFrameImpl* old_active_frame = main_frame_impl->active_match_frame_;
1159 // Set this frame as the active frame (the one with the active highlight).
1160 main_frame_impl->active_match_frame_ = this;
1161
1162 // We found something, so we can now query the selection for its position.
1163 VisibleSelection new_selection(frame()->selection()->selection());
1164 IntRect curr_selection_rect;
1165
1166 // If we thought we found something, but it couldn't be selected (perhaps
1167 // because it was marked -webkit-user-select: none), we can't set it to
1168 // be active but we still continue searching. This matches Safari's
1169 // behavior, including some oddities when selectable and un-selectable text
1170 // are mixed on a page: see https://bugs.webkit.org/show_bug.cgi?id=19127.
1171 if (new_selection.isNone() ||
1172 (new_selection.start() == new_selection.end())) {
1173 active_match_ = NULL;
1174 } else {
1175 active_match_ = new_selection.toNormalizedRange();
1176 curr_selection_rect = active_match_->boundingBox();
1177 SetMarkerActive(active_match_.get(), true); // Active.
1178 // WebKit draws the highlighting for all matches.
1179 executeCommand(WebString::fromUTF8("Unselect"));
1180 }
1181
1182 if (!options.findNext) {
1183 // This is a Find operation, so we set the flag to ask the scoping effort
1184 // to find the active rect for us so we can update the ordinal (n of m).
1185 locating_active_rect_ = true;
1186 } else {
1187 if (old_active_frame != this) {
1188 // If the active frame has changed it means that we have a multi-frame
1189 // page and we just switch to searching in a new frame. Then we just
1190 // want to reset the index.
1191 if (options.forward)
1192 active_match_index_ = 0;
1193 else
1194 active_match_index_ = last_match_count_ - 1;
1195 } else {
1196 // We are still the active frame, so increment (or decrement) the
1197 // |active_match_index|, wrapping if needed (on single frame pages).
1198 options.forward ? ++active_match_index_ : --active_match_index_;
1199 if (active_match_index_ + 1 > last_match_count_)
1200 active_match_index_ = 0;
1201 if (active_match_index_ + 1 == 0)
1202 active_match_index_ = last_match_count_ - 1;
1203 }
1204 if (selection_rect) {
1205 WebRect rect = webkit_glue::IntRectToWebRect(
1206 frame()->view()->convertToContainingWindow(curr_selection_rect));
1207 rect.x -= frameview()->scrollOffset().width();
1208 rect.y -= frameview()->scrollOffset().height();
1209 *selection_rect = rect;
1210
1211 ReportFindInPageSelection(rect,
1212 active_match_index_ + 1,
1213 request_id);
1214 }
1215 }
1216 } else {
1217 // Nothing was found in this frame.
1218 active_match_ = NULL;
1219
1220 // Erase all previous tickmarks and highlighting.
1221 InvalidateArea(INVALIDATE_ALL);
1222 }
1223
1224 return found;
1225 }
1226
1227 void WebFrameImpl::stopFinding(bool clear_selection) {
1228 if (!clear_selection)
1229 SetFindEndstateFocusAndSelection();
1230 cancelPendingScopingEffort();
1231
1232 // Remove all markers for matches found and turn off the highlighting.
1233 if (!parent())
1234 frame()->document()->removeMarkers(WebCore::DocumentMarker::TextMatch);
1235 frame()->setMarkedTextMatchesAreHighlighted(false);
1236
1237 // Let the frame know that we don't want tickmarks or highlighting anymore.
1238 InvalidateArea(INVALIDATE_ALL);
1239 }
1240
1241 void WebFrameImpl::scopeStringMatches(int request_id,
1242 const WebString& search_text,
1243 const WebFindOptions& options,
1244 bool reset) {
1245 if (!ShouldScopeMatches(search_text))
1246 return;
1247
1248 WebFrameImpl* main_frame_impl = GetWebViewImpl()->main_frame();
1249
1250 if (reset) {
1251 // This is a brand new search, so we need to reset everything.
1252 // Scoping is just about to begin.
1253 scoping_complete_ = false;
1254 // Clear highlighting for this frame.
1255 if (frame()->markedTextMatchesAreHighlighted())
1256 frame()->page()->unmarkAllTextMatches();
1257 // Clear the counters from last operation.
1258 last_match_count_ = 0;
1259 next_invalidate_after_ = 0;
1260
1261 resume_scoping_from_range_ = NULL;
1262
1263 main_frame_impl->frames_scoping_count_++;
1264
1265 // Now, defer scoping until later to allow find operation to finish quickly.
1266 ScopeStringMatchesSoon(
1267 request_id,
1268 search_text,
1269 options,
1270 false); // false=we just reset, so don't do it again.
1271 return;
1272 }
1273
1274 WebCore::String webcore_string = webkit_glue::String16ToString(search_text);
1275
1276 RefPtr<Range> search_range(rangeOfContents(frame()->document()));
1277
1278 ExceptionCode ec = 0, ec2 = 0;
1279 if (resume_scoping_from_range_.get()) {
1280 // This is a continuation of a scoping operation that timed out and didn't
1281 // complete last time around, so we should start from where we left off.
1282 search_range->setStart(resume_scoping_from_range_->startContainer(),
1283 resume_scoping_from_range_->startOffset(ec2) + 1,
1284 ec);
1285 if (ec != 0 || ec2 != 0) {
1286 if (ec2 != 0) // A non-zero |ec| happens when navigating during search.
1287 ASSERT_NOT_REACHED();
1288 return;
1289 }
1290 }
1291
1292 // This timeout controls how long we scope before releasing control. This
1293 // value does not prevent us from running for longer than this, but it is
1294 // periodically checked to see if we have exceeded our allocated time.
1295 const double kTimeout = 0.1; // seconds
1296
1297 int match_count = 0;
1298 bool timeout = false;
1299 double start_time = currentTime();
1300 do {
1301 // Find next occurrence of the search string.
1302 // TODO(finnur): (http://b/1088245) This WebKit operation may run
1303 // for longer than the timeout value, and is not interruptible as it is
1304 // currently written. We may need to rewrite it with interruptibility in
1305 // mind, or find an alternative.
1306 RefPtr<Range> result_range(findPlainText(search_range.get(),
1307 webcore_string,
1308 true,
1309 options.matchCase));
1310 if (result_range->collapsed(ec)) {
1311 if (!result_range->startContainer()->isInShadowTree())
1312 break;
1313
1314 search_range = rangeOfContents(frame()->document());
1315 search_range->setStartAfter(
1316 result_range->startContainer()->shadowAncestorNode(), ec);
1317 continue;
1318 }
1319
1320 // A non-collapsed result range can in some funky whitespace cases still not
1321 // advance the range's start position (4509328). Break to avoid infinite
1322 // loop. (This function is based on the implementation of
1323 // Frame::markAllMatchesForText, which is where this safeguard comes from).
1324 VisiblePosition new_start = endVisiblePosition(result_range.get(),
1325 WebCore::DOWNSTREAM);
1326 if (new_start == startVisiblePosition(search_range.get(),
1327 WebCore::DOWNSTREAM))
1328 break;
1329
1330 // Only treat the result as a match if it is visible
1331 if (frame()->editor()->insideVisibleArea(result_range.get())) {
1332 ++match_count;
1333
1334 setStart(search_range.get(), new_start);
1335 Node* shadow_tree_root = search_range->shadowTreeRootNode();
1336 if (search_range->collapsed(ec) && shadow_tree_root)
1337 search_range->setEnd(shadow_tree_root,
1338 shadow_tree_root->childNodeCount(), ec);
1339
1340 // Catch a special case where Find found something but doesn't know what
1341 // the bounding box for it is. In this case we set the first match we find
1342 // as the active rect.
1343 IntRect result_bounds = result_range->boundingBox();
1344 IntRect active_selection_rect;
1345 if (locating_active_rect_) {
1346 active_selection_rect = active_match_.get() ?
1347 active_match_->boundingBox() : result_bounds;
1348 }
1349
1350 // If the Find function found a match it will have stored where the
1351 // match was found in active_selection_rect_ on the current frame. If we
1352 // find this rect during scoping it means we have found the active
1353 // tickmark.
1354 bool found_active_match = false;
1355 if (locating_active_rect_ && (active_selection_rect == result_bounds)) {
1356 // We have found the active tickmark frame.
1357 main_frame_impl->active_match_frame_ = this;
1358 found_active_match = true;
1359 // We also know which tickmark is active now.
1360 active_match_index_ = match_count - 1;
1361 // To stop looking for the active tickmark, we set this flag.
1362 locating_active_rect_ = false;
1363
1364 // Notify browser of new location for the selected rectangle.
1365 result_bounds.move(-frameview()->scrollOffset().width(),
1366 -frameview()->scrollOffset().height());
1367 ReportFindInPageSelection(
1368 webkit_glue::IntRectToWebRect(
1369 frame()->view()->convertToContainingWindow(result_bounds)),
1370 active_match_index_ + 1,
1371 request_id);
1372 }
1373
1374 AddMarker(result_range.get(), found_active_match);
1375 }
1376
1377 resume_scoping_from_range_ = result_range;
1378 timeout = (currentTime() - start_time) >= kTimeout;
1379 } while (!timeout);
1380
1381 // Remember what we search for last time, so we can skip searching if more
1382 // letters are added to the search string (and last outcome was 0).
1383 last_search_string_ = search_text;
1384
1385 if (match_count > 0) {
1386 frame()->setMarkedTextMatchesAreHighlighted(true);
1387
1388 last_match_count_ += match_count;
1389
1390 // Let the mainframe know how much we found during this pass.
1391 main_frame_impl->increaseMatchCount(match_count, request_id);
1392 }
1393
1394 if (timeout) {
1395 // If we found anything during this pass, we should redraw. However, we
1396 // don't want to spam too much if the page is extremely long, so if we
1397 // reach a certain point we start throttling the redraw requests.
1398 if (match_count > 0)
1399 InvalidateIfNecessary();
1400
1401 // Scoping effort ran out of time, lets ask for another time-slice.
1402 ScopeStringMatchesSoon(
1403 request_id,
1404 search_text,
1405 options,
1406 false); // don't reset.
1407 return; // Done for now, resume work later.
1408 }
1409
1410 // This frame has no further scoping left, so it is done. Other frames might,
1411 // of course, continue to scope matches.
1412 scoping_complete_ = true;
1413 main_frame_impl->frames_scoping_count_--;
1414
1415 // If this is the last frame to finish scoping we need to trigger the final
1416 // update to be sent.
1417 if (main_frame_impl->frames_scoping_count_ == 0)
1418 main_frame_impl->increaseMatchCount(0, request_id);
1419
1420 // This frame is done, so show any scrollbar tickmarks we haven't drawn yet.
1421 InvalidateArea(INVALIDATE_SCROLLBAR);
1422 }
1423
1424 void WebFrameImpl::cancelPendingScopingEffort() {
1425 deleteAllValues(deferred_scoping_work_);
1426 deferred_scoping_work_.clear();
1427
1428 active_match_index_ = -1;
1429 }
1430
1431 void WebFrameImpl::increaseMatchCount(int count, int request_id) {
1432 // This function should only be called on the mainframe.
1433 ASSERT(!parent());
1434
1435 total_matchcount_ += count;
1436
1437 // Update the UI with the latest findings.
1438 if (client()) {
1439 client()->reportFindInPageMatchCount(
1440 request_id, total_matchcount_, frames_scoping_count_ == 0);
1441 }
1442 }
1443
1444 void WebFrameImpl::ReportFindInPageSelection(const WebRect& selection_rect,
1445 int active_match_ordinal,
1446 int request_id) {
1447 // Update the UI with the latest selection rect.
1448 if (client()) {
1449 client()->reportFindInPageSelection(
1450 request_id, OrdinalOfFirstMatchForFrame(this) + active_match_ordinal,
1451 selection_rect);
1452 }
1453 }
1454
1455 void WebFrameImpl::resetMatchCount() {
1456 total_matchcount_ = 0;
1457 frames_scoping_count_ = 0;
1458 }
1459
1460 WebURL WebFrameImpl::completeURL(const WebString& url) const {
1461 if (!frame_ || !frame_->document())
1462 return WebURL();
1463
1464 return webkit_glue::KURLToWebURL(
1465 frame_->document()->completeURL(webkit_glue::WebStringToString(url)));
1466 }
1467
1468 WebString WebFrameImpl::contentAsText(size_t max_chars) const {
1469 if (!frame_)
1470 return WebString();
1471
1472 Vector<UChar> text;
1473 FrameContentAsPlainText(max_chars, frame_, &text);
1474 return webkit_glue::StringToWebString(String::adopt(text));
1475 }
1476
1477 WebString WebFrameImpl::contentAsMarkup() const {
1478 return webkit_glue::StringToWebString(createFullMarkup(frame_->document()));
1479 }
1480
1481 // WebFrameImpl public ---------------------------------------------------------
1482
1483 int WebFrameImpl::live_object_count_ = 0;
1484
1485 PassRefPtr<WebFrameImpl> WebFrameImpl::create(WebFrameClient* client) {
1486 return adoptRef(new WebFrameImpl(ClientHandle::create(client)));
1487 }
1488
1489 WebFrameImpl::WebFrameImpl(PassRefPtr<ClientHandle> client_handle)
1490 : ALLOW_THIS_IN_INITIALIZER_LIST(frame_loader_client_(this)),
1491 client_handle_(client_handle),
1492 active_match_frame_(NULL),
1493 active_match_index_(-1),
1494 locating_active_rect_(false),
1495 resume_scoping_from_range_(NULL),
1496 last_match_count_(-1),
1497 total_matchcount_(-1),
1498 frames_scoping_count_(-1),
1499 scoping_complete_(false),
1500 next_invalidate_after_(0) {
1501 ChromiumBridge::incrementStatsCounter(kWebFrameActiveCount);
1502 live_object_count_++;
1503 }
1504
1505 WebFrameImpl::~WebFrameImpl() {
1506 ChromiumBridge::decrementStatsCounter(kWebFrameActiveCount);
1507 live_object_count_--;
1508
1509 cancelPendingScopingEffort();
1510 ClearPasswordListeners();
1511 }
1512
1513 void WebFrameImpl::InitMainFrame(WebViewImpl* webview_impl) {
1514 RefPtr<Frame> frame =
1515 Frame::create(webview_impl->page(), 0, &frame_loader_client_);
1516 frame_ = frame.get();
1517
1518 // Add reference on behalf of FrameLoader. See comments in
1519 // WebFrameLoaderClient::frameLoaderDestroyed for more info.
1520 ref();
1521
1522 // We must call init() after frame_ is assigned because it is referenced
1523 // during init().
1524 frame_->init();
1525 }
1526
1527 PassRefPtr<Frame> WebFrameImpl::CreateChildFrame(
1528 const FrameLoadRequest& request, HTMLFrameOwnerElement* owner_element) {
1529 // TODO(darin): share code with initWithName()
1530
1531 RefPtr<WebFrameImpl> webframe(adoptRef(new WebFrameImpl(client_handle_)));
1532
1533 // Add an extra ref on behalf of the Frame/FrameLoader, which references the
1534 // WebFrame via the FrameLoaderClient interface. See the comment at the top
1535 // of this file for more info.
1536 webframe->ref();
1537
1538 RefPtr<Frame> child_frame = Frame::create(
1539 frame_->page(), owner_element, &webframe->frame_loader_client_);
1540 webframe->frame_ = child_frame.get();
1541
1542 child_frame->tree()->setName(request.frameName());
1543
1544 frame_->tree()->appendChild(child_frame);
1545
1546 // Frame::init() can trigger onload event in the parent frame,
1547 // which may detach this frame and trigger a null-pointer access
1548 // in FrameTree::removeChild. Move init() after appendChild call
1549 // so that webframe->frame_ is in the tree before triggering
1550 // onload event handler.
1551 // Because the event handler may set webframe->frame_ to null,
1552 // it is necessary to check the value after calling init() and
1553 // return without loading URL.
1554 // (b:791612)
1555 child_frame->init(); // create an empty document
1556 if (!child_frame->tree()->parent())
1557 return NULL;
1558
1559 frame_->loader()->loadURLIntoChildFrame(
1560 request.resourceRequest().url(),
1561 request.resourceRequest().httpReferrer(),
1562 child_frame.get());
1563
1564 // A synchronous navigation (about:blank) would have already processed
1565 // onload, so it is possible for the frame to have already been destroyed by
1566 // script in the page.
1567 if (!child_frame->tree()->parent())
1568 return NULL;
1569
1570 return child_frame.release();
1571 }
1572
1573 void WebFrameImpl::Layout() {
1574 // layout this frame
1575 FrameView* view = frame_->view();
1576 if (view)
1577 view->layoutIfNeededRecursive();
1578 }
1579
1580 void WebFrameImpl::Paint(WebCanvas* canvas, const WebRect& rect) {
1581 if (rect.isEmpty())
1582 return;
1583 IntRect dirty_rect(webkit_glue::WebRectToIntRect(rect));
1584 #if WEBKIT_USING_CG
1585 GraphicsContext gc(canvas);
1586 WebCore::LocalCurrentGraphicsContext localContext(&gc);
1587 #elif WEBKIT_USING_SKIA
1588 PlatformContextSkia context(canvas);
1589
1590 // PlatformGraphicsContext is actually a pointer to PlatformContextSkia
1591 GraphicsContext gc(reinterpret_cast<PlatformGraphicsContext*>(&context));
1592 #else
1593 notImplemented();
1594 #endif
1595 gc.save();
1596 if (frame_->document() && frameview()) {
1597 gc.clip(dirty_rect);
1598 frameview()->paint(&gc, dirty_rect);
1599 frame_->page()->inspectorController()->drawNodeHighlight(gc);
1600 } else {
1601 gc.fillRect(dirty_rect, Color::white);
1602 }
1603 gc.restore();
1604 }
1605
1606 void WebFrameImpl::CreateFrameView() {
1607 ASSERT(frame_); // If frame_ doesn't exist, we probably didn't init properly.
1608
1609 WebCore::Page* page = frame_->page();
1610 ASSERT(page);
1611
1612 ASSERT(page->mainFrame() != NULL);
1613
1614 bool is_main_frame = frame_ == page->mainFrame();
1615 if (is_main_frame && frame_->view())
1616 frame_->view()->setParentVisible(false);
1617
1618 frame_->setView(0);
1619
1620 WebViewImpl* web_view = GetWebViewImpl();
1621
1622 RefPtr<WebCore::FrameView> view;
1623 if (is_main_frame) {
1624 IntSize size = webkit_glue::WebSizeToIntSize(web_view->size());
1625 view = FrameView::create(frame_, size);
1626 } else {
1627 view = FrameView::create(frame_);
1628 }
1629
1630 frame_->setView(view);
1631
1632 if (web_view->isTransparent())
1633 view->setTransparent(true);
1634
1635 // TODO(darin): The Mac code has a comment about this possibly being
1636 // unnecessary. See installInFrame in WebCoreFrameBridge.mm
1637 if (frame_->ownerRenderer())
1638 frame_->ownerRenderer()->setWidget(view.get());
1639
1640 if (HTMLFrameOwnerElement* owner = frame_->ownerElement()) {
1641 view->setCanHaveScrollbars(
1642 owner->scrollingMode() != WebCore::ScrollbarAlwaysOff);
1643 }
1644
1645 if (is_main_frame)
1646 view->setParentVisible(true);
1647 }
1648
1649 // static
1650 WebFrameImpl* WebFrameImpl::FromFrame(WebCore::Frame* frame) {
1651 if (!frame)
1652 return NULL;
1653 return static_cast<WebFrameLoaderClient*>(
1654 frame->loader()->client())->webframe();
1655 }
1656
1657 WebViewImpl* WebFrameImpl::GetWebViewImpl() const {
1658 if (!frame_)
1659 return NULL;
1660
1661 return WebViewImpl::FromPage(frame_->page());
1662 }
1663
1664 WebDataSourceImpl* WebFrameImpl::GetDataSourceImpl() const {
1665 return static_cast<WebDataSourceImpl*>(dataSource());
1666 }
1667
1668 WebDataSourceImpl* WebFrameImpl::GetProvisionalDataSourceImpl() const {
1669 return static_cast<WebDataSourceImpl*>(provisionalDataSource());
1670 }
1671
1672 void WebFrameImpl::SetFindEndstateFocusAndSelection() {
1673 WebFrameImpl* main_frame_impl = GetWebViewImpl()->main_frame();
1674
1675 if (this == main_frame_impl->active_match_frame() &&
1676 active_match_.get()) {
1677 // If the user has set the selection since the match was found, we
1678 // don't focus anything.
1679 VisibleSelection selection(frame()->selection()->selection());
1680 if (!selection.isNone())
1681 return;
1682
1683 // Try to find the first focusable node up the chain, which will, for
1684 // example, focus links if we have found text within the link.
1685 Node* node = active_match_->firstNode();
1686 while (node && !node->isFocusable() && node != frame()->document())
1687 node = node->parent();
1688
1689 if (node && node != frame()->document()) {
1690 // Found a focusable parent node. Set focus to it.
1691 frame()->document()->setFocusedNode(node);
1692 } else {
1693 // Iterate over all the nodes in the range until we find a focusable node.
1694 // This, for example, sets focus to the first link if you search for
1695 // text and text that is within one or more links.
1696 node = active_match_->firstNode();
1697 while (node && node != active_match_->pastLastNode()) {
1698 if (node->isFocusable()) {
1699 frame()->document()->setFocusedNode(node);
1700 break;
1701 }
1702 node = node->traverseNextNode();
1703 }
1704 }
1705 }
1706 }
1707
1708 void WebFrameImpl::DidFail(const ResourceError& error, bool was_provisional) {
1709 if (!client())
1710 return;
1711 const WebURLError& web_error =
1712 webkit_glue::ResourceErrorToWebURLError(error);
1713 if (was_provisional) {
1714 client()->didFailProvisionalLoad(this, web_error);
1715 } else {
1716 client()->didFailLoad(this, web_error);
1717 }
1718 }
1719
1720 void WebFrameImpl::SetAllowsScrolling(bool flag) {
1721 frame_->view()->setCanHaveScrollbars(flag);
1722 }
1723
1724 void WebFrameImpl::RegisterPasswordListener(
1725 PassRefPtr<HTMLInputElement> input_element,
1726 PasswordAutocompleteListener* listener) {
1727 RefPtr<HTMLInputElement> element = input_element;
1728 ASSERT(password_listeners_.find(element) == password_listeners_.end());
1729 password_listeners_.set(element, listener);
1730 }
1731
1732 PasswordAutocompleteListener* WebFrameImpl::GetPasswordListener(
1733 HTMLInputElement* input_element) {
1734 return password_listeners_.get(RefPtr<HTMLInputElement>(input_element));
1735 }
1736
1737 // WebFrameImpl protected ------------------------------------------------------
1738
1739 void WebFrameImpl::Closing() {
1740 frame_ = NULL;
1741 }
1742
1743 // WebFrameImpl private --------------------------------------------------------
1744
1745 void WebFrameImpl::InvalidateArea(AreaToInvalidate area) {
1746 ASSERT(frame() && frame()->view());
1747 FrameView* view = frame()->view();
1748
1749 if ((area & INVALIDATE_ALL) == INVALIDATE_ALL) {
1750 view->invalidateRect(view->frameRect());
1751 } else {
1752 if ((area & INVALIDATE_CONTENT_AREA) == INVALIDATE_CONTENT_AREA) {
1753 IntRect content_area(
1754 view->x(), view->y(), view->visibleWidth(), view->visibleHeight());
1755 view->invalidateRect(content_area);
1756 }
1757
1758 if ((area & INVALIDATE_SCROLLBAR) == INVALIDATE_SCROLLBAR) {
1759 // Invalidate the vertical scroll bar region for the view.
1760 IntRect scroll_bar_vert(
1761 view->x() + view->visibleWidth(), view->y(),
1762 WebCore::ScrollbarTheme::nativeTheme()->scrollbarThickness(),
1763 view->visibleHeight());
1764 view->invalidateRect(scroll_bar_vert);
1765 }
1766 }
1767 }
1768
1769 void WebFrameImpl::AddMarker(WebCore::Range* range, bool active_match) {
1770 // Use a TextIterator to visit the potentially multiple nodes the range
1771 // covers.
1772 TextIterator markedText(range);
1773 for (; !markedText.atEnd(); markedText.advance()) {
1774 RefPtr<Range> textPiece = markedText.range();
1775 int exception = 0;
1776
1777 WebCore::DocumentMarker marker = {
1778 WebCore::DocumentMarker::TextMatch,
1779 textPiece->startOffset(exception),
1780 textPiece->endOffset(exception),
1781 "",
1782 active_match };
1783
1784 if (marker.endOffset > marker.startOffset) {
1785 // Find the node to add a marker to and add it.
1786 Node* node = textPiece->startContainer(exception);
1787 frame()->document()->addMarker(node, marker);
1788
1789 // Rendered rects for markers in WebKit are not populated until each time
1790 // the markers are painted. However, we need it to happen sooner, because
1791 // the whole purpose of tickmarks on the scrollbar is to show where
1792 // matches off-screen are (that haven't been painted yet).
1793 Vector<WebCore::DocumentMarker> markers =
1794 frame()->document()->markersForNode(node);
1795 frame()->document()->setRenderedRectForMarker(
1796 textPiece->startContainer(exception),
1797 markers[markers.size() - 1],
1798 range->boundingBox());
1799 }
1800 }
1801 }
1802
1803 void WebFrameImpl::SetMarkerActive(WebCore::Range* range, bool active) {
1804 if (!range)
1805 return;
1806
1807 frame()->document()->setMarkersActive(range, active);
1808 }
1809
1810 int WebFrameImpl::OrdinalOfFirstMatchForFrame(WebFrameImpl* frame) const {
1811 int ordinal = 0;
1812 WebFrameImpl* main_frame_impl = GetWebViewImpl()->main_frame();
1813 // Iterate from the main frame up to (but not including) |frame| and
1814 // add up the number of matches found so far.
1815 for (WebFrameImpl* it = main_frame_impl;
1816 it != frame;
1817 it = static_cast<WebFrameImpl*>(it->traverseNext(true))) {
1818 if (it->last_match_count_ > 0)
1819 ordinal += it->last_match_count_;
1820 }
1821
1822 return ordinal;
1823 }
1824
1825 bool WebFrameImpl::ShouldScopeMatches(const string16& search_text) {
1826 // Don't scope if we can't find a frame or if the frame is not visible.
1827 // The user may have closed the tab/application, so abort.
1828 if (!frame() || !hasVisibleContent())
1829 return false;
1830
1831 ASSERT(frame()->document() && frame()->view());
1832
1833 // If the frame completed the scoping operation and found 0 matches the last
1834 // time it was searched, then we don't have to search it again if the user is
1835 // just adding to the search string or sending the same search string again.
1836 if (scoping_complete_ &&
1837 !last_search_string_.empty() && last_match_count_ == 0) {
1838 // Check to see if the search string prefixes match.
1839 string16 previous_search_prefix =
1840 search_text.substr(0, last_search_string_.length());
1841
1842 if (previous_search_prefix == last_search_string_) {
1843 return false; // Don't search this frame, it will be fruitless.
1844 }
1845 }
1846
1847 return true;
1848 }
1849
1850 void WebFrameImpl::ScopeStringMatchesSoon(
1851 int identifier, const WebString& search_text,
1852 const WebFindOptions& options, bool reset) {
1853 deferred_scoping_work_.append(new DeferredScopeStringMatches(
1854 this, identifier, search_text, options, reset));
1855 }
1856
1857 void WebFrameImpl::CallScopeStringMatches(
1858 DeferredScopeStringMatches* caller, int identifier,
1859 const WebString& search_text, const WebFindOptions& options, bool reset) {
1860 deferred_scoping_work_.remove(deferred_scoping_work_.find(caller));
1861
1862 scopeStringMatches(identifier, search_text, options, reset);
1863
1864 // This needs to happen last since search_text is passed by reference.
1865 delete caller;
1866 }
1867
1868 void WebFrameImpl::InvalidateIfNecessary() {
1869 if (last_match_count_ > next_invalidate_after_) {
1870 // TODO(finnur): (http://b/1088165) Optimize the drawing of the
1871 // tickmarks and remove this. This calculation sets a milestone for when
1872 // next to invalidate the scrollbar and the content area. We do this so that
1873 // we don't spend too much time drawing the scrollbar over and over again.
1874 // Basically, up until the first 500 matches there is no throttle. After the
1875 // first 500 matches, we set set the milestone further and further out (750,
1876 // 1125, 1688, 2K, 3K).
1877 static const int start_slowing_down_after = 500;
1878 static const int slowdown = 750;
1879 int i = (last_match_count_ / start_slowing_down_after);
1880 next_invalidate_after_ += i * slowdown;
1881
1882 InvalidateArea(INVALIDATE_SCROLLBAR);
1883 }
1884 }
1885
1886 void WebFrameImpl::ClearPasswordListeners() {
1887 for (PasswordListenerMap::iterator iter = password_listeners_.begin();
1888 iter != password_listeners_.end(); ++iter) {
1889 delete iter->second;
1890 }
1891 password_listeners_.clear();
1892 }
1893
1894 void WebFrameImpl::LoadJavaScriptURL(const KURL& url) {
1895 // This is copied from FrameLoader::executeIfJavaScriptURL. Unfortunately,
1896 // we cannot just use that method since it is private, and it also doesn't
1897 // quite behave as we require it to for bookmarklets. The key difference is
1898 // that we need to suppress loading the string result from evaluating the JS
1899 // URL if executing the JS URL resulted in a location change. We also allow
1900 // a JS URL to be loaded even if scripts on the page are otherwise disabled.
1901
1902 if (!frame_->document() || !frame_->page())
1903 return;
1904
1905 String script =
1906 decodeURLEscapeSequences(url.string().substring(strlen("javascript:")));
1907 ScriptValue result = frame_->script()->executeScript(script, true);
1908
1909 String script_result;
1910 if (!result.getString(script_result))
1911 return;
1912
1913 SecurityOrigin* security_origin = frame_->document()->securityOrigin();
1914
1915 if (!frame_->redirectScheduler()->locationChangePending()) {
1916 frame_->loader()->stopAllLoaders();
1917 frame_->loader()->begin(frame_->loader()->url(), true, security_origin);
1918 frame_->loader()->write(script_result);
1919 frame_->loader()->end();
1920 }
1921 }
OLDNEW
« no previous file with comments | « webkit/glue/webframe_impl.h ('k') | webkit/glue/webframeloaderclient_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698