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