1 /* 2 * Copyright (C) 1998, 1999 Torben Weis <weis (at) kde.org> 3 * 1999 Lars Knoll <knoll (at) kde.org> 4 * 1999 Antti Koivisto <koivisto (at) kde.org> 5 * 2000 Simon Hausmann <hausmann (at) kde.org> 6 * 2000 Stefan Schimanski <1Stein (at) gmx.de> 7 * 2001 George Staikos <staikos (at) 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 (at) nypop.com> 10 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 11 * Copyright (C) 2008 Eric Seidel <eric (at) 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/page/Frame.h" 32 33 #include "RuntimeEnabledFeatures.h" 34 #include "bindings/v8/ScriptController.h" 35 #include "core/dom/DocumentType.h" 36 #include "core/dom/Event.h" 37 #include "core/editing/Editor.h" 38 #include "core/editing/FrameSelection.h" 39 #include "core/editing/InputMethodController.h" 40 #include "core/editing/htmlediting.h" 41 #include "core/editing/markup.h" 42 #include "core/html/HTMLFrameElementBase.h" 43 #include "core/loader/FrameLoader.h" 44 #include "core/loader/FrameLoaderClient.h" 45 #include "core/loader/cache/ResourceFetcher.h" 46 #include "core/page/Chrome.h" 47 #include "core/page/ChromeClient.h" 48 #include "core/page/DOMWindow.h" 49 #include "core/page/EventHandler.h" 50 #include "core/page/FocusController.h" 51 #include "core/page/FrameDestructionObserver.h" 52 #include "core/page/FrameView.h" 53 #include "core/page/Page.h" 54 #include "core/page/Settings.h" 55 #include "core/page/animation/AnimationController.h" 56 #include "core/page/scrolling/ScrollingCoordinator.h" 57 #include "core/platform/DragImage.h" 58 #include "core/platform/graphics/GraphicsContext.h" 59 #include "core/platform/graphics/ImageBuffer.h" 60 #include "core/rendering/HitTestResult.h" 61 #include "core/rendering/RenderLayerCompositor.h" 62 #include "core/rendering/RenderPart.h" 63 #include "core/rendering/RenderView.h" 64 #include "core/svg/SVGDocument.h" 65 #include "wtf/PassOwnPtr.h" 66 #include "wtf/RefCountedLeakCounter.h" 67 #include "wtf/StdLibExtras.h" 68 69 using namespace std; 70 71 namespace WebCore { 72 73 using namespace HTMLNames; 74 75 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, frameCounter, ("Frame")); 76 77 static inline Frame* parentFromOwnerElement(HTMLFrameOwnerElement* ownerElement) 78 { 79 if (!ownerElement) 80 return 0; 81 return ownerElement->document()->frame(); 82 } 83 84 static inline float parentPageZoomFactor(Frame* frame) 85 { 86 Frame* parent = frame->tree()->parent(); 87 if (!parent) 88 return 1; 89 return parent->pageZoomFactor(); 90 } 91 92 static inline float parentTextZoomFactor(Frame* frame) 93 { 94 Frame* parent = frame->tree()->parent(); 95 if (!parent) 96 return 1; 97 return parent->textZoomFactor(); 98 } 99 100 inline Frame::Frame(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* frameLoaderClient) 101 : m_page(page) 102 , m_treeNode(this, parentFromOwnerElement(ownerElement)) 103 , m_loader(this, frameLoaderClient) 104 , m_navigationScheduler(this) 105 , m_ownerElement(ownerElement) 106 , m_script(adoptPtr(new ScriptController(this))) 107 , m_editor(adoptPtr(new Editor(this))) 108 , m_selection(adoptPtr(new FrameSelection(this))) 109 , m_eventHandler(adoptPtr(new EventHandler(this))) 110 , m_animationController(adoptPtr(new AnimationController(this))) 111 , m_inputMethodController(InputMethodController::create(this)) 112 , m_pageZoomFactor(parentPageZoomFactor(this)) 113 , m_textZoomFactor(parentTextZoomFactor(this)) 114 #if ENABLE(ORIENTATION_EVENTS) 115 , m_orientation(0) 116 #endif 117 , m_inViewSourceMode(false) 118 { 119 ASSERT(page); 120 121 if (ownerElement) { 122 page->incrementSubframeCount(); 123 ownerElement->setContentFrame(this); 124 } 125 126 #ifndef NDEBUG 127 frameCounter.increment(); 128 #endif 129 } 130 131 PassRefPtr<Frame> Frame::create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client) 132 { 133 RefPtr<Frame> frame = adoptRef(new Frame(page, ownerElement, client)); 134 if (!ownerElement) 135 page->setMainFrame(frame); 136 return frame.release(); 137 } 138 139 Frame::~Frame() 140 { 141 setView(0); 142 loader()->cancelAndClear(); 143 144 // FIXME: We should not be doing all this work inside the destructor 145 146 #ifndef NDEBUG 147 frameCounter.decrement(); 148 #endif 149 150 disconnectOwnerElement(); 151 152 HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end(); 153 for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it) 154 (*it)->frameDestroyed(); 155 } 156 157 bool Frame::inScope(TreeScope* scope) const 158 { 159 ASSERT(scope); 160 Document* doc = document(); 161 if (!doc) 162 return false; 163 HTMLFrameOwnerElement* owner = doc->ownerElement(); 164 if (!owner) 165 return false; 166 return owner->treeScope() == scope; 167 } 168 169 void Frame::addDestructionObserver(FrameDestructionObserver* observer) 170 { 171 m_destructionObservers.add(observer); 172 } 173 174 void Frame::removeDestructionObserver(FrameDestructionObserver* observer) 175 { 176 m_destructionObservers.remove(observer); 177 } 178 179 void Frame::setView(PassRefPtr<FrameView> view) 180 { 181 // We the custom scroll bars as early as possible to prevent m_doc->detach() 182 // from messing with the view such that its scroll bars won't be torn down. 183 // FIXME: We should revisit this. 184 if (m_view) 185 m_view->prepareForDetach(); 186 187 // Prepare for destruction now, so any unload event handlers get run and the DOMWindow is 188 // notified. If we wait until the view is destroyed, then things won't be hooked up enough for 189 // these calls to work. 190 if (!view && document() && document()->attached()) { 191 // FIXME: We don't call willRemove here. Why is that OK? 192 document()->prepareForDestruction(); 193 } 194 195 if (m_view) 196 m_view->unscheduleRelayout(); 197 198 eventHandler()->clear(); 199 200 m_view = view; 201 202 if (m_view && m_page && m_page->mainFrame() == this) 203 m_view->setVisibleContentScaleFactor(m_page->pageScaleFactor()); 204 205 // Only one form submission is allowed per view of a part. 206 // Since this part may be getting reused as a result of being 207 // pulled from the back/forward cache, reset this flag. 208 loader()->resetMultipleFormSubmissionProtection(); 209 } 210 211 #if ENABLE(ORIENTATION_EVENTS) 212 void Frame::sendOrientationChangeEvent(int orientation) 213 { 214 m_orientation = orientation; 215 if (Document* doc = document()) 216 doc->dispatchWindowEvent(Event::create(eventNames().orientationchangeEvent, false, false)); 217 } 218 #endif // ENABLE(ORIENTATION_EVENTS) 219 220 Settings* Frame::settings() const 221 { 222 return m_page ? m_page->settings() : 0; 223 } 224 225 void Frame::setPrinting(bool printing, const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkRatio, AdjustViewSizeOrNot shouldAdjustViewSize) 226 { 227 // In setting printing, we should not validate resources already cached for the document. 228 // See https://bugs.webkit.org/show_bug.cgi?id=43704 229 ResourceCacheValidationSuppressor validationSuppressor(document()->fetcher()); 230 231 document()->setPrinting(printing); 232 view()->adjustMediaTypeForPrinting(printing); 233 234 document()->styleResolverChanged(RecalcStyleImmediately); 235 if (shouldUsePrintingLayout()) { 236 view()->forceLayoutForPagination(pageSize, originalPageSize, maximumShrinkRatio, shouldAdjustViewSize); 237 } else { 238 view()->forceLayout(); 239 if (shouldAdjustViewSize == AdjustViewSize) 240 view()->adjustViewSize(); 241 } 242 243 // Subframes of the one we're printing don't lay out to the page size. 244 for (RefPtr<Frame> child = tree()->firstChild(); child; child = child->tree()->nextSibling()) 245 child->setPrinting(printing, FloatSize(), FloatSize(), 0, shouldAdjustViewSize); 246 } 247 248 bool Frame::shouldUsePrintingLayout() const 249 { 250 // Only top frame being printed should be fit to page size. 251 // Subframes should be constrained by parents only. 252 return document()->printing() && (!tree()->parent() || !tree()->parent()->document()->printing()); 253 } 254 255 FloatSize Frame::resizePageRectsKeepingRatio(const FloatSize& originalSize, const FloatSize& expectedSize) 256 { 257 FloatSize resultSize; 258 if (!contentRenderer()) 259 return FloatSize(); 260 261 if (contentRenderer()->style()->isHorizontalWritingMode()) { 262 ASSERT(fabs(originalSize.width()) > numeric_limits<float>::epsilon()); 263 float ratio = originalSize.height() / originalSize.width(); 264 resultSize.setWidth(floorf(expectedSize.width())); 265 resultSize.setHeight(floorf(resultSize.width() * ratio)); 266 } else { 267 ASSERT(fabs(originalSize.height()) > numeric_limits<float>::epsilon()); 268 float ratio = originalSize.width() / originalSize.height(); 269 resultSize.setHeight(floorf(expectedSize.height())); 270 resultSize.setWidth(floorf(resultSize.height() * ratio)); 271 } 272 return resultSize; 273 } 274 275 void Frame::setDOMWindow(PassRefPtr<DOMWindow> domWindow) 276 { 277 m_domWindow = domWindow; 278 } 279 280 Document* Frame::document() const 281 { 282 return m_domWindow ? m_domWindow->document() : 0; 283 } 284 285 RenderView* Frame::contentRenderer() const 286 { 287 return document() ? document()->renderView() : 0; 288 } 289 290 RenderPart* Frame::ownerRenderer() const 291 { 292 HTMLFrameOwnerElement* ownerElement = m_ownerElement; 293 if (!ownerElement) 294 return 0; 295 RenderObject* object = ownerElement->renderer(); 296 if (!object) 297 return 0; 298 // FIXME: If <object> is ever fixed to disassociate itself from frames 299 // that it has started but canceled, then this can turn into an ASSERT 300 // since m_ownerElement would be 0 when the load is canceled. 301 // https://bugs.webkit.org/show_bug.cgi?id=18585 302 if (!object->isRenderPart()) 303 return 0; 304 return toRenderPart(object); 305 } 306 307 Frame* Frame::frameForWidget(const Widget* widget) 308 { 309 ASSERT_ARG(widget, widget); 310 311 if (RenderWidget* renderer = RenderWidget::find(widget)) 312 if (Node* node = renderer->node()) 313 return node->document()->frame(); 314 315 // Assume all widgets are either a FrameView or owned by a RenderWidget. 316 // FIXME: That assumption is not right for scroll bars! 317 ASSERT_WITH_SECURITY_IMPLICATION(widget->isFrameView()); 318 return toFrameView(widget)->frame(); 319 } 320 321 void Frame::clearTimers(FrameView *view, Document *document) 322 { 323 if (view) { 324 view->unscheduleRelayout(); 325 if (view->frame()) { 326 if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled()) 327 view->frame()->animation()->suspendAnimationsForDocument(document); 328 view->frame()->eventHandler()->stopAutoscrollTimer(); 329 } 330 } 331 } 332 333 void Frame::clearTimers() 334 { 335 clearTimers(m_view.get(), document()); 336 } 337 338 void Frame::dispatchVisibilityStateChangeEvent() 339 { 340 if (document()) 341 document()->dispatchVisibilityStateChangeEvent(); 342 343 Vector<RefPtr<Frame> > childFrames; 344 for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling()) 345 childFrames.append(child); 346 347 for (size_t i = 0; i < childFrames.size(); ++i) 348 childFrames[i]->dispatchVisibilityStateChangeEvent(); 349 } 350 351 void Frame::willDetachPage() 352 { 353 // We should never be detatching the page during a Layout. 354 RELEASE_ASSERT(!m_view || !m_view->isInLayout()); 355 356 if (Frame* parent = tree()->parent()) 357 parent->loader()->checkLoadComplete(); 358 359 HashSet<FrameDestructionObserver*>::iterator stop = m_destructionObservers.end(); 360 for (HashSet<FrameDestructionObserver*>::iterator it = m_destructionObservers.begin(); it != stop; ++it) 361 (*it)->willDetachPage(); 362 363 // FIXME: It's unclear as to why this is called more than once, but it is, 364 // so page() could be NULL. 365 if (page() && page()->focusController().focusedFrame() == this) 366 page()->focusController().setFocusedFrame(0); 367 368 if (page() && page()->scrollingCoordinator() && m_view) 369 page()->scrollingCoordinator()->willDestroyScrollableArea(m_view.get()); 370 371 script()->clearScriptObjects(); 372 } 373 374 void Frame::detachFromPage() 375 { 376 // We should never be detatching the page during a Layout. 377 RELEASE_ASSERT(!m_view || !m_view->isInLayout()); 378 m_page = 0; 379 } 380 381 void Frame::disconnectOwnerElement() 382 { 383 if (m_ownerElement) { 384 if (Document* doc = document()) 385 doc->topDocument()->clearAXObjectCache(); 386 m_ownerElement->clearContentFrame(); 387 if (m_page) 388 m_page->decrementSubframeCount(); 389 } 390 m_ownerElement = 0; 391 } 392 393 String Frame::documentTypeString() const 394 { 395 if (DocumentType* doctype = document()->doctype()) 396 return createMarkup(doctype); 397 398 return String(); 399 } 400 401 String Frame::displayStringModifiedByEncoding(const String& str) const 402 { 403 return document() ? document()->displayStringModifiedByEncoding(str) : str; 404 } 405 406 String Frame::selectedText() const 407 { 408 return selection()->selectedText(); 409 } 410 411 String Frame::selectedTextForClipboard() const 412 { 413 return selection()->selectedTextForClipboard(); 414 } 415 416 VisiblePosition Frame::visiblePositionForPoint(const IntPoint& framePoint) 417 { 418 HitTestResult result = eventHandler()->hitTestResultAtPoint(framePoint); 419 Node* node = result.innerNonSharedNode(); 420 if (!node) 421 return VisiblePosition(); 422 RenderObject* renderer = node->renderer(); 423 if (!renderer) 424 return VisiblePosition(); 425 VisiblePosition visiblePos = VisiblePosition(renderer->positionForPoint(result.localPoint())); 426 if (visiblePos.isNull()) 427 visiblePos = firstPositionInOrBeforeNode(node); 428 return visiblePos; 429 } 430 431 Document* Frame::documentAtPoint(const IntPoint& point) 432 { 433 if (!view()) 434 return 0; 435 436 IntPoint pt = view()->windowToContents(point); 437 HitTestResult result = HitTestResult(pt); 438 439 if (contentRenderer()) 440 result = eventHandler()->hitTestResultAtPoint(pt, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent); 441 return result.innerNode() ? result.innerNode()->document() : 0; 442 } 443 444 PassRefPtr<Range> Frame::rangeForPoint(const IntPoint& framePoint) 445 { 446 VisiblePosition position = visiblePositionForPoint(framePoint); 447 if (position.isNull()) 448 return 0; 449 450 VisiblePosition previous = position.previous(); 451 if (previous.isNotNull()) { 452 RefPtr<Range> previousCharacterRange = makeRange(previous, position); 453 LayoutRect rect = editor()->firstRectForRange(previousCharacterRange.get()); 454 if (rect.contains(framePoint)) 455 return previousCharacterRange.release(); 456 } 457 458 VisiblePosition next = position.next(); 459 if (RefPtr<Range> nextCharacterRange = makeRange(position, next)) { 460 LayoutRect rect = editor()->firstRectForRange(nextCharacterRange.get()); 461 if (rect.contains(framePoint)) 462 return nextCharacterRange.release(); 463 } 464 465 return 0; 466 } 467 468 void Frame::createView(const IntSize& viewportSize, const StyleColor& backgroundColor, bool transparent, 469 const IntSize& fixedLayoutSize, bool useFixedLayout, ScrollbarMode horizontalScrollbarMode, bool horizontalLock, 470 ScrollbarMode verticalScrollbarMode, bool verticalLock) 471 { 472 ASSERT(this); 473 ASSERT(m_page); 474 475 bool isMainFrame = this == m_page->mainFrame(); 476 477 if (isMainFrame && view()) 478 view()->setParentVisible(false); 479 480 setView(0); 481 482 RefPtr<FrameView> frameView; 483 if (isMainFrame) { 484 frameView = FrameView::create(this, viewportSize); 485 frameView->setFixedLayoutSize(fixedLayoutSize); 486 frameView->setUseFixedLayout(useFixedLayout); 487 } else 488 frameView = FrameView::create(this); 489 490 frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock); 491 492 setView(frameView); 493 494 if (backgroundColor.isValid()) 495 frameView->updateBackgroundRecursively(backgroundColor.color(), transparent); 496 497 if (isMainFrame) 498 frameView->setParentVisible(true); 499 500 if (ownerRenderer()) 501 ownerRenderer()->setWidget(frameView); 502 503 if (HTMLFrameOwnerElement* owner = ownerElement()) 504 view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff); 505 } 506 507 String Frame::layerTreeAsText(unsigned flags) const 508 { 509 document()->updateLayout(); 510 511 if (!contentRenderer()) 512 return String(); 513 514 return contentRenderer()->compositor()->layerTreeAsText(static_cast<LayerTreeFlags>(flags)); 515 } 516 517 String Frame::trackedRepaintRectsAsText() const 518 { 519 if (!m_view) 520 return String(); 521 return m_view->trackedRepaintRectsAsText(); 522 } 523 524 void Frame::setPageZoomFactor(float factor) 525 { 526 setPageAndTextZoomFactors(factor, m_textZoomFactor); 527 } 528 529 void Frame::setTextZoomFactor(float factor) 530 { 531 setPageAndTextZoomFactors(m_pageZoomFactor, factor); 532 } 533 534 void Frame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor) 535 { 536 if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor) 537 return; 538 539 Page* page = this->page(); 540 if (!page) 541 return; 542 543 Document* document = this->document(); 544 if (!document) 545 return; 546 547 // Respect SVGs zoomAndPan="disabled" property in standalone SVG documents. 548 // FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification. 549 if (document->isSVGDocument()) { 550 if (!toSVGDocument(document)->zoomAndPanEnabled()) 551 return; 552 } 553 554 if (m_pageZoomFactor != pageZoomFactor) { 555 if (FrameView* view = this->view()) { 556 // Update the scroll position when doing a full page zoom, so the content stays in relatively the same position. 557 LayoutPoint scrollPosition = view->scrollPosition(); 558 float percentDifference = (pageZoomFactor / m_pageZoomFactor); 559 view->setScrollPosition(IntPoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference)); 560 } 561 } 562 563 m_pageZoomFactor = pageZoomFactor; 564 m_textZoomFactor = textZoomFactor; 565 566 document->recalcStyle(Node::Force); 567 568 for (RefPtr<Frame> child = tree()->firstChild(); child; child = child->tree()->nextSibling()) 569 child->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor); 570 571 if (FrameView* view = this->view()) { 572 if (document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout()) 573 view->layout(); 574 } 575 } 576 577 void Frame::deviceOrPageScaleFactorChanged() 578 { 579 for (RefPtr<Frame> child = tree()->firstChild(); child; child = child->tree()->nextSibling()) 580 child->deviceOrPageScaleFactorChanged(); 581 582 m_page->chrome().client()->deviceOrPageScaleFactorChanged(); 583 } 584 585 void Frame::notifyChromeClientWheelEventHandlerCountChanged() const 586 { 587 // Ensure that this method is being called on the main frame of the page. 588 ASSERT(m_page && m_page->mainFrame() == this); 589 590 unsigned count = 0; 591 for (const Frame* frame = this; frame; frame = frame->tree()->traverseNext()) { 592 if (frame->document()) 593 count += frame->document()->wheelEventHandlerCount(); 594 } 595 596 m_page->chrome().client()->numWheelEventHandlersChanged(count); 597 } 598 599 bool Frame::isURLAllowed(const KURL& url) const 600 { 601 // We allow one level of self-reference because some sites depend on that, 602 // but we don't allow more than one. 603 if (m_page->subframeCount() >= Page::maxNumberOfFrames) 604 return false; 605 bool foundSelfReference = false; 606 for (const Frame* frame = this; frame; frame = frame->tree()->parent()) { 607 if (equalIgnoringFragmentIdentifier(frame->document()->url(), url)) { 608 if (foundSelfReference) 609 return false; 610 foundSelfReference = true; 611 } 612 } 613 return true; 614 } 615 616 struct ScopedFramePaintingState { 617 ScopedFramePaintingState(Frame* frame, Node* node) 618 : frame(frame) 619 , node(node) 620 , paintBehavior(frame->view()->paintBehavior()) 621 , backgroundColor(frame->view()->baseBackgroundColor()) 622 { 623 ASSERT(!node || node->renderer()); 624 if (node) 625 node->renderer()->updateDragState(true); 626 } 627 628 ~ScopedFramePaintingState() 629 { 630 if (node && node->renderer()) 631 node->renderer()->updateDragState(false); 632 frame->view()->setPaintBehavior(paintBehavior); 633 frame->view()->setBaseBackgroundColor(backgroundColor); 634 frame->view()->setNodeToDraw(0); 635 } 636 637 Frame* frame; 638 Node* node; 639 PaintBehavior paintBehavior; 640 Color backgroundColor; 641 }; 642 643 PassOwnPtr<DragImage> Frame::nodeImage(Node* node) 644 { 645 if (!node->renderer()) 646 return nullptr; 647 648 const ScopedFramePaintingState state(this, node); 649 650 m_view->setPaintBehavior(state.paintBehavior | PaintBehaviorFlattenCompositingLayers); 651 652 // When generating the drag image for an element, ignore the document background. 653 m_view->setBaseBackgroundColor(Color::transparent); 654 document()->updateLayout(); 655 m_view->setNodeToDraw(node); // Enable special sub-tree drawing mode. 656 657 // Document::updateLayout may have blown away the original RenderObject. 658 RenderObject* renderer = node->renderer(); 659 if (!renderer) 660 return nullptr; 661 662 LayoutRect topLevelRect; 663 IntRect paintingRect = pixelSnappedIntRect(renderer->paintingRootRect(topLevelRect)); 664 665 float deviceScaleFactor = 1; 666 if (m_page) 667 deviceScaleFactor = m_page->deviceScaleFactor(); 668 paintingRect.setWidth(paintingRect.width() * deviceScaleFactor); 669 paintingRect.setHeight(paintingRect.height() * deviceScaleFactor); 670 671 OwnPtr<ImageBuffer> buffer(ImageBuffer::create(paintingRect.size(), deviceScaleFactor)); 672 if (!buffer) 673 return nullptr; 674 buffer->context()->translate(-paintingRect.x(), -paintingRect.y()); 675 buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY())); 676 677 m_view->paintContents(buffer->context(), paintingRect); 678 679 RefPtr<Image> image = buffer->copyImage(); 680 return DragImage::create(image.get(), renderer->shouldRespectImageOrientation()); 681 } 682 683 PassOwnPtr<DragImage> Frame::dragImageForSelection() 684 { 685 if (!selection()->isRange()) 686 return nullptr; 687 688 const ScopedFramePaintingState state(this, 0); 689 m_view->setPaintBehavior(PaintBehaviorSelectionOnly | PaintBehaviorFlattenCompositingLayers); 690 document()->updateLayout(); 691 692 IntRect paintingRect = enclosingIntRect(selection()->bounds()); 693 694 float deviceScaleFactor = 1; 695 if (m_page) 696 deviceScaleFactor = m_page->deviceScaleFactor(); 697 paintingRect.setWidth(paintingRect.width() * deviceScaleFactor); 698 paintingRect.setHeight(paintingRect.height() * deviceScaleFactor); 699 700 OwnPtr<ImageBuffer> buffer(ImageBuffer::create(paintingRect.size(), deviceScaleFactor)); 701 if (!buffer) 702 return nullptr; 703 buffer->context()->translate(-paintingRect.x(), -paintingRect.y()); 704 buffer->context()->clip(FloatRect(0, 0, paintingRect.maxX(), paintingRect.maxY())); 705 706 m_view->paintContents(buffer->context(), paintingRect); 707 708 RefPtr<Image> image = buffer->copyImage(); 709 return DragImage::create(image.get()); 710 } 711 712 } // namespace WebCore 713