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 "bindings/core/v8/ScriptController.h"
34#include "core/dom/DocumentType.h"
35#include "core/editing/Editor.h"
36#include "core/editing/FrameSelection.h"
37#include "core/editing/InputMethodController.h"
38#include "core/editing/SpellChecker.h"
39#include "core/editing/htmlediting.h"
40#include "core/editing/markup.h"
41#include "core/events/Event.h"
42#include "core/fetch/ResourceFetcher.h"
43#include "core/frame/EventHandlerRegistry.h"
44#include "core/frame/FrameConsole.h"
45#include "core/frame/FrameDestructionObserver.h"
46#include "core/frame/FrameHost.h"
47#include "core/frame/FrameView.h"
48#include "core/frame/LocalDOMWindow.h"
49#include "core/frame/Settings.h"
50#include "core/html/HTMLFrameElementBase.h"
51#include "core/inspector/ConsoleMessageStorage.h"
52#include "core/inspector/InspectorInstrumentation.h"
53#include "core/loader/FrameLoaderClient.h"
54#include "core/page/Chrome.h"
55#include "core/page/EventHandler.h"
56#include "core/page/FocusController.h"
57#include "core/page/Page.h"
58#include "core/page/scrolling/ScrollingCoordinator.h"
59#include "core/rendering/HitTestResult.h"
60#include "core/rendering/RenderLayer.h"
61#include "core/rendering/RenderView.h"
62#include "core/rendering/compositing/RenderLayerCompositor.h"
63#include "core/svg/SVGDocumentExtensions.h"
64#include "platform/DragImage.h"
65#include "platform/RuntimeEnabledFeatures.h"
66#include "platform/graphics/GraphicsContext.h"
67#include "platform/graphics/ImageBuffer.h"
68#include "platform/text/TextStream.h"
69#include "wtf/PassOwnPtr.h"
70#include "wtf/StdLibExtras.h"
71
72namespace blink {
73
74using namespace HTMLNames;
75
76static inline float parentPageZoomFactor(LocalFrame* frame)
77{
78    Frame* parent = frame->tree().parent();
79    if (!parent || !parent->isLocalFrame())
80        return 1;
81    return toLocalFrame(parent)->pageZoomFactor();
82}
83
84static inline float parentTextZoomFactor(LocalFrame* frame)
85{
86    Frame* parent = frame->tree().parent();
87    if (!parent || !parent->isLocalFrame())
88        return 1;
89    return toLocalFrame(parent)->textZoomFactor();
90}
91
92inline LocalFrame::LocalFrame(FrameLoaderClient* client, FrameHost* host, FrameOwner* owner)
93    : Frame(client, host, owner)
94    , m_loader(this)
95    , m_navigationScheduler(this)
96    , m_script(adoptPtr(new ScriptController(this)))
97    , m_editor(Editor::create(*this))
98    , m_spellChecker(SpellChecker::create(*this))
99    , m_selection(FrameSelection::create(this))
100    , m_eventHandler(adoptPtrWillBeNoop(new EventHandler(this)))
101    , m_console(FrameConsole::create(*this))
102    , m_inputMethodController(InputMethodController::create(*this))
103    , m_pageZoomFactor(parentPageZoomFactor(this))
104    , m_textZoomFactor(parentTextZoomFactor(this))
105    , m_inViewSourceMode(false)
106{
107}
108
109PassRefPtrWillBeRawPtr<LocalFrame> LocalFrame::create(FrameLoaderClient* client, FrameHost* host, FrameOwner* owner)
110{
111    RefPtrWillBeRawPtr<LocalFrame> frame = adoptRefWillBeNoop(new LocalFrame(client, host, owner));
112    InspectorInstrumentation::frameAttachedToParent(frame.get());
113    return frame.release();
114}
115
116LocalFrame::~LocalFrame()
117{
118#if ENABLE(OILPAN)
119    // Verify that the FrameView has been cleared as part of detaching
120    // the frame owner.
121    ASSERT(!m_view);
122    // Oilpan: see setDOMWindow() comment why it is acceptable not to
123    // mirror the non-Oilpan call below.
124    //
125    // Also, FrameDestructionObservers that live longer than this
126    // frame object keep weak references to the frame; those will be
127    // automatically cleared by the garbage collector. Hence, explicit
128    // frameDestroyed() notifications aren't needed.
129#else
130    // FIXME: follow Oilpan and clear the FrameView and FrameLoader
131    // during FrameOwner detachment instead, see LocalFrame::disconnectOwnerElement().
132    setView(nullptr);
133    m_loader.clear();
134    setDOMWindow(nullptr);
135
136    HashSet<RawPtr<FrameDestructionObserver> >::iterator stop = m_destructionObservers.end();
137    for (HashSet<RawPtr<FrameDestructionObserver> >::iterator it = m_destructionObservers.begin(); it != stop; ++it)
138        (*it)->frameDestroyed();
139#endif
140}
141
142void LocalFrame::trace(Visitor* visitor)
143{
144#if ENABLE(OILPAN)
145    visitor->trace(m_destructionObservers);
146    visitor->trace(m_loader);
147    visitor->trace(m_navigationScheduler);
148    visitor->trace(m_pagePopupOwner);
149    visitor->trace(m_editor);
150    visitor->trace(m_spellChecker);
151    visitor->trace(m_selection);
152    visitor->trace(m_eventHandler);
153    visitor->trace(m_console);
154    visitor->trace(m_inputMethodController);
155    HeapSupplementable<LocalFrame>::trace(visitor);
156#endif
157    Frame::trace(visitor);
158}
159
160void LocalFrame::detach()
161{
162    // A lot of the following steps can result in the current frame being
163    // detached, so protect a reference to it.
164    RefPtrWillBeRawPtr<LocalFrame> protect(this);
165    m_loader.stopAllLoaders();
166    m_loader.closeURL();
167    detachChildren();
168    // stopAllLoaders() needs to be called after detachChildren(), because detachChildren()
169    // will trigger the unload event handlers of any child frames, and those event
170    // handlers might start a new subresource load in this frame.
171    m_loader.stopAllLoaders();
172    m_loader.detachFromParent();
173}
174
175bool LocalFrame::inScope(TreeScope* scope) const
176{
177    ASSERT(scope);
178    Document* doc = document();
179    if (!doc)
180        return false;
181    // FIXME: This check is broken in for OOPI.
182    HTMLFrameOwnerElement* owner = doc->ownerElement();
183    if (!owner)
184        return false;
185    return owner->treeScope() == scope;
186}
187
188void LocalFrame::detachView()
189{
190    // We detach the FrameView's custom scroll bars as early as
191    // possible to prevent m_doc->detach() from messing with the view
192    // such that its scroll bars won't be torn down.
193    //
194    // FIXME: We should revisit this.
195    if (m_view)
196        m_view->prepareForDetach();
197}
198
199void LocalFrame::setView(PassRefPtr<FrameView> view)
200{
201    detachView();
202
203    // Prepare for destruction now, so any unload event handlers get run and the LocalDOMWindow is
204    // notified. If we wait until the view is destroyed, then things won't be hooked up enough for
205    // these calls to work.
206    if (!view && document() && document()->isActive()) {
207        // FIXME: We don't call willRemove here. Why is that OK?
208        document()->prepareForDestruction();
209    }
210
211    eventHandler().clear();
212
213    m_view = view;
214
215    if (m_view && isMainFrame()) {
216        if (settings()->pinchVirtualViewportEnabled())
217            m_host->pinchViewport().mainFrameDidChangeSize();
218        else
219            m_view->setVisibleContentScaleFactor(page()->pageScaleFactor());
220    }
221}
222
223void LocalFrame::setPrinting(bool printing, const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkRatio)
224{
225    // In setting printing, we should not validate resources already cached for the document.
226    // See https://bugs.webkit.org/show_bug.cgi?id=43704
227    ResourceCacheValidationSuppressor validationSuppressor(document()->fetcher());
228
229    document()->setPrinting(printing);
230    view()->adjustMediaTypeForPrinting(printing);
231
232    document()->styleResolverChanged();
233    if (shouldUsePrintingLayout()) {
234        view()->forceLayoutForPagination(pageSize, originalPageSize, maximumShrinkRatio);
235    } else {
236        view()->forceLayout();
237        view()->adjustViewSize();
238    }
239
240    // Subframes of the one we're printing don't lay out to the page size.
241    for (RefPtrWillBeRawPtr<Frame> child = tree().firstChild(); child; child = child->tree().nextSibling()) {
242        if (child->isLocalFrame())
243            toLocalFrame(child.get())->setPrinting(printing, FloatSize(), FloatSize(), 0);
244    }
245}
246
247bool LocalFrame::shouldUsePrintingLayout() const
248{
249    // Only top frame being printed should be fit to page size.
250    // Subframes should be constrained by parents only.
251    return document()->printing() && (!tree().parent() || !tree().parent()->isLocalFrame() || !toLocalFrame(tree().parent())->document()->printing());
252}
253
254FloatSize LocalFrame::resizePageRectsKeepingRatio(const FloatSize& originalSize, const FloatSize& expectedSize)
255{
256    FloatSize resultSize;
257    if (!contentRenderer())
258        return FloatSize();
259
260    if (contentRenderer()->style()->isHorizontalWritingMode()) {
261        ASSERT(fabs(originalSize.width()) > std::numeric_limits<float>::epsilon());
262        float ratio = originalSize.height() / originalSize.width();
263        resultSize.setWidth(floorf(expectedSize.width()));
264        resultSize.setHeight(floorf(resultSize.width() * ratio));
265    } else {
266        ASSERT(fabs(originalSize.height()) > std::numeric_limits<float>::epsilon());
267        float ratio = originalSize.width() / originalSize.height();
268        resultSize.setHeight(floorf(expectedSize.height()));
269        resultSize.setWidth(floorf(resultSize.height() * ratio));
270    }
271    return resultSize;
272}
273
274void LocalFrame::setDOMWindow(PassRefPtrWillBeRawPtr<LocalDOMWindow> domWindow)
275{
276    if (m_domWindow) {
277        // Oilpan: the assumption is that FrameDestructionObserver::willDetachFrameHost()
278        // on LocalWindow will have signalled these frameWindowDiscarded() notifications.
279        //
280        // It is not invoked when finalizing the LocalFrame, as setDOMWindow() isn't
281        // performed (accessing the m_domWindow heap object is unsafe then.)
282        console().messageStorage()->frameWindowDiscarded(m_domWindow.get());
283        InspectorInstrumentation::frameWindowDiscarded(this, m_domWindow.get());
284    }
285    if (domWindow)
286        script().clearWindowProxy();
287    Frame::setDOMWindow(domWindow);
288}
289
290void LocalFrame::didChangeVisibilityState()
291{
292    if (document())
293        document()->didChangeVisibilityState();
294
295    WillBeHeapVector<RefPtrWillBeMember<LocalFrame> > childFrames;
296    for (Frame* child = tree().firstChild(); child; child = child->tree().nextSibling()) {
297        if (child->isLocalFrame())
298            childFrames.append(toLocalFrame(child));
299    }
300
301    for (size_t i = 0; i < childFrames.size(); ++i)
302        childFrames[i]->didChangeVisibilityState();
303}
304
305void LocalFrame::addDestructionObserver(FrameDestructionObserver* observer)
306{
307    m_destructionObservers.add(observer);
308}
309
310void LocalFrame::removeDestructionObserver(FrameDestructionObserver* observer)
311{
312    m_destructionObservers.remove(observer);
313}
314
315void LocalFrame::willDetachFrameHost()
316{
317    // We should never be detatching the page during a Layout.
318    RELEASE_ASSERT(!m_view || !m_view->isInPerformLayout());
319
320    Frame* parent = tree().parent();
321    if (parent && parent->isLocalFrame())
322        toLocalFrame(parent)->loader().checkLoadComplete();
323
324    WillBeHeapHashSet<RawPtrWillBeWeakMember<FrameDestructionObserver> >::iterator stop = m_destructionObservers.end();
325    for (WillBeHeapHashSet<RawPtrWillBeWeakMember<FrameDestructionObserver> >::iterator it = m_destructionObservers.begin(); it != stop; ++it)
326        (*it)->willDetachFrameHost();
327
328    // FIXME: Page should take care of updating focus/scrolling instead of Frame.
329    // FIXME: It's unclear as to why this is called more than once, but it is,
330    // so page() could be null.
331    if (page() && page()->focusController().focusedFrame() == this)
332        page()->focusController().setFocusedFrame(nullptr);
333    script().clearScriptObjects();
334
335    if (page() && page()->scrollingCoordinator() && m_view)
336        page()->scrollingCoordinator()->willDestroyScrollableArea(m_view.get());
337}
338
339void LocalFrame::detachFromFrameHost()
340{
341    // We should never be detaching the page during a Layout.
342    RELEASE_ASSERT(!m_view || !m_view->isInPerformLayout());
343    m_host = nullptr;
344}
345
346String LocalFrame::documentTypeString() const
347{
348    if (DocumentType* doctype = document()->doctype())
349        return createMarkup(doctype);
350
351    return String();
352}
353
354String LocalFrame::selectedText() const
355{
356    return selection().selectedText();
357}
358
359String LocalFrame::selectedTextForClipboard() const
360{
361    return selection().selectedTextForClipboard();
362}
363
364VisiblePosition LocalFrame::visiblePositionForPoint(const IntPoint& framePoint)
365{
366    HitTestResult result = eventHandler().hitTestResultAtPoint(framePoint);
367    Node* node = result.innerNonSharedNode();
368    if (!node)
369        return VisiblePosition();
370    RenderObject* renderer = node->renderer();
371    if (!renderer)
372        return VisiblePosition();
373    VisiblePosition visiblePos = VisiblePosition(renderer->positionForPoint(result.localPoint()));
374    if (visiblePos.isNull())
375        visiblePos = VisiblePosition(firstPositionInOrBeforeNode(node));
376    return visiblePos;
377}
378
379RenderView* LocalFrame::contentRenderer() const
380{
381    return document() ? document()->renderView() : 0;
382}
383
384Document* LocalFrame::document() const
385{
386    return m_domWindow ? m_domWindow->document() : 0;
387}
388
389Document* LocalFrame::documentAtPoint(const IntPoint& point)
390{
391    if (!view())
392        return 0;
393
394    IntPoint pt = view()->windowToContents(point);
395    HitTestResult result = HitTestResult(pt);
396
397    if (contentRenderer())
398        result = eventHandler().hitTestResultAtPoint(pt, HitTestRequest::ReadOnly | HitTestRequest::Active);
399    return result.innerNode() ? &result.innerNode()->document() : 0;
400}
401
402PassRefPtrWillBeRawPtr<Range> LocalFrame::rangeForPoint(const IntPoint& framePoint)
403{
404    VisiblePosition position = visiblePositionForPoint(framePoint);
405    if (position.isNull())
406        return nullptr;
407
408    VisiblePosition previous = position.previous();
409    if (previous.isNotNull()) {
410        RefPtrWillBeRawPtr<Range> previousCharacterRange = makeRange(previous, position);
411        LayoutRect rect = editor().firstRectForRange(previousCharacterRange.get());
412        if (rect.contains(framePoint))
413            return previousCharacterRange.release();
414    }
415
416    VisiblePosition next = position.next();
417    if (RefPtrWillBeRawPtr<Range> nextCharacterRange = makeRange(position, next)) {
418        LayoutRect rect = editor().firstRectForRange(nextCharacterRange.get());
419        if (rect.contains(framePoint))
420            return nextCharacterRange.release();
421    }
422
423    return nullptr;
424}
425
426void LocalFrame::createView(const IntSize& viewportSize, const Color& backgroundColor, bool transparent,
427    ScrollbarMode horizontalScrollbarMode, bool horizontalLock,
428    ScrollbarMode verticalScrollbarMode, bool verticalLock)
429{
430    ASSERT(this);
431    ASSERT(page());
432
433    bool isLocalRoot = this->isLocalRoot();
434
435    if (isLocalRoot && view())
436        view()->setParentVisible(false);
437
438    setView(nullptr);
439
440    RefPtr<FrameView> frameView;
441    if (isLocalRoot) {
442        frameView = FrameView::create(this, viewportSize);
443
444        // The layout size is set by WebViewImpl to support @viewport
445        frameView->setLayoutSizeFixedToFrameSize(false);
446    } else
447        frameView = FrameView::create(this);
448
449    frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock);
450
451    setView(frameView);
452
453    frameView->updateBackgroundRecursively(backgroundColor, transparent);
454
455    if (isLocalRoot)
456        frameView->setParentVisible(true);
457
458    // FIXME: Not clear what the right thing for OOPI is here.
459    if (ownerRenderer()) {
460        HTMLFrameOwnerElement* owner = deprecatedLocalOwner();
461        ASSERT(owner);
462        owner->setWidget(frameView);
463    }
464
465    if (HTMLFrameOwnerElement* owner = deprecatedLocalOwner())
466        view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
467}
468
469
470void LocalFrame::countObjectsNeedingLayout(unsigned& needsLayoutObjects, unsigned& totalObjects, bool& isPartial)
471{
472    RenderObject* root = view()->layoutRoot();
473    isPartial = true;
474    if (!root) {
475        isPartial = false;
476        root = contentRenderer();
477    }
478
479    needsLayoutObjects = 0;
480    totalObjects = 0;
481
482    for (RenderObject* o = root; o; o = o->nextInPreOrder(root)) {
483        ++totalObjects;
484        if (o->needsLayout())
485            ++needsLayoutObjects;
486    }
487}
488
489String LocalFrame::layerTreeAsText(LayerTreeFlags flags) const
490{
491    TextStream textStream;
492    textStream << localLayerTreeAsText(flags);
493
494    for (Frame* child = tree().firstChild(); child; child = child->tree().traverseNext(this)) {
495        if (!child->isLocalFrame())
496            continue;
497        String childLayerTree = toLocalFrame(child)->localLayerTreeAsText(flags);
498        if (!childLayerTree.length())
499            continue;
500
501        textStream << "\n\n--------\nFrame: '";
502        textStream << child->tree().uniqueName();
503        textStream << "'\n--------\n";
504        textStream << childLayerTree;
505    }
506
507    return textStream.release();
508}
509
510String LocalFrame::localLayerTreeAsText(unsigned flags) const
511{
512    if (!contentRenderer())
513        return String();
514
515    return contentRenderer()->compositor()->layerTreeAsText(static_cast<LayerTreeFlags>(flags));
516}
517
518void LocalFrame::setPageZoomFactor(float factor)
519{
520    setPageAndTextZoomFactors(factor, m_textZoomFactor);
521}
522
523void LocalFrame::setTextZoomFactor(float factor)
524{
525    setPageAndTextZoomFactors(m_pageZoomFactor, factor);
526}
527
528void LocalFrame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor)
529{
530    if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
531        return;
532
533    Page* page = this->page();
534    if (!page)
535        return;
536
537    Document* document = this->document();
538    if (!document)
539        return;
540
541    // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents.
542    // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification.
543    if (document->isSVGDocument()) {
544        if (!document->accessSVGExtensions().zoomAndPanEnabled())
545            return;
546    }
547
548    if (m_pageZoomFactor != pageZoomFactor) {
549        if (FrameView* view = this->view()) {
550            // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
551            LayoutPoint scrollPosition = view->scrollPosition();
552            float percentDifference = (pageZoomFactor / m_pageZoomFactor);
553            view->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference));
554        }
555    }
556
557    m_pageZoomFactor = pageZoomFactor;
558    m_textZoomFactor = textZoomFactor;
559
560    for (RefPtrWillBeRawPtr<Frame> child = tree().firstChild(); child; child = child->tree().nextSibling()) {
561        if (child->isLocalFrame())
562            toLocalFrame(child.get())->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor);
563    }
564
565    document->setNeedsStyleRecalc(SubtreeStyleChange);
566    document->updateLayoutIgnorePendingStylesheets();
567}
568
569void LocalFrame::deviceOrPageScaleFactorChanged()
570{
571    document()->mediaQueryAffectingValueChanged();
572    for (RefPtrWillBeRawPtr<Frame> child = tree().firstChild(); child; child = child->tree().nextSibling()) {
573        if (child->isLocalFrame())
574            toLocalFrame(child.get())->deviceOrPageScaleFactorChanged();
575    }
576}
577
578bool LocalFrame::isURLAllowed(const KURL& url) const
579{
580    // We allow one level of self-reference because some sites depend on that,
581    // but we don't allow more than one.
582    if (page()->subframeCount() >= Page::maxNumberOfFrames)
583        return false;
584    bool foundSelfReference = false;
585    for (const Frame* frame = this; frame; frame = frame->tree().parent()) {
586        if (!frame->isLocalFrame())
587            continue;
588        if (equalIgnoringFragmentIdentifier(toLocalFrame(frame)->document()->url(), url)) {
589            if (foundSelfReference)
590                return false;
591            foundSelfReference = true;
592        }
593    }
594    return true;
595}
596
597bool LocalFrame::shouldReuseDefaultView(const KURL& url) const
598{
599    return loader().stateMachine()->isDisplayingInitialEmptyDocument() && document()->isSecureTransitionTo(url);
600}
601
602void LocalFrame::removeSpellingMarkersUnderWords(const Vector<String>& words)
603{
604    spellChecker().removeSpellingMarkersUnderWords(words);
605}
606
607struct ScopedFramePaintingState {
608    ScopedFramePaintingState(LocalFrame* frame, Node* node)
609        : frame(frame)
610        , node(node)
611        , paintBehavior(frame->view()->paintBehavior())
612    {
613        ASSERT(!node || node->renderer());
614        if (node)
615            node->renderer()->updateDragState(true);
616    }
617
618    ~ScopedFramePaintingState()
619    {
620        if (node && node->renderer())
621            node->renderer()->updateDragState(false);
622        frame->view()->setPaintBehavior(paintBehavior);
623        frame->view()->setNodeToDraw(0);
624    }
625
626    LocalFrame* frame;
627    Node* node;
628    PaintBehavior paintBehavior;
629};
630
631PassOwnPtr<DragImage> LocalFrame::nodeImage(Node& node)
632{
633    if (!node.renderer())
634        return nullptr;
635
636    const ScopedFramePaintingState state(this, &node);
637
638    m_view->updateLayoutAndStyleForPainting();
639
640    m_view->setPaintBehavior(state.paintBehavior | PaintBehaviorFlattenCompositingLayers);
641
642    m_view->setNodeToDraw(&node); // Enable special sub-tree drawing mode.
643
644    // Document::updateLayout may have blown away the original RenderObject.
645    RenderObject* renderer = node.renderer();
646    if (!renderer)
647        return nullptr;
648
649    LayoutRect topLevelRect;
650    IntRect paintingRect = pixelSnappedIntRect(renderer->paintingRootRect(topLevelRect));
651
652    ASSERT(document()->isActive());
653    float deviceScaleFactor = m_host->deviceScaleFactor();
654    paintingRect.setWidth(paintingRect.width() * deviceScaleFactor);
655    paintingRect.setHeight(paintingRect.height() * deviceScaleFactor);
656
657    OwnPtr<ImageBuffer> buffer = ImageBuffer::create(paintingRect.size());
658    if (!buffer)
659        return nullptr;
660    buffer->context()->scale(deviceScaleFactor, deviceScaleFactor);
661    buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
662    buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
663
664    m_view->paintContents(buffer->context(), paintingRect);
665
666    RefPtr<Image> image = buffer->copyImage();
667    return DragImage::create(image.get(), renderer->shouldRespectImageOrientation(), deviceScaleFactor);
668}
669
670PassOwnPtr<DragImage> LocalFrame::dragImageForSelection()
671{
672    if (!selection().isRange())
673        return nullptr;
674
675    const ScopedFramePaintingState state(this, 0);
676    m_view->setPaintBehavior(PaintBehaviorSelectionOnly | PaintBehaviorFlattenCompositingLayers);
677    m_view->updateLayoutAndStyleForPainting();
678
679    IntRect paintingRect = enclosingIntRect(selection().bounds());
680
681    ASSERT(document()->isActive());
682    float deviceScaleFactor = m_host->deviceScaleFactor();
683    paintingRect.setWidth(paintingRect.width() * deviceScaleFactor);
684    paintingRect.setHeight(paintingRect.height() * deviceScaleFactor);
685
686    OwnPtr<ImageBuffer> buffer = ImageBuffer::create(paintingRect.size());
687    if (!buffer)
688        return nullptr;
689    buffer->context()->scale(deviceScaleFactor, deviceScaleFactor);
690    buffer->context()->translate(-paintingRect.x(), -paintingRect.y());
691    buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY()));
692
693    m_view->paintContents(buffer->context(), paintingRect);
694
695    RefPtr<Image> image = buffer->copyImage();
696    return DragImage::create(image.get(), DoNotRespectImageOrientation, deviceScaleFactor);
697}
698
699double LocalFrame::devicePixelRatio() const
700{
701    if (!m_host)
702        return 0;
703
704    double ratio = m_host->deviceScaleFactor();
705    ratio *= pageZoomFactor();
706    return ratio;
707}
708
709void LocalFrame::disconnectOwnerElement()
710{
711    if (owner()) {
712        if (Document* document = this->document())
713            document->topDocument().clearAXObjectCache();
714#if ENABLE(OILPAN)
715        // Clear the FrameView and FrameLoader right here rather than
716        // during finalization. Too late to access various heap objects
717        // at that stage.
718        setView(nullptr);
719        loader().clear();
720#endif
721    }
722    Frame::disconnectOwnerElement();
723}
724
725LocalFrame* LocalFrame::localFrameRoot()
726{
727    LocalFrame* curFrame = this;
728    while (curFrame && curFrame->tree().parent() && curFrame->tree().parent()->isLocalFrame())
729        curFrame = toLocalFrame(curFrame->tree().parent());
730
731    return curFrame;
732}
733
734void LocalFrame::setPagePopupOwner(Element& owner)
735{
736    m_pagePopupOwner = &owner;
737}
738
739} // namespace blink
740