1/* 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 3 * (C) 2000 Simon Hausmann <hausmann@kde.org> 4 * (C) 2000 Stefan Schimanski (1Stein@gmx.de) 5 * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 Apple Inc. All rights reserved. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Library General Public 9 * License as published by the Free Software Foundation; either 10 * version 2 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Library General Public License for more details. 16 * 17 * You should have received a copy of the GNU Library General Public License 18 * along with this library; see the file COPYING.LIB. If not, write to 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 * Boston, MA 02110-1301, USA. 21 * 22 */ 23 24#include "config.h" 25#include "RenderEmbeddedObject.h" 26 27#include "CSSValueKeywords.h" 28#include "Chrome.h" 29#include "ChromeClient.h" 30#include "Cursor.h" 31#include "EventHandler.h" 32#include "Font.h" 33#include "FontSelector.h" 34#include "Frame.h" 35#include "FrameLoaderClient.h" 36#include "GraphicsContext.h" 37#include "HTMLAppletElement.h" 38#include "HTMLEmbedElement.h" 39#include "HTMLIFrameElement.h" 40#include "HTMLNames.h" 41#include "HTMLObjectElement.h" 42#include "HTMLParamElement.h" 43#include "HTMLPlugInElement.h" 44#include "HitTestResult.h" 45#include "LocalizedStrings.h" 46#include "MIMETypeRegistry.h" 47#include "MouseEvent.h" 48#include "Page.h" 49#include "PaintInfo.h" 50#include "Path.h" 51#include "PlatformMouseEvent.h" 52#include "PluginViewBase.h" 53#include "RenderLayer.h" 54#include "RenderTheme.h" 55#include "RenderView.h" 56#include "Settings.h" 57#include "Text.h" 58#include "TextRun.h" 59#include <wtf/StackStats.h> 60 61namespace WebCore { 62 63using namespace HTMLNames; 64 65static const float replacementTextRoundedRectHeight = 22; 66static const float replacementTextRoundedRectLeftTextMargin = 10; 67static const float replacementTextRoundedRectRightTextMargin = 10; 68static const float replacementTextRoundedRectRightTextMarginWithArrow = 5; 69static const float replacementTextRoundedRectTopTextMargin = -1; 70static const float replacementTextRoundedRectRadius = 11; 71static const float replacementArrowLeftMargin = -4; 72static const float replacementArrowPadding = 4; 73static const float replacementArrowCirclePadding = 3; 74 75static const Color& replacementTextRoundedRectPressedColor() 76{ 77 static const Color pressed(105, 105, 105, 242); 78 return pressed; 79} 80 81static const Color& replacementTextRoundedRectColor() 82{ 83 static const Color standard(125, 125, 125, 242); 84 return standard; 85} 86 87static const Color& replacementTextColor() 88{ 89 static const Color standard(240, 240, 240, 255); 90 return standard; 91} 92 93static const Color& unavailablePluginBorderColor() 94{ 95 static const Color standard(255, 255, 255, 216); 96 return standard; 97} 98 99RenderEmbeddedObject::RenderEmbeddedObject(HTMLFrameOwnerElement& element, PassRef<RenderStyle> style) 100 : RenderWidget(element, WTF::move(style)) 101 , m_isPluginUnavailable(false) 102 , m_isUnavailablePluginIndicatorHidden(false) 103 , m_unavailablePluginIndicatorIsPressed(false) 104 , m_mouseDownWasInUnavailablePluginIndicator(false) 105{ 106 // Actual size is not known yet, report the default intrinsic size. 107 view().frameView().incrementVisuallyNonEmptyPixelCount(roundedIntSize(intrinsicSize())); 108} 109 110RenderEmbeddedObject::~RenderEmbeddedObject() 111{ 112 view().frameView().removeEmbeddedObjectToUpdate(*this); 113} 114 115RenderPtr<RenderEmbeddedObject> RenderEmbeddedObject::createForApplet(HTMLAppletElement& applet, PassRef<RenderStyle> style) 116{ 117 auto renderer = createRenderer<RenderEmbeddedObject>(applet, WTF::move(style)); 118 renderer->setInline(true); 119 return renderer; 120} 121 122bool RenderEmbeddedObject::requiresLayer() const 123{ 124 if (RenderWidget::requiresLayer()) 125 return true; 126 127 return allowsAcceleratedCompositing(); 128} 129 130bool RenderEmbeddedObject::allowsAcceleratedCompositing() const 131{ 132#if PLATFORM(IOS) 133 // The timing of layer creation is different on the phone, since the plugin can only be manipulated from the main thread. 134 return widget() && widget()->isPluginViewBase() && toPluginViewBase(widget())->willProvidePluginLayer(); 135#else 136 return widget() && widget()->isPluginViewBase() && toPluginViewBase(widget())->platformLayer(); 137#endif 138} 139 140#if !PLATFORM(IOS) 141static String unavailablePluginReplacementText(RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason) 142{ 143 switch (pluginUnavailabilityReason) { 144 case RenderEmbeddedObject::PluginMissing: 145 return missingPluginText(); 146 case RenderEmbeddedObject::PluginCrashed: 147 return crashedPluginText(); 148 case RenderEmbeddedObject::PluginBlockedByContentSecurityPolicy: 149 return blockedPluginByContentSecurityPolicyText(); 150 case RenderEmbeddedObject::InsecurePluginVersion: 151 return insecurePluginVersionText(); 152 } 153 154 ASSERT_NOT_REACHED(); 155 return String(); 156} 157#endif 158 159static bool shouldUnavailablePluginMessageBeButton(Document& document, RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason) 160{ 161 Page* page = document.page(); 162 return page && page->chrome().client().shouldUnavailablePluginMessageBeButton(pluginUnavailabilityReason); 163} 164 165void RenderEmbeddedObject::setPluginUnavailabilityReason(PluginUnavailabilityReason pluginUnavailabilityReason) 166{ 167#if PLATFORM(IOS) 168 UNUSED_PARAM(pluginUnavailabilityReason); 169#else 170 setPluginUnavailabilityReasonWithDescription(pluginUnavailabilityReason, unavailablePluginReplacementText(pluginUnavailabilityReason)); 171#endif 172} 173 174void RenderEmbeddedObject::setPluginUnavailabilityReasonWithDescription(PluginUnavailabilityReason pluginUnavailabilityReason, const String& description) 175{ 176#if PLATFORM(IOS) 177 UNUSED_PARAM(pluginUnavailabilityReason); 178 UNUSED_PARAM(description); 179#else 180 ASSERT(!m_isPluginUnavailable); 181 m_isPluginUnavailable = true; 182 m_pluginUnavailabilityReason = pluginUnavailabilityReason; 183 184 if (description.isEmpty()) 185 m_unavailablePluginReplacementText = unavailablePluginReplacementText(pluginUnavailabilityReason); 186 else 187 m_unavailablePluginReplacementText = description; 188#endif 189} 190 191void RenderEmbeddedObject::setUnavailablePluginIndicatorIsPressed(bool pressed) 192{ 193 if (m_unavailablePluginIndicatorIsPressed == pressed) 194 return; 195 196 m_unavailablePluginIndicatorIsPressed = pressed; 197 repaint(); 198} 199 200void RenderEmbeddedObject::paintSnapshotImage(PaintInfo& paintInfo, const LayoutPoint& paintOffset, Image* image) 201{ 202 LayoutUnit cWidth = contentWidth(); 203 LayoutUnit cHeight = contentHeight(); 204 if (!cWidth || !cHeight) 205 return; 206 207 GraphicsContext* context = paintInfo.context; 208 LayoutSize contentSize(cWidth, cHeight); 209 LayoutPoint contentLocation = location() + paintOffset; 210 contentLocation.move(borderLeft() + paddingLeft(), borderTop() + paddingTop()); 211 212 LayoutRect rect(contentLocation, contentSize); 213 IntRect alignedRect = pixelSnappedIntRect(rect); 214 if (alignedRect.width() <= 0 || alignedRect.height() <= 0) 215 return; 216 217 bool useLowQualityScaling = shouldPaintAtLowQuality(context, image, image, alignedRect.size()); 218 ImageOrientationDescription orientationDescription(shouldRespectImageOrientation()); 219#if ENABLE(CSS_IMAGE_ORIENTATION) 220 orientationDescription.setImageOrientationEnum(style().imageOrientation()); 221#endif 222 context->drawImage(image, style().colorSpace(), alignedRect, ImagePaintingOptions(orientationDescription, useLowQualityScaling)); 223} 224 225void RenderEmbeddedObject::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 226{ 227 if (!frameOwnerElement().isPluginElement()) 228 return; 229 230 HTMLPlugInElement& plugInElement = toHTMLPlugInElement(frameOwnerElement()); 231 232 if (plugInElement.displayState() > HTMLPlugInElement::DisplayingSnapshot) { 233 RenderWidget::paintContents(paintInfo, paintOffset); 234 if (!plugInElement.isRestartedPlugin()) 235 return; 236 } 237 238 if (!plugInElement.isPlugInImageElement()) 239 return; 240 241 Image* snapshot = toHTMLPlugInImageElement(plugInElement).snapshotImage(); 242 if (snapshot) 243 paintSnapshotImage(paintInfo, paintOffset, snapshot); 244} 245 246void RenderEmbeddedObject::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 247{ 248 Page* page = frame().page(); 249 250 if (isPluginUnavailable()) { 251 if (page && paintInfo.phase == PaintPhaseForeground) 252 page->addRelevantUnpaintedObject(this, visualOverflowRect()); 253 RenderReplaced::paint(paintInfo, paintOffset); 254 return; 255 } 256 257 if (page && paintInfo.phase == PaintPhaseForeground) 258 page->addRelevantRepaintedObject(this, visualOverflowRect()); 259 260 RenderWidget::paint(paintInfo, paintOffset); 261} 262 263static void drawReplacementArrow(GraphicsContext* context, const FloatRect& insideRect) 264{ 265 GraphicsContextStateSaver stateSaver(*context); 266 267 FloatRect rect(insideRect); 268 rect.inflate(-replacementArrowPadding); 269 270 FloatPoint center(rect.center()); 271 FloatPoint arrowTip(rect.maxX(), center.y()); 272 273 context->setStrokeThickness(2); 274 context->setLineCap(RoundCap); 275 context->setLineJoin(RoundJoin); 276 277 Path path; 278 path.moveTo(FloatPoint(rect.x(), center.y())); 279 path.addLineTo(arrowTip); 280 path.addLineTo(FloatPoint(center.x(), rect.y())); 281 path.moveTo(arrowTip); 282 path.addLineTo(FloatPoint(center.x(), rect.maxY())); 283 context->strokePath(path); 284} 285 286void RenderEmbeddedObject::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 287{ 288 if (!showsUnavailablePluginIndicator()) 289 return; 290 291 if (paintInfo.phase == PaintPhaseSelection) 292 return; 293 294 GraphicsContext* context = paintInfo.context; 295 if (context->paintingDisabled()) 296 return; 297 298 FloatRect contentRect; 299 FloatRect indicatorRect; 300 FloatRect replacementTextRect; 301 FloatRect arrowRect; 302 Font font; 303 TextRun run(""); 304 float textWidth; 305 if (!getReplacementTextGeometry(paintOffset, contentRect, indicatorRect, replacementTextRect, arrowRect, font, run, textWidth)) 306 return; 307 308 Path background; 309 background.addRoundedRect(indicatorRect, FloatSize(replacementTextRoundedRectRadius, replacementTextRoundedRectRadius)); 310 311 GraphicsContextStateSaver stateSaver(*context); 312 context->clip(contentRect); 313 context->setFillColor(m_unavailablePluginIndicatorIsPressed ? replacementTextRoundedRectPressedColor() : replacementTextRoundedRectColor(), style().colorSpace()); 314 context->fillPath(background); 315 316 Path strokePath; 317 FloatRect strokeRect(indicatorRect); 318 strokeRect.inflate(1); 319 strokePath.addRoundedRect(strokeRect, FloatSize(replacementTextRoundedRectRadius + 1, replacementTextRoundedRectRadius + 1)); 320 321 context->setStrokeColor(unavailablePluginBorderColor(), style().colorSpace()); 322 context->setStrokeThickness(2); 323 context->strokePath(strokePath); 324 325 const FontMetrics& fontMetrics = font.fontMetrics(); 326 float labelX = roundf(replacementTextRect.location().x() + replacementTextRoundedRectLeftTextMargin); 327 float labelY = roundf(replacementTextRect.location().y() + (replacementTextRect.size().height() - fontMetrics.height()) / 2 + fontMetrics.ascent() + replacementTextRoundedRectTopTextMargin); 328 context->setFillColor(replacementTextColor(), style().colorSpace()); 329 context->drawBidiText(font, run, FloatPoint(labelX, labelY)); 330 331 if (shouldUnavailablePluginMessageBeButton(document(), m_pluginUnavailabilityReason)) { 332 arrowRect.inflate(-replacementArrowCirclePadding); 333 334 context->beginTransparencyLayer(1.0); 335 context->setFillColor(replacementTextColor(), style().colorSpace()); 336 context->fillEllipse(arrowRect); 337 338 context->setCompositeOperation(CompositeClear); 339 drawReplacementArrow(context, arrowRect); 340 context->endTransparencyLayer(); 341 } 342} 343 344void RenderEmbeddedObject::setUnavailablePluginIndicatorIsHidden(bool hidden) 345{ 346 m_isUnavailablePluginIndicatorHidden = hidden; 347 348 repaint(); 349} 350 351bool RenderEmbeddedObject::getReplacementTextGeometry(const LayoutPoint& accumulatedOffset, FloatRect& contentRect, FloatRect& indicatorRect, FloatRect& replacementTextRect, FloatRect& arrowRect, Font& font, TextRun& run, float& textWidth) const 352{ 353 bool includesArrow = shouldUnavailablePluginMessageBeButton(document(), m_pluginUnavailabilityReason); 354 355 contentRect = contentBoxRect(); 356 contentRect.moveBy(roundedIntPoint(accumulatedOffset)); 357 358 FontDescription fontDescription; 359 RenderTheme::defaultTheme()->systemFont(CSSValueWebkitSmallControl, fontDescription); 360 fontDescription.setWeight(FontWeightBold); 361 fontDescription.setRenderingMode(frame().settings().fontRenderingMode()); 362 fontDescription.setComputedSize(12); 363 font = Font(fontDescription, 0, 0); 364 font.update(0); 365 366 run = TextRun(m_unavailablePluginReplacementText); 367 textWidth = font.width(run); 368 369 replacementTextRect.setSize(FloatSize(textWidth + replacementTextRoundedRectLeftTextMargin + (includesArrow ? replacementTextRoundedRectRightTextMarginWithArrow : replacementTextRoundedRectRightTextMargin), replacementTextRoundedRectHeight)); 370 float x = (contentRect.size().width() / 2 - replacementTextRect.size().width() / 2) + contentRect.location().x(); 371 float y = (contentRect.size().height() / 2 - replacementTextRect.size().height() / 2) + contentRect.location().y(); 372 replacementTextRect.setLocation(FloatPoint(x, y)); 373 374 indicatorRect = replacementTextRect; 375 376 // Expand the background rect to include the arrow, if it will be used. 377 if (includesArrow) { 378 arrowRect = indicatorRect; 379 arrowRect.setX(ceilf(arrowRect.maxX() + replacementArrowLeftMargin)); 380 arrowRect.setWidth(arrowRect.height()); 381 indicatorRect.unite(arrowRect); 382 } 383 384 return true; 385} 386 387LayoutRect RenderEmbeddedObject::unavailablePluginIndicatorBounds(const LayoutPoint& accumulatedOffset) const 388{ 389 FloatRect contentRect; 390 FloatRect indicatorRect; 391 FloatRect replacementTextRect; 392 FloatRect arrowRect; 393 Font font; 394 TextRun run("", 0); 395 float textWidth; 396 if (getReplacementTextGeometry(accumulatedOffset, contentRect, indicatorRect, replacementTextRect, arrowRect, font, run, textWidth)) 397 return LayoutRect(indicatorRect); 398 399 return LayoutRect(); 400} 401 402bool RenderEmbeddedObject::isReplacementObscured() const 403{ 404 // Return whether or not the replacement content for blocked plugins is accessible to the user. 405 406 // Check the opacity of each layer containing the element or its ancestors. 407 float opacity = 1.0; 408 for (RenderLayer* layer = enclosingLayer(); layer; layer = layer->parent()) { 409 opacity *= layer->renderer().style().opacity(); 410 if (opacity < 0.1) 411 return true; 412 } 413 414 // Calculate the absolute rect for the blocked plugin replacement text. 415 IntRect absoluteBoundingBox = absoluteBoundingBoxRect(); 416 LayoutPoint absoluteLocation(absoluteBoundingBox.location()); 417 LayoutRect rect = unavailablePluginIndicatorBounds(absoluteLocation); 418 if (rect.isEmpty()) 419 return true; 420 421 RenderView* rootRenderView = document().topDocument().renderView(); 422 ASSERT(rootRenderView); 423 if (!rootRenderView) 424 return true; 425 426 IntRect rootViewRect = view().frameView().convertToRootView(pixelSnappedIntRect(rect)); 427 428 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent | HitTestRequest::AllowChildFrameContent); 429 HitTestResult result; 430 HitTestLocation location; 431 432 LayoutUnit x = rootViewRect.x(); 433 LayoutUnit y = rootViewRect.y(); 434 LayoutUnit width = rootViewRect.width(); 435 LayoutUnit height = rootViewRect.height(); 436 437 // Hit test the center and near the corners of the replacement text to ensure 438 // it is visible and is not masked by other elements. 439 bool hit = false; 440 location = LayoutPoint(x + width / 2, y + height / 2); 441 hit = rootRenderView->hitTest(request, location, result); 442 if (!hit || result.innerNode() != &frameOwnerElement()) 443 return true; 444 445 location = LayoutPoint(x, y); 446 hit = rootRenderView->hitTest(request, location, result); 447 if (!hit || result.innerNode() != &frameOwnerElement()) 448 return true; 449 450 location = LayoutPoint(x + width, y); 451 hit = rootRenderView->hitTest(request, location, result); 452 if (!hit || result.innerNode() != &frameOwnerElement()) 453 return true; 454 455 location = LayoutPoint(x + width, y + height); 456 hit = rootRenderView->hitTest(request, location, result); 457 if (!hit || result.innerNode() != &frameOwnerElement()) 458 return true; 459 460 location = LayoutPoint(x, y + height); 461 hit = rootRenderView->hitTest(request, location, result); 462 if (!hit || result.innerNode() != &frameOwnerElement()) 463 return true; 464 465 return false; 466} 467 468void RenderEmbeddedObject::layout() 469{ 470 StackStats::LayoutCheckPoint layoutCheckPoint; 471 ASSERT(needsLayout()); 472 473 LayoutSize oldSize = contentBoxRect().size(); 474 475 updateLogicalWidth(); 476 updateLogicalHeight(); 477 478 RenderWidget::layout(); 479 480 clearOverflow(); 481 addVisualEffectOverflow(); 482 483 updateLayerTransform(); 484 485 bool wasMissingWidget = false; 486 if (!widget() && canHaveWidget()) { 487 wasMissingWidget = true; 488 view().frameView().addEmbeddedObjectToUpdate(*this); 489 } 490 491 clearNeedsLayout(); 492 493 LayoutSize newSize = contentBoxRect().size(); 494 495 if (!wasMissingWidget && newSize.width() >= oldSize.width() && newSize.height() >= oldSize.height()) { 496 HTMLFrameOwnerElement& element = frameOwnerElement(); 497 if (element.isPluginElement() && toHTMLPlugInElement(element).isPlugInImageElement()) { 498 HTMLPlugInImageElement& plugInImageElement = toHTMLPlugInImageElement(element); 499 if (plugInImageElement.displayState() > HTMLPlugInElement::DisplayingSnapshot && plugInImageElement.snapshotDecision() == HTMLPlugInImageElement::MaySnapshotWhenResized) { 500 plugInImageElement.setNeedsCheckForSizeChange(); 501 view().frameView().addEmbeddedObjectToUpdate(*this); 502 } 503 } 504 } 505 506 if (!canHaveChildren()) 507 return; 508 509 // This code copied from RenderMedia::layout(). 510 RenderObject* child = firstChild(); 511 512 if (!child) 513 return; 514 515 RenderBox* childBox = toRenderBox(child); 516 517 if (!childBox) 518 return; 519 520 if (newSize == oldSize && !childBox->needsLayout()) 521 return; 522 523 // When calling layout() on a child node, a parent must either push a LayoutStateMaintainter, or 524 // instantiate LayoutStateDisabler. Since using a LayoutStateMaintainer is slightly more efficient, 525 // and this method will be called many times per second during playback, use a LayoutStateMaintainer: 526 LayoutStateMaintainer statePusher(view(), *this, locationOffset(), hasTransform() || hasReflection() || style().isFlippedBlocksWritingMode()); 527 528 childBox->setLocation(LayoutPoint(borderLeft(), borderTop()) + LayoutSize(paddingLeft(), paddingTop())); 529 childBox->style().setHeight(Length(newSize.height(), Fixed)); 530 childBox->style().setWidth(Length(newSize.width(), Fixed)); 531 childBox->setNeedsLayout(MarkOnlyThis); 532 childBox->layout(); 533 clearChildNeedsLayout(); 534 535 statePusher.pop(); 536} 537 538bool RenderEmbeddedObject::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) 539{ 540 if (!RenderWidget::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, hitTestAction)) 541 return false; 542 543 if (!widget() || !widget()->isPluginViewBase()) 544 return true; 545 546 PluginViewBase* view = toPluginViewBase(widget()); 547 IntPoint roundedPoint = locationInContainer.roundedPoint(); 548 549 if (Scrollbar* horizontalScrollbar = view->horizontalScrollbar()) { 550 if (horizontalScrollbar->shouldParticipateInHitTesting() && horizontalScrollbar->frameRect().contains(roundedPoint)) { 551 result.setScrollbar(horizontalScrollbar); 552 return true; 553 } 554 } 555 556 if (Scrollbar* verticalScrollbar = view->verticalScrollbar()) { 557 if (verticalScrollbar->shouldParticipateInHitTesting() && verticalScrollbar->frameRect().contains(roundedPoint)) { 558 result.setScrollbar(verticalScrollbar); 559 return true; 560 } 561 } 562 563 return true; 564} 565 566bool RenderEmbeddedObject::scroll(ScrollDirection direction, ScrollGranularity granularity, float, Element**, RenderBox*, const IntPoint&) 567{ 568 if (!widget() || !widget()->isPluginViewBase()) 569 return false; 570 571 return toPluginViewBase(widget())->scroll(direction, granularity); 572} 573 574bool RenderEmbeddedObject::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Element** stopElement) 575{ 576 // Plugins don't expose a writing direction, so assuming horizontal LTR. 577 return scroll(logicalToPhysical(direction, true, false), granularity, multiplier, stopElement); 578} 579 580 581bool RenderEmbeddedObject::isInUnavailablePluginIndicator(const LayoutPoint& point) const 582{ 583 FloatRect contentRect; 584 FloatRect indicatorRect; 585 FloatRect replacementTextRect; 586 FloatRect arrowRect; 587 Font font; 588 TextRun run(""); 589 float textWidth; 590 return getReplacementTextGeometry(IntPoint(), contentRect, indicatorRect, replacementTextRect, arrowRect, font, run, textWidth) 591 && indicatorRect.contains(point); 592} 593 594bool RenderEmbeddedObject::isInUnavailablePluginIndicator(MouseEvent* event) const 595{ 596 return isInUnavailablePluginIndicator(roundedLayoutPoint(absoluteToLocal(event->absoluteLocation(), UseTransforms))); 597} 598 599void RenderEmbeddedObject::handleUnavailablePluginIndicatorEvent(Event* event) 600{ 601 if (!shouldUnavailablePluginMessageBeButton(document(), m_pluginUnavailabilityReason)) 602 return; 603 604 if (!event->isMouseEvent()) 605 return; 606 607 MouseEvent* mouseEvent = toMouseEvent(event); 608 HTMLPlugInElement& element = toHTMLPlugInElement(frameOwnerElement()); 609 if (event->type() == eventNames().mousedownEvent && toMouseEvent(event)->button() == LeftButton) { 610 m_mouseDownWasInUnavailablePluginIndicator = isInUnavailablePluginIndicator(mouseEvent); 611 if (m_mouseDownWasInUnavailablePluginIndicator) { 612 frame().eventHandler().setCapturingMouseEventsElement(&element); 613 element.setIsCapturingMouseEvents(true); 614 setUnavailablePluginIndicatorIsPressed(true); 615 } 616 event->setDefaultHandled(); 617 } 618 if (event->type() == eventNames().mouseupEvent && toMouseEvent(event)->button() == LeftButton) { 619 if (m_unavailablePluginIndicatorIsPressed) { 620 frame().eventHandler().setCapturingMouseEventsElement(nullptr); 621 element.setIsCapturingMouseEvents(false); 622 setUnavailablePluginIndicatorIsPressed(false); 623 } 624 if (m_mouseDownWasInUnavailablePluginIndicator && isInUnavailablePluginIndicator(mouseEvent)) { 625 if (Page* page = document().page()) 626 page->chrome().client().unavailablePluginButtonClicked(&element, m_pluginUnavailabilityReason); 627 } 628 m_mouseDownWasInUnavailablePluginIndicator = false; 629 event->setDefaultHandled(); 630 } 631 if (event->type() == eventNames().mousemoveEvent) { 632 setUnavailablePluginIndicatorIsPressed(m_mouseDownWasInUnavailablePluginIndicator && isInUnavailablePluginIndicator(mouseEvent)); 633 event->setDefaultHandled(); 634 } 635} 636 637CursorDirective RenderEmbeddedObject::getCursor(const LayoutPoint& point, Cursor& cursor) const 638{ 639 if (showsUnavailablePluginIndicator() && shouldUnavailablePluginMessageBeButton(document(), m_pluginUnavailabilityReason) && isInUnavailablePluginIndicator(point)) { 640 cursor = handCursor(); 641 return SetCursor; 642 } 643 if (widget() && widget()->isPluginViewBase()) { 644 // A plug-in is responsible for setting the cursor when the pointer is over it. 645 return DoNotSetCursor; 646 } 647 return RenderWidget::getCursor(point, cursor); 648} 649 650bool RenderEmbeddedObject::canHaveChildren() const 651{ 652 if (isSnapshottedPlugIn()) 653 return true; 654 655 return false; 656} 657 658} 659