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