Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / frame / LocalFrame.cpp
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  * Copyright (C) 2008 Google Inc.
13  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Library General Public
16  * License as published by the Free Software Foundation; either
17  * version 2 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Library General Public License for more details.
23  *
24  * You should have received a copy of the GNU Library General Public License
25  * along with this library; see the file COPYING.LIB.  If not, write to
26  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27  * Boston, MA 02110-1301, USA.
28  */
29
30 #include "config.h"
31 #include "core/frame/LocalFrame.h"
32
33 #include "RuntimeEnabledFeatures.h"
34 #include "bindings/v8/ScriptController.h"
35 #include "core/dom/DocumentType.h"
36 #include "core/dom/WheelController.h"
37 #include "core/editing/Editor.h"
38 #include "core/editing/FrameSelection.h"
39 #include "core/editing/InputMethodController.h"
40 #include "core/editing/SpellChecker.h"
41 #include "core/editing/htmlediting.h"
42 #include "core/editing/markup.h"
43 #include "core/events/Event.h"
44 #include "core/fetch/ResourceFetcher.h"
45 #include "core/frame/DOMWindow.h"
46 #include "core/frame/FrameConsole.h"
47 #include "core/frame/FrameHost.h"
48 #include "core/frame/FrameView.h"
49 #include "core/frame/Settings.h"
50 #include "core/html/HTMLFrameElementBase.h"
51 #include "core/inspector/InspectorInstrumentation.h"
52 #include "core/loader/FrameLoaderClient.h"
53 #include "core/page/Chrome.h"
54 #include "core/page/EventHandler.h"
55 #include "core/page/FocusController.h"
56 #include "core/page/scrolling/ScrollingCoordinator.h"
57 #include "core/rendering/HitTestResult.h"
58 #include "core/rendering/RenderLayer.h"
59 #include "core/rendering/RenderView.h"
60 #include "core/rendering/compositing/RenderLayerCompositor.h"
61 #include "core/svg/SVGDocumentExtensions.h"
62 #include "platform/DragImage.h"
63 #include "platform/graphics/GraphicsContext.h"
64 #include "platform/graphics/ImageBuffer.h"
65 #include "wtf/PassOwnPtr.h"
66 #include "wtf/StdLibExtras.h"
67
68 using namespace std;
69
70 namespace WebCore {
71
72 using namespace HTMLNames;
73
74 static inline float parentPageZoomFactor(LocalFrame* frame)
75 {
76     LocalFrame* parent = frame->tree().parent();
77     if (!parent)
78         return 1;
79     return parent->pageZoomFactor();
80 }
81
82 static inline float parentTextZoomFactor(LocalFrame* frame)
83 {
84     LocalFrame* parent = frame->tree().parent();
85     if (!parent)
86         return 1;
87     return parent->textZoomFactor();
88 }
89
90 inline LocalFrame::LocalFrame(FrameLoaderClient* client, FrameHost* host, HTMLFrameOwnerElement* ownerElement)
91     : Frame(host, ownerElement)
92     , m_treeNode(this)
93     , m_loader(this, client)
94     , m_navigationScheduler(this)
95     , m_script(adoptPtr(new ScriptController(this)))
96     , m_editor(Editor::create(*this))
97     , m_spellChecker(SpellChecker::create(*this))
98     , m_selection(adoptPtr(new FrameSelection(this)))
99     , m_eventHandler(adoptPtr(new EventHandler(this)))
100     , m_console(FrameConsole::create(*this))
101     , m_inputMethodController(InputMethodController::create(*this))
102     , m_pageZoomFactor(parentPageZoomFactor(this))
103     , m_textZoomFactor(parentTextZoomFactor(this))
104     , m_inViewSourceMode(false)
105 {
106 }
107
108 PassRefPtr<LocalFrame> LocalFrame::create(FrameLoaderClient* client, FrameHost* host, HTMLFrameOwnerElement* ownerElement)
109 {
110     RefPtr<LocalFrame> frame = adoptRef(new LocalFrame(client, host, ownerElement));
111     if (!frame->ownerElement())
112         frame->page()->setMainFrame(frame);
113     InspectorInstrumentation::frameAttachedToParent(frame.get());
114     return frame.release();
115 }
116
117 LocalFrame::~LocalFrame()
118 {
119     setView(nullptr);
120     loader().clear();
121     setDOMWindow(nullptr);
122 }
123
124 bool LocalFrame::inScope(TreeScope* scope) const
125 {
126     ASSERT(scope);
127     Document* doc = document();
128     if (!doc)
129         return false;
130     HTMLFrameOwnerElement* owner = doc->ownerElement();
131     if (!owner)
132         return false;
133     return owner->treeScope() == scope;
134 }
135
136 void LocalFrame::setView(PassRefPtr<FrameView> view)
137 {
138     // We the custom scroll bars as early as possible to prevent m_doc->detach()
139     // from messing with the view such that its scroll bars won't be torn down.
140     // FIXME: We should revisit this.
141     if (m_view)
142         m_view->prepareForDetach();
143
144     // Prepare for destruction now, so any unload event handlers get run and the DOMWindow is
145     // notified. If we wait until the view is destroyed, then things won't be hooked up enough for
146     // these calls to work.
147     if (!view && document() && document()->isActive()) {
148         // FIXME: We don't call willRemove here. Why is that OK?
149         document()->prepareForDestruction();
150     }
151
152     eventHandler().clear();
153
154     m_view = view;
155
156     if (m_view && isMainFrame()) {
157         if (settings()->pinchVirtualViewportEnabled())
158             m_host->pinchViewport().mainFrameDidChangeSize();
159         else
160             m_view->setVisibleContentScaleFactor(page()->pageScaleFactor());
161     }
162 }
163
164 void LocalFrame::sendOrientationChangeEvent()
165 {
166     if (!RuntimeEnabledFeatures::orientationEventEnabled())
167         return;
168
169     if (DOMWindow* window = domWindow())
170         window->dispatchEvent(Event::create(EventTypeNames::orientationchange));
171 }
172
173 void LocalFrame::setPrinting(bool printing, const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkRatio)
174 {
175     // In setting printing, we should not validate resources already cached for the document.
176     // See https://bugs.webkit.org/show_bug.cgi?id=43704
177     ResourceCacheValidationSuppressor validationSuppressor(document()->fetcher());
178
179     document()->setPrinting(printing);
180     view()->adjustMediaTypeForPrinting(printing);
181
182     document()->styleResolverChanged(RecalcStyleImmediately);
183     if (shouldUsePrintingLayout()) {
184         view()->forceLayoutForPagination(pageSize, originalPageSize, maximumShrinkRatio);
185     } else {
186         view()->forceLayout();
187         view()->adjustViewSize();
188     }
189
190     // Subframes of the one we're printing don't lay out to the page size.
191     for (RefPtr<LocalFrame> child = tree().firstChild(); child; child = child->tree().nextSibling())
192         child->setPrinting(printing, FloatSize(), FloatSize(), 0);
193 }
194
195 bool LocalFrame::shouldUsePrintingLayout() const
196 {
197     // Only top frame being printed should be fit to page size.
198     // Subframes should be constrained by parents only.
199     return document()->printing() && (!tree().parent() || !tree().parent()->document()->printing());
200 }
201
202 FloatSize LocalFrame::resizePageRectsKeepingRatio(const FloatSize& originalSize, const FloatSize& expectedSize)
203 {
204     FloatSize resultSize;
205     if (!contentRenderer())
206         return FloatSize();
207
208     if (contentRenderer()->style()->isHorizontalWritingMode()) {
209         ASSERT(fabs(originalSize.width()) > numeric_limits<float>::epsilon());
210         float ratio = originalSize.height() / originalSize.width();
211         resultSize.setWidth(floorf(expectedSize.width()));
212         resultSize.setHeight(floorf(resultSize.width() * ratio));
213     } else {
214         ASSERT(fabs(originalSize.height()) > numeric_limits<float>::epsilon());
215         float ratio = originalSize.width() / originalSize.height();
216         resultSize.setHeight(floorf(expectedSize.height()));
217         resultSize.setWidth(floorf(resultSize.height() * ratio));
218     }
219     return resultSize;
220 }
221
222 void LocalFrame::setDOMWindow(PassRefPtrWillBeRawPtr<DOMWindow> domWindow)
223 {
224     InspectorInstrumentation::frameWindowDiscarded(this, m_domWindow.get());
225     if (domWindow)
226         script().clearWindowShell();
227     Frame::setDOMWindow(domWindow);
228 }
229
230 void LocalFrame::didChangeVisibilityState()
231 {
232     if (document())
233         document()->didChangeVisibilityState();
234
235     Vector<RefPtr<LocalFrame> > childFrames;
236     for (LocalFrame* child = tree().firstChild(); child; child = child->tree().nextSibling())
237         childFrames.append(child);
238
239     for (size_t i = 0; i < childFrames.size(); ++i)
240         childFrames[i]->didChangeVisibilityState();
241 }
242
243 void LocalFrame::willDetachFrameHost()
244 {
245     // We should never be detatching the page during a Layout.
246     RELEASE_ASSERT(!m_view || !m_view->isInPerformLayout());
247
248     if (LocalFrame* parent = tree().parent())
249         parent->loader().checkLoadComplete();
250
251     Frame::willDetachFrameHost();
252     script().clearScriptObjects();
253
254     if (page() && page()->scrollingCoordinator() && m_view)
255         page()->scrollingCoordinator()->willDestroyScrollableArea(m_view.get());
256 }
257
258 void LocalFrame::detachFromFrameHost()
259 {
260     // We should never be detatching the page during a Layout.
261     RELEASE_ASSERT(!m_view || !m_view->isInPerformLayout());
262     Frame::detachFromFrameHost();
263 }
264
265 String LocalFrame::documentTypeString() const
266 {
267     if (DocumentType* doctype = document()->doctype())
268         return createMarkup(doctype);
269
270     return String();
271 }
272
273 String LocalFrame::selectedText() const
274 {
275     return selection().selectedText();
276 }
277
278 String LocalFrame::selectedTextForClipboard() const
279 {
280     return selection().selectedTextForClipboard();
281 }
282
283 VisiblePosition LocalFrame::visiblePositionForPoint(const IntPoint& framePoint)
284 {
285     HitTestResult result = eventHandler().hitTestResultAtPoint(framePoint);
286     Node* node = result.innerNonSharedNode();
287     if (!node)
288         return VisiblePosition();
289     RenderObject* renderer = node->renderer();
290     if (!renderer)
291         return VisiblePosition();
292     VisiblePosition visiblePos = VisiblePosition(renderer->positionForPoint(result.localPoint()));
293     if (visiblePos.isNull())
294         visiblePos = VisiblePosition(firstPositionInOrBeforeNode(node));
295     return visiblePos;
296 }
297
298 RenderView* LocalFrame::contentRenderer() const
299 {
300     return document() ? document()->renderView() : 0;
301 }
302
303 Document* LocalFrame::document() const
304 {
305     return m_domWindow ? m_domWindow->document() : 0;
306 }
307
308 Document* LocalFrame::documentAtPoint(const IntPoint& point)
309 {
310     if (!view())
311         return 0;
312
313     IntPoint pt = view()->windowToContents(point);
314     HitTestResult result = HitTestResult(pt);
315
316     if (contentRenderer())
317         result = eventHandler().hitTestResultAtPoint(pt, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
318     return result.innerNode() ? &result.innerNode()->document() : 0;
319 }
320
321 PassRefPtrWillBeRawPtr<Range> LocalFrame::rangeForPoint(const IntPoint& framePoint)
322 {
323     VisiblePosition position = visiblePositionForPoint(framePoint);
324     if (position.isNull())
325         return nullptr;
326
327     VisiblePosition previous = position.previous();
328     if (previous.isNotNull()) {
329         RefPtrWillBeRawPtr<Range> previousCharacterRange = makeRange(previous, position);
330         LayoutRect rect = editor().firstRectForRange(previousCharacterRange.get());
331         if (rect.contains(framePoint))
332             return previousCharacterRange.release();
333     }
334
335     VisiblePosition next = position.next();
336     if (RefPtrWillBeRawPtr<Range> nextCharacterRange = makeRange(position, next)) {
337         LayoutRect rect = editor().firstRectForRange(nextCharacterRange.get());
338         if (rect.contains(framePoint))
339             return nextCharacterRange.release();
340     }
341
342     return nullptr;
343 }
344
345 void LocalFrame::createView(const IntSize& viewportSize, const Color& backgroundColor, bool transparent,
346     ScrollbarMode horizontalScrollbarMode, bool horizontalLock,
347     ScrollbarMode verticalScrollbarMode, bool verticalLock)
348 {
349     ASSERT(this);
350     ASSERT(page());
351
352     bool isMainFrame = this->isMainFrame();
353
354     if (isMainFrame && view())
355         view()->setParentVisible(false);
356
357     setView(nullptr);
358
359     RefPtr<FrameView> frameView;
360     if (isMainFrame) {
361         frameView = FrameView::create(this, viewportSize);
362
363         // The layout size is set by WebViewImpl to support @viewport
364         frameView->setLayoutSizeFixedToFrameSize(false);
365     } else
366         frameView = FrameView::create(this);
367
368     frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock);
369
370     setView(frameView);
371
372     if (backgroundColor.alpha())
373         frameView->updateBackgroundRecursively(backgroundColor, transparent);
374
375     if (isMainFrame)
376         frameView->setParentVisible(true);
377
378     if (ownerRenderer()) {
379         HTMLFrameOwnerElement* owner = ownerElement();
380         ASSERT(owner);
381         owner->setWidget(frameView);
382     }
383
384     if (HTMLFrameOwnerElement* owner = ownerElement())
385         view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
386 }
387
388
389 void LocalFrame::countObjectsNeedingLayout(unsigned& needsLayoutObjects, unsigned& totalObjects, bool& isPartial)
390 {
391     RenderObject* root = view()->layoutRoot();
392     isPartial = true;
393     if (!root) {
394         isPartial = false;
395         root = contentRenderer();
396     }
397
398     needsLayoutObjects = 0;
399     totalObjects = 0;
400
401     for (RenderObject* o = root; o; o = o->nextInPreOrder(root)) {
402         ++totalObjects;
403         if (o->needsLayout())
404             ++needsLayoutObjects;
405     }
406 }
407
408 String LocalFrame::layerTreeAsText(unsigned flags) const
409 {
410     if (!contentRenderer())
411         return String();
412
413     return contentRenderer()->compositor()->layerTreeAsText(static_cast<LayerTreeFlags>(flags));
414 }
415
416 String LocalFrame::trackedRepaintRectsAsText() const
417 {
418     if (!m_view)
419         return String();
420     return m_view->trackedRepaintRectsAsText();
421 }
422
423 void LocalFrame::setPageZoomFactor(float factor)
424 {
425     setPageAndTextZoomFactors(factor, m_textZoomFactor);
426 }
427
428 void LocalFrame::setTextZoomFactor(float factor)
429 {
430     setPageAndTextZoomFactors(m_pageZoomFactor, factor);
431 }
432
433 void LocalFrame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor)
434 {
435     if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
436         return;
437
438     Page* page = this->page();
439     if (!page)
440         return;
441
442     Document* document = this->document();
443     if (!document)
444         return;
445
446     // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents.
447     // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification.
448     if (document->isSVGDocument()) {
449         if (!document->accessSVGExtensions().zoomAndPanEnabled())
450             return;
451     }
452
453     if (m_pageZoomFactor != pageZoomFactor) {
454         if (FrameView* view = this->view()) {
455             // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
456             LayoutPoint scrollPosition = view->scrollPosition();
457             float percentDifference = (pageZoomFactor / m_pageZoomFactor);
458             view->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference));
459         }
460     }
461
462     m_pageZoomFactor = pageZoomFactor;
463     m_textZoomFactor = textZoomFactor;
464
465     for (RefPtr<LocalFrame> child = tree().firstChild(); child; child = child->tree().nextSibling())
466         child->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor);
467
468     document->setNeedsStyleRecalc(SubtreeStyleChange);
469     document->updateLayoutIgnorePendingStylesheets();
470 }
471
472 void LocalFrame::deviceOrPageScaleFactorChanged()
473 {
474     document()->mediaQueryAffectingValueChanged();
475     for (RefPtr<LocalFrame> child = tree().firstChild(); child; child = child->tree().nextSibling())
476         child->deviceOrPageScaleFactorChanged();
477 }
478
479 void LocalFrame::notifyChromeClientWheelEventHandlerCountChanged() const
480 {
481     // Ensure that this method is being called on the main frame of the page.
482     ASSERT(isMainFrame());
483
484     unsigned count = 0;
485     for (const LocalFrame* frame = this; frame; frame = frame->tree().traverseNext()) {
486         if (frame->document())
487             count += WheelController::from(*frame->document())->wheelEventHandlerCount();
488     }
489
490     m_host->chrome().client().numWheelEventHandlersChanged(count);
491 }
492
493 bool LocalFrame::isURLAllowed(const KURL& url) const
494 {
495     // We allow one level of self-reference because some sites depend on that,
496     // but we don't allow more than one.
497     if (page()->subframeCount() >= Page::maxNumberOfFrames)
498         return false;
499     bool foundSelfReference = false;
500     for (const LocalFrame* frame = this; frame; frame = frame->tree().parent()) {
501         if (equalIgnoringFragmentIdentifier(frame->document()->url(), url)) {
502             if (foundSelfReference)
503                 return false;
504             foundSelfReference = true;
505         }
506     }
507     return true;
508 }
509
510 struct ScopedFramePaintingState {
511     ScopedFramePaintingState(LocalFrame* frame, Node* node)
512         : frame(frame)
513         , node(node)
514         , paintBehavior(frame->view()->paintBehavior())
515     {
516         ASSERT(!node || node->renderer());
517         if (node)
518             node->renderer()->updateDragState(true);
519     }
520
521     ~ScopedFramePaintingState()
522     {
523         if (node && node->renderer())
524             node->renderer()->updateDragState(false);
525         frame->view()->setPaintBehavior(paintBehavior);
526         frame->view()->setNodeToDraw(0);
527     }
528
529     LocalFrame* frame;
530     Node* node;
531     PaintBehavior paintBehavior;
532 };
533
534 PassOwnPtr<DragImage> LocalFrame::nodeImage(Node& node)
535 {
536     if (!node.renderer())
537         return nullptr;
538
539     const ScopedFramePaintingState state(this, &node);
540
541     m_view->updateLayoutAndStyleForPainting();
542
543     m_view->setPaintBehavior(state.paintBehavior | PaintBehaviorFlattenCompositingLayers);
544
545     m_view->setNodeToDraw(&node); // Enable special sub-tree drawing mode.
546
547     // Document::updateLayout may have blown away the original RenderObject.
548     RenderObject* renderer = node.renderer();
549     if (!renderer)
550         return nullptr;
551
552     LayoutRect topLevelRect;
553     IntRect paintingRect = pixelSnappedIntRect(renderer->paintingRootRect(topLevelRect));
554
555     ASSERT(document()->isActive());
556     float deviceScaleFactor = m_host->deviceScaleFactor();
557     paintingRect.setWidth(paintingRect.width() * deviceScaleFactor);
558     paintingRect.setHeight(paintingRect.height() * deviceScaleFactor);
559
560     OwnPtr<ImageBuffer> buffer = ImageBuffer::create(paintingRect.size());
561     if (!buffer)
562         return nullptr;
563     buffer->context()->scale(FloatSize(deviceScaleFactor, deviceScaleFactor));
564     buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
565     buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
566
567     m_view->paintContents(buffer->context(), paintingRect);
568
569     RefPtr<Image> image = buffer->copyImage();
570     return DragImage::create(image.get(), renderer->shouldRespectImageOrientation(), deviceScaleFactor);
571 }
572
573 PassOwnPtr<DragImage> LocalFrame::dragImageForSelection()
574 {
575     if (!selection().isRange())
576         return nullptr;
577
578     const ScopedFramePaintingState state(this, 0);
579     m_view->setPaintBehavior(PaintBehaviorSelectionOnly | PaintBehaviorFlattenCompositingLayers);
580     document()->updateLayout();
581
582     IntRect paintingRect = enclosingIntRect(selection().bounds());
583
584     ASSERT(document()->isActive());
585     float deviceScaleFactor = m_host->deviceScaleFactor();
586     paintingRect.setWidth(paintingRect.width() * deviceScaleFactor);
587     paintingRect.setHeight(paintingRect.height() * deviceScaleFactor);
588
589     OwnPtr<ImageBuffer> buffer = ImageBuffer::create(paintingRect.size());
590     if (!buffer)
591         return nullptr;
592     buffer->context()->scale(FloatSize(deviceScaleFactor, deviceScaleFactor));
593     buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
594     buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
595
596     m_view->paintContents(buffer->context(), paintingRect);
597
598     RefPtr<Image> image = buffer->copyImage();
599     return DragImage::create(image.get(), DoNotRespectImageOrientation, deviceScaleFactor);
600 }
601
602 double LocalFrame::devicePixelRatio() const
603 {
604     if (!m_host)
605         return 0;
606
607     double ratio = m_host->deviceScaleFactor();
608     ratio *= pageZoomFactor();
609     return ratio;
610 }
611
612 void LocalFrame::disconnectOwnerElement()
613 {
614     if (ownerElement()) {
615         if (Document* doc = document())
616             doc->topDocument().clearAXObjectCache();
617     }
618     Frame::disconnectOwnerElement();
619 }
620
621 LocalFrame* LocalFrame::localFrameRoot()
622 {
623     LocalFrame* curFrame = this;
624     while (curFrame && curFrame->tree().parent() && curFrame->tree().parent()->isLocalFrame())
625         curFrame = curFrame->tree().parent();
626
627     return curFrame;
628 }
629
630 } // namespace WebCore