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