1 /*
2 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3 * 1999 Lars Knoll <knoll@kde.org>
4 * 1999 Antti Koivisto <koivisto@kde.org>
5 * 2000 Simon Hausmann <hausmann@kde.org>
6 * 2000 Stefan Schimanski <1Stein@gmx.de>
7 * 2001 George Staikos <staikos@kde.org>
8 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
9 * Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com>
10 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
11 * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Library General Public License for more details.
22 *
23 * You should have received a copy of the GNU Library General Public License
24 * along with this library; see the file COPYING.LIB. If not, write to
25 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26 * Boston, MA 02110-1301, USA.
27 */
28
29 #include "config.h"
30 #include "Frame.h"
31
32 #include "ApplyStyleCommand.h"
33 #include "CSSComputedStyleDeclaration.h"
34 #include "CSSMutableStyleDeclaration.h"
35 #include "CSSProperty.h"
36 #include "CSSPropertyNames.h"
37 #include "CachedCSSStyleSheet.h"
38 #include "Chrome.h"
39 #include "ChromeClient.h"
40 #include "DOMWindow.h"
41 #include "CachedResourceLoader.h"
42 #include "DocumentType.h"
43 #include "EditingText.h"
44 #include "EditorClient.h"
45 #include "EventNames.h"
46 #include "FloatQuad.h"
47 #include "FocusController.h"
48 #include "FrameLoader.h"
49 #include "FrameLoaderClient.h"
50 #include "FrameView.h"
51 #include "GraphicsContext.h"
52 #include "GraphicsLayer.h"
53 #include "HTMLDocument.h"
54 #include "HTMLFormControlElement.h"
55 #include "HTMLFormElement.h"
56 #include "HTMLFrameElementBase.h"
57 #include "HTMLNames.h"
58 #include "HTMLTableCellElement.h"
59 #include "HitTestResult.h"
60 #include "Logging.h"
61 #include "MediaFeatureNames.h"
62 #include "Navigator.h"
63 #include "NodeList.h"
64 #include "Page.h"
65 #include "PageGroup.h"
66 #include "RegularExpression.h"
67 #include "RenderLayer.h"
68 #include "RenderPart.h"
69 #include "RenderTableCell.h"
70 #include "RenderTextControl.h"
71 #include "RenderTheme.h"
72 #include "RenderView.h"
73 #include "ScriptController.h"
74 #include "ScriptSourceCode.h"
75 #include "ScriptValue.h"
76 #include "Settings.h"
77 #include "TextIterator.h"
78 #include "TextResourceDecoder.h"
79 #include "UserContentURLPattern.h"
80 #include "UserTypingGestureIndicator.h"
81 #include "XMLNSNames.h"
82 #include "XMLNames.h"
83 #include "htmlediting.h"
84 #include "markup.h"
85 #include "npruntime_impl.h"
86 #include "visible_units.h"
87 #include <wtf/RefCountedLeakCounter.h>
88 #include <wtf/StdLibExtras.h>
89
90 #if USE(ACCELERATED_COMPOSITING)
91 #include "RenderLayerCompositor.h"
92 #endif
93
94 #if USE(JSC)
95 #include "JSDOMWindowShell.h"
96 #include "runtime_root.h"
97 #endif
98
99 #include "MathMLNames.h"
100 #include "SVGNames.h"
101 #include "XLinkNames.h"
102
103 #if ENABLE(SVG)
104 #include "SVGDocument.h"
105 #include "SVGDocumentExtensions.h"
106 #endif
107
108 #if ENABLE(TILED_BACKING_STORE)
109 #include "TiledBackingStore.h"
110 #endif
111
112 #if ENABLE(WML)
113 #include "WMLNames.h"
114 #endif
115
116 #if PLATFORM(ANDROID)
117 #include "WebViewCore.h"
118 #endif
119
120 using namespace std;
121
122 namespace WebCore {
123
124 using namespace HTMLNames;
125
126 #ifndef NDEBUG
127 static WTF::RefCountedLeakCounter frameCounter("Frame");
128 #endif
129
parentFromOwnerElement(HTMLFrameOwnerElement * ownerElement)130 static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement)
131 {
132 if (!ownerElement)
133 return 0;
134 return ownerElement->document()->frame();
135 }
136
parentPageZoomFactor(Frame * frame)137 static inline float parentPageZoomFactor(Frame* frame)
138 {
139 Frame* parent = frame->tree()->parent();
140 if (!parent)
141 return 1;
142 return parent->pageZoomFactor();
143 }
144
parentTextZoomFactor(Frame * frame)145 static inline float parentTextZoomFactor(Frame* frame)
146 {
147 Frame* parent = frame->tree()->parent();
148 if (!parent)
149 return 1;
150 return parent->textZoomFactor();
151 }
152
Frame(Page * page,HTMLFrameOwnerElement * ownerElement,FrameLoaderClient * frameLoaderClient)153 inline Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient)
154 : m_page(page)
155 , m_treeNode(this, parentFromOwnerElement(ownerElement))
156 , m_loader(this, frameLoaderClient)
157 , m_navigationScheduler(this)
158 , m_ownerElement(ownerElement)
159 , m_script(this)
160 , m_editor(this)
161 , m_selectionController(this)
162 , m_eventHandler(this)
163 , m_animationController(this)
164 , m_lifeSupportTimer(this, &Frame::lifeSupportTimerFired)
165 , m_pageZoomFactor(parentPageZoomFactor(this))
166 , m_textZoomFactor(parentTextZoomFactor(this))
167 , m_pageScaleFactor(1)
168 #if ENABLE(ORIENTATION_EVENTS)
169 , m_orientation(0)
170 #endif
171 , m_inViewSourceMode(false)
172 , m_isDisconnected(false)
173 , m_excludeFromTextSearch(false)
174 #if PLATFORM(ANDROID)
175 // Temporary hack for http://b/5188895
176 , m_isDocumentUpToDate(true)
177 #endif
178 {
179 ASSERT(page);
180 AtomicString::init();
181 HTMLNames::init();
182 QualifiedName::init();
183 MediaFeatureNames::init();
184 SVGNames::init();
185 XLinkNames::init();
186 MathMLNames::init();
187 XMLNSNames::init();
188 XMLNames::init();
189
190 #if ENABLE(WML)
191 WMLNames::init();
192 #endif
193
194 if (!ownerElement) {
195 #if ENABLE(TILED_BACKING_STORE)
196 // Top level frame only for now.
197 setTiledBackingStoreEnabled(page->settings()->tiledBackingStoreEnabled());
198 #endif
199 } else {
200 page->incrementFrameCount();
201
202 // Make sure we will not end up with two frames referencing the same owner element.
203 Frame*& contentFrameSlot = ownerElement->m_contentFrame;
204 ASSERT(!contentFrameSlot || contentFrameSlot->ownerElement() != ownerElement);
205 contentFrameSlot = this;
206 }
207
208 #ifndef NDEBUG
209 frameCounter.increment();
210 #endif
211 }
212
create(Page * page,HTMLFrameOwnerElement * ownerElement,FrameLoaderClient * client)213 PassRefPtr<Frame> Frame::create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client)
214 {
215 RefPtr<Frame> frame = adoptRef(new Frame(page, ownerElement, client));
216 if (!ownerElement)
217 page->setMainFrame(frame);
218 return frame.release();
219 }
220
~Frame()221 Frame::~Frame()
222 {
223 setView(0);
224 loader()->cancelAndClear();
225
226 // FIXME: We should not be doing all this work inside the destructor
227
228 ASSERT(!m_lifeSupportTimer.isActive());
229
230 #ifndef NDEBUG
231 frameCounter.decrement();
232 #endif
233
234 disconnectOwnerElement();
235
236 if (m_domWindow)
237 m_domWindow->disconnectFrame();
238 script()->clearWindowShell();
239
240 HashSet<DOMWindow*>::iterator end = m_liveFormerWindows.end();
241 for (HashSet<DOMWindow*>::iterator it = m_liveFormerWindows.begin(); it != end; ++it)
242 (*it)->disconnectFrame();
243
244 HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end();
245 for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it)
246 (*it)->frameDestroyed();
247
248 if (m_view) {
249 m_view->hide();
250 m_view->clearFrame();
251 }
252
253 ASSERT(!m_lifeSupportTimer.isActive());
254 }
255
addDestructionObserver(FrameDestructionObserver * observer)256 void Frame::addDestructionObserver(FrameDestructionObserver* observer)
257 {
258 m_destructionObservers.add(observer);
259 }
260
removeDestructionObserver(FrameDestructionObserver * observer)261 void Frame::removeDestructionObserver(FrameDestructionObserver* observer)
262 {
263 m_destructionObservers.remove(observer);
264 }
265
setView(PassRefPtr<FrameView> view)266 void Frame::setView(PassRefPtr<FrameView> view)
267 {
268 // We the custom scroll bars as early as possible to prevent m_doc->detach()
269 // from messing with the view such that its scroll bars won't be torn down.
270 // FIXME: We should revisit this.
271 if (m_view)
272 m_view->detachCustomScrollbars();
273
274 // Detach the document now, so any onUnload handlers get run - if
275 // we wait until the view is destroyed, then things won't be
276 // hooked up enough for some JavaScript calls to work.
277 if (!view && m_doc && m_doc->attached() && !m_doc->inPageCache()) {
278 // FIXME: We don't call willRemove here. Why is that OK?
279 m_doc->detach();
280 }
281
282 if (m_view)
283 m_view->unscheduleRelayout();
284
285 eventHandler()->clear();
286
287 m_view = view;
288
289 // Only one form submission is allowed per view of a part.
290 // Since this part may be getting reused as a result of being
291 // pulled from the back/forward cache, reset this flag.
292 loader()->resetMultipleFormSubmissionProtection();
293
294 #if ENABLE(TILED_BACKING_STORE)
295 if (m_view && tiledBackingStore())
296 m_view->setPaintsEntireContents(true);
297 #endif
298 }
299
setDocument(PassRefPtr<Document> newDoc)300 void Frame::setDocument(PassRefPtr<Document> newDoc)
301 {
302 ASSERT(!newDoc || newDoc->frame());
303 if (m_doc && m_doc->attached() && !m_doc->inPageCache()) {
304 // FIXME: We don't call willRemove here. Why is that OK?
305 m_doc->detach();
306 }
307
308 m_doc = newDoc;
309 #if PLATFORM(ANDROID)
310 // Temporary hack for http://b/5188895
311 m_isDocumentUpToDate = true;
312 #endif
313 selection()->updateSecureKeyboardEntryIfActive();
314
315 if (m_doc && !m_doc->attached())
316 m_doc->attach();
317
318 // Update the cached 'document' property, which is now stale.
319 m_script.updateDocument();
320
321 if (m_page)
322 m_page->updateViewportArguments();
323 }
324
325 #if ENABLE(ORIENTATION_EVENTS)
sendOrientationChangeEvent(int orientation)326 void Frame::sendOrientationChangeEvent(int orientation)
327 {
328 m_orientation = orientation;
329 if (Document* doc = document())
330 doc->dispatchWindowEvent(Event::create(eventNames().orientationchangeEvent, false, false));
331 }
332 #endif // ENABLE(ORIENTATION_EVENTS)
333
settings() const334 Settings* Frame::settings() const
335 {
336 return m_page ? m_page->settings() : 0;
337 }
338
createRegExpForLabels(const Vector<String> & labels)339 static RegularExpression* createRegExpForLabels(const Vector<String>& labels)
340 {
341 // REVIEW- version of this call in FrameMac.mm caches based on the NSArray ptrs being
342 // the same across calls. We can't do that.
343
344 DEFINE_STATIC_LOCAL(RegularExpression, wordRegExp, ("\\w", TextCaseSensitive));
345 String pattern("(");
346 unsigned int numLabels = labels.size();
347 unsigned int i;
348 for (i = 0; i < numLabels; i++) {
349 String label = labels[i];
350
351 bool startsWithWordChar = false;
352 bool endsWithWordChar = false;
353 if (label.length()) {
354 startsWithWordChar = wordRegExp.match(label.substring(0, 1)) >= 0;
355 endsWithWordChar = wordRegExp.match(label.substring(label.length() - 1, 1)) >= 0;
356 }
357
358 if (i)
359 pattern.append("|");
360 // Search for word boundaries only if label starts/ends with "word characters".
361 // If we always searched for word boundaries, this wouldn't work for languages
362 // such as Japanese.
363 if (startsWithWordChar)
364 pattern.append("\\b");
365 pattern.append(label);
366 if (endsWithWordChar)
367 pattern.append("\\b");
368 }
369 pattern.append(")");
370 return new RegularExpression(pattern, TextCaseInsensitive);
371 }
372
searchForLabelsAboveCell(RegularExpression * regExp,HTMLTableCellElement * cell,size_t * resultDistanceFromStartOfCell)373 String Frame::searchForLabelsAboveCell(RegularExpression* regExp, HTMLTableCellElement* cell, size_t* resultDistanceFromStartOfCell)
374 {
375 HTMLTableCellElement* aboveCell = cell->cellAbove();
376 if (aboveCell) {
377 // search within the above cell we found for a match
378 size_t lengthSearched = 0;
379 for (Node* n = aboveCell->firstChild(); n; n = n->traverseNextNode(aboveCell)) {
380 if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
381 // For each text chunk, run the regexp
382 String nodeString = n->nodeValue();
383 int pos = regExp->searchRev(nodeString);
384 if (pos >= 0) {
385 if (resultDistanceFromStartOfCell)
386 *resultDistanceFromStartOfCell = lengthSearched;
387 return nodeString.substring(pos, regExp->matchedLength());
388 }
389 lengthSearched += nodeString.length();
390 }
391 }
392 }
393
394 // Any reason in practice to search all cells in that are above cell?
395 if (resultDistanceFromStartOfCell)
396 *resultDistanceFromStartOfCell = notFound;
397 return String();
398 }
399
searchForLabelsBeforeElement(const Vector<String> & labels,Element * element,size_t * resultDistance,bool * resultIsInCellAbove)400 String Frame::searchForLabelsBeforeElement(const Vector<String>& labels, Element* element, size_t* resultDistance, bool* resultIsInCellAbove)
401 {
402 OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
403 // We stop searching after we've seen this many chars
404 const unsigned int charsSearchedThreshold = 500;
405 // This is the absolute max we search. We allow a little more slop than
406 // charsSearchedThreshold, to make it more likely that we'll search whole nodes.
407 const unsigned int maxCharsSearched = 600;
408 // If the starting element is within a table, the cell that contains it
409 HTMLTableCellElement* startingTableCell = 0;
410 bool searchedCellAbove = false;
411
412 if (resultDistance)
413 *resultDistance = notFound;
414 if (resultIsInCellAbove)
415 *resultIsInCellAbove = false;
416
417 // walk backwards in the node tree, until another element, or form, or end of tree
418 int unsigned lengthSearched = 0;
419 Node* n;
420 for (n = element->traversePreviousNode();
421 n && lengthSearched < charsSearchedThreshold;
422 n = n->traversePreviousNode())
423 {
424 if (n->hasTagName(formTag)
425 || (n->isHTMLElement() && static_cast<Element*>(n)->isFormControlElement()))
426 {
427 // We hit another form element or the start of the form - bail out
428 break;
429 } else if (n->hasTagName(tdTag) && !startingTableCell) {
430 startingTableCell = static_cast<HTMLTableCellElement*>(n);
431 } else if (n->hasTagName(trTag) && startingTableCell) {
432 String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
433 if (!result.isEmpty()) {
434 if (resultIsInCellAbove)
435 *resultIsInCellAbove = true;
436 return result;
437 }
438 searchedCellAbove = true;
439 } else if (n->isTextNode() && n->renderer() && n->renderer()->style()->visibility() == VISIBLE) {
440 // For each text chunk, run the regexp
441 String nodeString = n->nodeValue();
442 // add 100 for slop, to make it more likely that we'll search whole nodes
443 if (lengthSearched + nodeString.length() > maxCharsSearched)
444 nodeString = nodeString.right(charsSearchedThreshold - lengthSearched);
445 int pos = regExp->searchRev(nodeString);
446 if (pos >= 0) {
447 if (resultDistance)
448 *resultDistance = lengthSearched;
449 return nodeString.substring(pos, regExp->matchedLength());
450 }
451 lengthSearched += nodeString.length();
452 }
453 }
454
455 // If we started in a cell, but bailed because we found the start of the form or the
456 // previous element, we still might need to search the row above us for a label.
457 if (startingTableCell && !searchedCellAbove) {
458 String result = searchForLabelsAboveCell(regExp.get(), startingTableCell, resultDistance);
459 if (!result.isEmpty()) {
460 if (resultIsInCellAbove)
461 *resultIsInCellAbove = true;
462 return result;
463 }
464 }
465 return String();
466 }
467
matchLabelsAgainstString(const Vector<String> & labels,const String & stringToMatch)468 static String matchLabelsAgainstString(const Vector<String>& labels, const String& stringToMatch)
469 {
470 if (stringToMatch.isEmpty())
471 return String();
472
473 String mutableStringToMatch = stringToMatch;
474
475 // Make numbers and _'s in field names behave like word boundaries, e.g., "address2"
476 replace(mutableStringToMatch, RegularExpression("\\d", TextCaseSensitive), " ");
477 mutableStringToMatch.replace('_', ' ');
478
479 OwnPtr<RegularExpression> regExp(createRegExpForLabels(labels));
480 // Use the largest match we can find in the whole string
481 int pos;
482 int length;
483 int bestPos = -1;
484 int bestLength = -1;
485 int start = 0;
486 do {
487 pos = regExp->match(mutableStringToMatch, start);
488 if (pos != -1) {
489 length = regExp->matchedLength();
490 if (length >= bestLength) {
491 bestPos = pos;
492 bestLength = length;
493 }
494 start = pos + 1;
495 }
496 } while (pos != -1);
497
498 if (bestPos != -1)
499 return mutableStringToMatch.substring(bestPos, bestLength);
500 return String();
501 }
502
matchLabelsAgainstElement(const Vector<String> & labels,Element * element)503 String Frame::matchLabelsAgainstElement(const Vector<String>& labels, Element* element)
504 {
505 // Match against the name element, then against the id element if no match is found for the name element.
506 // See 7538330 for one popular site that benefits from the id element check.
507 // FIXME: This code is mirrored in FrameMac.mm. It would be nice to make the Mac code call the platform-agnostic
508 // code, which would require converting the NSArray of NSStrings to a Vector of Strings somewhere along the way.
509 String resultFromNameAttribute = matchLabelsAgainstString(labels, element->getAttribute(nameAttr));
510 if (!resultFromNameAttribute.isEmpty())
511 return resultFromNameAttribute;
512
513 return matchLabelsAgainstString(labels, element->getAttribute(idAttr));
514 }
515
setPrinting(bool printing,const FloatSize & pageSize,float maximumShrinkRatio,AdjustViewSizeOrNot shouldAdjustViewSize)516 void Frame::setPrinting(bool printing, const FloatSize& pageSize, float maximumShrinkRatio, AdjustViewSizeOrNot shouldAdjustViewSize)
517 {
518 m_doc->setPrinting(printing);
519 view()->adjustMediaTypeForPrinting(printing);
520
521 m_doc->styleSelectorChanged(RecalcStyleImmediately);
522 view()->forceLayoutForPagination(pageSize, maximumShrinkRatio, shouldAdjustViewSize);
523
524 // Subframes of the one we're printing don't lay out to the page size.
525 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
526 child->setPrinting(printing, IntSize(), 0, shouldAdjustViewSize);
527 }
528
injectUserScripts(UserScriptInjectionTime injectionTime)529 void Frame::injectUserScripts(UserScriptInjectionTime injectionTime)
530 {
531 if (!m_page)
532 return;
533
534 if (loader()->stateMachine()->creatingInitialEmptyDocument() && !settings()->shouldInjectUserScriptsInInitialEmptyDocument())
535 return;
536
537 // Walk the hashtable. Inject by world.
538 const UserScriptMap* userScripts = m_page->group().userScripts();
539 if (!userScripts)
540 return;
541 UserScriptMap::const_iterator end = userScripts->end();
542 for (UserScriptMap::const_iterator it = userScripts->begin(); it != end; ++it)
543 injectUserScriptsForWorld(it->first.get(), *it->second, injectionTime);
544 }
545
injectUserScriptsForWorld(DOMWrapperWorld * world,const UserScriptVector & userScripts,UserScriptInjectionTime injectionTime)546 void Frame::injectUserScriptsForWorld(DOMWrapperWorld* world, const UserScriptVector& userScripts, UserScriptInjectionTime injectionTime)
547 {
548 if (userScripts.isEmpty())
549 return;
550
551 Document* doc = document();
552 if (!doc)
553 return;
554
555 Vector<ScriptSourceCode> sourceCode;
556 unsigned count = userScripts.size();
557 for (unsigned i = 0; i < count; ++i) {
558 UserScript* script = userScripts[i].get();
559 if (script->injectedFrames() == InjectInTopFrameOnly && ownerElement())
560 continue;
561
562 if (script->injectionTime() == injectionTime && UserContentURLPattern::matchesPatterns(doc->url(), script->whitelist(), script->blacklist()))
563 m_script.evaluateInWorld(ScriptSourceCode(script->source(), script->url()), world);
564 }
565 }
566
567 #ifndef NDEBUG
keepAliveSet()568 static HashSet<Frame*>& keepAliveSet()
569 {
570 DEFINE_STATIC_LOCAL(HashSet<Frame*>, staticKeepAliveSet, ());
571 return staticKeepAliveSet;
572 }
573 #endif
574
keepAlive()575 void Frame::keepAlive()
576 {
577 if (m_lifeSupportTimer.isActive())
578 return;
579 #ifndef NDEBUG
580 keepAliveSet().add(this);
581 #endif
582 ref();
583 m_lifeSupportTimer.startOneShot(0);
584 }
585
586 #ifndef NDEBUG
cancelAllKeepAlive()587 void Frame::cancelAllKeepAlive()
588 {
589 HashSet<Frame*>::iterator end = keepAliveSet().end();
590 for (HashSet<Frame*>::iterator it = keepAliveSet().begin(); it != end; ++it) {
591 Frame* frame = *it;
592 frame->m_lifeSupportTimer.stop();
593 frame->deref();
594 }
595 keepAliveSet().clear();
596 }
597 #endif
598
lifeSupportTimerFired(Timer<Frame> *)599 void Frame::lifeSupportTimerFired(Timer<Frame>*)
600 {
601 #ifndef NDEBUG
602 keepAliveSet().remove(this);
603 #endif
604 deref();
605 }
606
clearDOMWindow()607 void Frame::clearDOMWindow()
608 {
609 if (m_domWindow) {
610 m_liveFormerWindows.add(m_domWindow.get());
611 m_domWindow->clear();
612 }
613 m_domWindow = 0;
614 }
615
contentRenderer() const616 RenderView* Frame::contentRenderer() const
617 {
618 Document* doc = document();
619 if (!doc)
620 return 0;
621 RenderObject* object = doc->renderer();
622 if (!object)
623 return 0;
624 ASSERT(object->isRenderView());
625 return toRenderView(object);
626 }
627
ownerRenderer() const628 RenderPart* Frame::ownerRenderer() const
629 {
630 HTMLFrameOwnerElement* ownerElement = m_ownerElement;
631 if (!ownerElement)
632 return 0;
633 RenderObject* object = ownerElement->renderer();
634 if (!object)
635 return 0;
636 // FIXME: If <object> is ever fixed to disassociate itself from frames
637 // that it has started but canceled, then this can turn into an ASSERT
638 // since m_ownerElement would be 0 when the load is canceled.
639 // https://bugs.webkit.org/show_bug.cgi?id=18585
640 if (!object->isRenderPart())
641 return 0;
642 return toRenderPart(object);
643 }
644
frameForWidget(const Widget * widget)645 Frame* Frame::frameForWidget(const Widget* widget)
646 {
647 ASSERT_ARG(widget, widget);
648
649 if (RenderWidget* renderer = RenderWidget::find(widget))
650 if (Node* node = renderer->node())
651 return node->document()->frame();
652
653 // Assume all widgets are either a FrameView or owned by a RenderWidget.
654 // FIXME: That assumption is not right for scroll bars!
655 ASSERT(widget->isFrameView());
656 return static_cast<const FrameView*>(widget)->frame();
657 }
658
clearTimers(FrameView * view,Document * document)659 void Frame::clearTimers(FrameView *view, Document *document)
660 {
661 if (view) {
662 view->unscheduleRelayout();
663 if (view->frame()) {
664 view->frame()->animation()->suspendAnimationsForDocument(document);
665 view->frame()->eventHandler()->stopAutoscrollTimer();
666 }
667 }
668 }
669
clearTimers()670 void Frame::clearTimers()
671 {
672 clearTimers(m_view.get(), document());
673 }
674
setDOMWindow(DOMWindow * domWindow)675 void Frame::setDOMWindow(DOMWindow* domWindow)
676 {
677 if (m_domWindow) {
678 m_liveFormerWindows.add(m_domWindow.get());
679 m_domWindow->clear();
680 }
681 m_domWindow = domWindow;
682 }
683
domWindow() const684 DOMWindow* Frame::domWindow() const
685 {
686 if (!m_domWindow)
687 m_domWindow = DOMWindow::create(const_cast<Frame*>(this));
688
689 return m_domWindow.get();
690 }
691
clearFormerDOMWindow(DOMWindow * window)692 void Frame::clearFormerDOMWindow(DOMWindow* window)
693 {
694 m_liveFormerWindows.remove(window);
695 }
696
pageDestroyed()697 void Frame::pageDestroyed()
698 {
699 if (Frame* parent = tree()->parent())
700 parent->loader()->checkLoadComplete();
701
702 if (m_domWindow) {
703 m_domWindow->resetGeolocation();
704 m_domWindow->pageDestroyed();
705 }
706
707 // FIXME: It's unclear as to why this is called more than once, but it is,
708 // so page() could be NULL.
709 if (page() && page()->focusController()->focusedFrame() == this)
710 page()->focusController()->setFocusedFrame(0);
711
712 script()->clearWindowShell();
713 script()->clearScriptObjects();
714 script()->updatePlatformScriptObjects();
715
716 detachFromPage();
717 }
718
disconnectOwnerElement()719 void Frame::disconnectOwnerElement()
720 {
721 if (m_ownerElement) {
722 if (Document* doc = document())
723 doc->clearAXObjectCache();
724 m_ownerElement->m_contentFrame = 0;
725 if (m_page)
726 m_page->decrementFrameCount();
727 }
728 m_ownerElement = 0;
729 }
730
731 // The frame is moved in DOM, potentially to another page.
transferChildFrameToNewDocument()732 void Frame::transferChildFrameToNewDocument()
733 {
734 ASSERT(m_ownerElement);
735 Frame* newParent = m_ownerElement->document()->frame();
736 ASSERT(newParent);
737 bool didTransfer = false;
738
739 // Switch page.
740 Page* newPage = newParent->page();
741 Page* oldPage = m_page;
742 if (m_page != newPage) {
743 if (m_page) {
744 if (m_page->focusController()->focusedFrame() == this)
745 m_page->focusController()->setFocusedFrame(0);
746
747 m_page->decrementFrameCount();
748 }
749
750 // FIXME: We should ideally allow existing Geolocation activities to continue
751 // when the Geolocation's iframe is reparented.
752 // See https://bugs.webkit.org/show_bug.cgi?id=55577
753 // and https://bugs.webkit.org/show_bug.cgi?id=52877
754 if (m_domWindow)
755 m_domWindow->resetGeolocation();
756
757 m_page = newPage;
758
759 if (newPage)
760 newPage->incrementFrameCount();
761
762 didTransfer = true;
763 }
764
765 // Update the frame tree.
766 didTransfer = newParent->tree()->transferChild(this) || didTransfer;
767
768 // Avoid unnecessary calls to client and frame subtree if the frame ended
769 // up on the same page and under the same parent frame.
770 if (didTransfer) {
771 // Let external clients update themselves.
772 loader()->client()->didTransferChildFrameToNewDocument(oldPage);
773
774 // Update resource tracking now that frame could be in a different page.
775 if (oldPage != newPage)
776 loader()->transferLoadingResourcesFromPage(oldPage);
777
778 // Do the same for all the children.
779 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
780 child->transferChildFrameToNewDocument();
781 }
782 }
783
documentTypeString() const784 String Frame::documentTypeString() const
785 {
786 if (DocumentType* doctype = document()->doctype())
787 return createMarkup(doctype);
788
789 return String();
790 }
791
visiblePositionForPoint(const IntPoint & framePoint)792 VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint)
793 {
794 HitTestResult result = eventHandler()->hitTestResultAtPoint(framePoint, true);
795 Node* node = result.innerNode();
796 if (!node)
797 return VisiblePosition();
798 RenderObject* renderer = node->renderer();
799 if (!renderer)
800 return VisiblePosition();
801 VisiblePosition visiblePos = renderer->positionForPoint(result.localPoint());
802 if (visiblePos.isNull())
803 visiblePos = firstPositionInOrBeforeNode(node);
804 return visiblePos;
805 }
806
documentAtPoint(const IntPoint & point)807 Document* Frame::documentAtPoint(const IntPoint& point)
808 {
809 if (!view())
810 return 0;
811
812 IntPoint pt = view()->windowToContents(point);
813 HitTestResult result = HitTestResult(pt);
814
815 if (contentRenderer())
816 result = eventHandler()->hitTestResultAtPoint(pt, false);
817 return result.innerNode() ? result.innerNode()->document() : 0;
818 }
819
rangeForPoint(const IntPoint & framePoint)820 PassRefPtr<Range> Frame::rangeForPoint(const IntPoint& framePoint)
821 {
822 VisiblePosition position = visiblePositionForPoint(framePoint);
823 if (position.isNull())
824 return 0;
825
826 VisiblePosition previous = position.previous();
827 if (previous.isNotNull()) {
828 RefPtr<Range> previousCharacterRange = makeRange(previous, position);
829 IntRect rect = editor()->firstRectForRange(previousCharacterRange.get());
830 if (rect.contains(framePoint))
831 return previousCharacterRange.release();
832 }
833
834 VisiblePosition next = position.next();
835 if (next.isNotNull()) {
836 RefPtr<Range> nextCharacterRange = makeRange(position, next);
837 IntRect rect = editor()->firstRectForRange(nextCharacterRange.get());
838 if (rect.contains(framePoint))
839 return nextCharacterRange.release();
840 }
841
842 return 0;
843 }
844
createView(const IntSize & viewportSize,const Color & backgroundColor,bool transparent,const IntSize & fixedLayoutSize,bool useFixedLayout,ScrollbarMode horizontalScrollbarMode,bool horizontalLock,ScrollbarMode verticalScrollbarMode,bool verticalLock)845 void Frame::createView(const IntSize& viewportSize,
846 const Color& backgroundColor, bool transparent,
847 const IntSize& fixedLayoutSize, bool useFixedLayout,
848 ScrollbarMode horizontalScrollbarMode, bool horizontalLock,
849 ScrollbarMode verticalScrollbarMode, bool verticalLock)
850 {
851 ASSERT(this);
852 ASSERT(m_page);
853
854 bool isMainFrame = this == m_page->mainFrame();
855
856 if (isMainFrame && view())
857 view()->setParentVisible(false);
858
859 setView(0);
860
861 RefPtr<FrameView> frameView;
862 if (isMainFrame) {
863 frameView = FrameView::create(this, viewportSize);
864 frameView->setFixedLayoutSize(fixedLayoutSize);
865 frameView->setUseFixedLayout(useFixedLayout);
866 } else
867 frameView = FrameView::create(this);
868
869 frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock);
870
871 setView(frameView);
872
873 if (backgroundColor.isValid())
874 frameView->updateBackgroundRecursively(backgroundColor, transparent);
875
876 if (isMainFrame)
877 frameView->setParentVisible(true);
878
879 if (ownerRenderer())
880 ownerRenderer()->setWidget(frameView);
881
882 if (HTMLFrameOwnerElement* owner = ownerElement())
883 view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
884 }
885
886 #if ENABLE(TILED_BACKING_STORE)
setTiledBackingStoreEnabled(bool enabled)887 void Frame::setTiledBackingStoreEnabled(bool enabled)
888 {
889 if (!enabled) {
890 m_tiledBackingStore.clear();
891 return;
892 }
893 if (m_tiledBackingStore)
894 return;
895 m_tiledBackingStore.set(new TiledBackingStore(this));
896 if (m_view)
897 m_view->setPaintsEntireContents(true);
898 }
899
tiledBackingStorePaintBegin()900 void Frame::tiledBackingStorePaintBegin()
901 {
902 if (!m_view)
903 return;
904 m_view->updateLayoutAndStyleIfNeededRecursive();
905 m_view->flushDeferredRepaints();
906 }
907
tiledBackingStorePaint(GraphicsContext * context,const IntRect & rect)908 void Frame::tiledBackingStorePaint(GraphicsContext* context, const IntRect& rect)
909 {
910 if (!m_view)
911 return;
912 m_view->paintContents(context, rect);
913 }
914
tiledBackingStorePaintEnd(const Vector<IntRect> & paintedArea)915 void Frame::tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea)
916 {
917 if (!m_page || !m_view)
918 return;
919 unsigned size = paintedArea.size();
920 // Request repaint from the system
921 for (int n = 0; n < size; ++n)
922 m_page->chrome()->invalidateContentsAndWindow(m_view->contentsToWindow(paintedArea[n]), false);
923 }
924
tiledBackingStoreContentsRect()925 IntRect Frame::tiledBackingStoreContentsRect()
926 {
927 if (!m_view)
928 return IntRect();
929 return IntRect(IntPoint(), m_view->contentsSize());
930 }
931
tiledBackingStoreVisibleRect()932 IntRect Frame::tiledBackingStoreVisibleRect()
933 {
934 if (!m_page)
935 return IntRect();
936 return m_page->chrome()->client()->visibleRectForTiledBackingStore();
937 }
938
tiledBackingStoreBackgroundColor() const939 Color Frame::tiledBackingStoreBackgroundColor() const
940 {
941 if (!m_view)
942 return Color();
943 return m_view->baseBackgroundColor();
944 }
945 #endif
946
layerTreeAsText(bool showDebugInfo) const947 String Frame::layerTreeAsText(bool showDebugInfo) const
948 {
949 #if USE(ACCELERATED_COMPOSITING)
950 document()->updateLayout();
951
952 if (!contentRenderer())
953 return String();
954
955 return contentRenderer()->compositor()->layerTreeAsText(showDebugInfo);
956 #else
957 return String();
958 #endif
959 }
960
setPageZoomFactor(float factor)961 void Frame::setPageZoomFactor(float factor)
962 {
963 setPageAndTextZoomFactors(factor, m_textZoomFactor);
964 }
965
setTextZoomFactor(float factor)966 void Frame::setTextZoomFactor(float factor)
967 {
968 setPageAndTextZoomFactors(m_pageZoomFactor, factor);
969 }
970
setPageAndTextZoomFactors(float pageZoomFactor,float textZoomFactor)971 void Frame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor)
972 {
973 if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
974 return;
975
976 Page* page = this->page();
977 if (!page)
978 return;
979
980 Document* document = this->document();
981 if (!document)
982 return;
983
984 m_editor.dismissCorrectionPanelAsIgnored();
985
986 #if ENABLE(SVG)
987 // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents.
988 // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification.
989 if (document->isSVGDocument()) {
990 if (!static_cast<SVGDocument*>(document)->zoomAndPanEnabled())
991 return;
992 if (document->renderer())
993 document->renderer()->setNeedsLayout(true);
994 }
995 #endif
996
997 if (m_pageZoomFactor != pageZoomFactor) {
998 if (FrameView* view = this->view()) {
999 // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
1000 IntPoint scrollPosition = view->scrollPosition();
1001 float percentDifference = (pageZoomFactor / m_pageZoomFactor);
1002 view->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference));
1003 }
1004 }
1005
1006 m_pageZoomFactor = pageZoomFactor;
1007 m_textZoomFactor = textZoomFactor;
1008
1009 document->recalcStyle(Node::Force);
1010
1011 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
1012 child->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor);
1013
1014 if (FrameView* view = this->view()) {
1015 if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
1016 view->layout();
1017 }
1018 }
1019
1020 #if USE(ACCELERATED_COMPOSITING)
updateContentsScale(float scale)1021 void Frame::updateContentsScale(float scale)
1022 {
1023 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
1024 child->updateContentsScale(scale);
1025
1026 RenderView* root = contentRenderer();
1027 if (root && root->compositor())
1028 root->compositor()->updateContentsScale(scale);
1029 }
1030 #endif
1031
scalePage(float scale,const IntPoint & origin)1032 void Frame::scalePage(float scale, const IntPoint& origin)
1033 {
1034 Document* document = this->document();
1035 if (!document)
1036 return;
1037
1038 if (scale != m_pageScaleFactor) {
1039 m_pageScaleFactor = scale;
1040
1041 if (document->renderer())
1042 document->renderer()->setNeedsLayout(true);
1043
1044 document->recalcStyle(Node::Force);
1045
1046 #if USE(ACCELERATED_COMPOSITING)
1047 updateContentsScale(scale);
1048 #endif
1049 }
1050
1051 if (FrameView* view = this->view()) {
1052 if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
1053 view->layout();
1054 view->setScrollPosition(origin);
1055 }
1056 }
1057
1058 } // namespace WebCore
1059