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