WebCore/rendering/RenderEmbeddedObject.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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 "Chrome.h"
       
    28 #include "ChromeClient.h"
       
    29 #include "CSSValueKeywords.h"
       
    30 #include "Font.h"
       
    31 #include "FontSelector.h"
       
    32 #include "Frame.h"
       
    33 #include "FrameLoaderClient.h"
       
    34 #include "GraphicsContext.h"
       
    35 #include "HTMLEmbedElement.h"
       
    36 #include "HTMLIFrameElement.h"
       
    37 #include "HTMLNames.h"
       
    38 #include "HTMLObjectElement.h"
       
    39 #include "HTMLParamElement.h"
       
    40 #include "LocalizedStrings.h"
       
    41 #include "MIMETypeRegistry.h"
       
    42 #include "MouseEvent.h"
       
    43 #include "Page.h"
       
    44 #include "Path.h"
       
    45 #include "PluginViewBase.h"
       
    46 #include "RenderTheme.h"
       
    47 #include "RenderView.h"
       
    48 #include "RenderWidgetProtector.h"
       
    49 #include "Settings.h"
       
    50 #include "Text.h"
       
    51 
       
    52 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
       
    53 #include "HTMLVideoElement.h"
       
    54 #endif
       
    55 
       
    56 namespace WebCore {
       
    57 
       
    58 using namespace HTMLNames;
       
    59     
       
    60 static const float replacementTextRoundedRectHeight = 18;
       
    61 static const float replacementTextRoundedRectLeftRightTextMargin = 6;
       
    62 static const float replacementTextRoundedRectOpacity = 0.20f;
       
    63 static const float replacementTextPressedRoundedRectOpacity = 0.65f;
       
    64 static const float replacementTextRoundedRectRadius = 5;
       
    65 static const float replacementTextTextOpacity = 0.55f;
       
    66 static const float replacementTextPressedTextOpacity = 0.65f;
       
    67 
       
    68 static const Color& replacementTextRoundedRectPressedColor()
       
    69 {
       
    70     static const Color lightGray(205, 205, 205);
       
    71     return lightGray;
       
    72 }
       
    73     
       
    74 RenderEmbeddedObject::RenderEmbeddedObject(Element* element)
       
    75     : RenderPart(element)
       
    76     , m_hasFallbackContent(false)
       
    77     , m_showsMissingPluginIndicator(false)
       
    78     , m_missingPluginIndicatorIsPressed(false)
       
    79     , m_mouseDownWasInMissingPluginIndicator(false)
       
    80 {
       
    81     view()->frameView()->setIsVisuallyNonEmpty();
       
    82 }
       
    83 
       
    84 RenderEmbeddedObject::~RenderEmbeddedObject()
       
    85 {
       
    86     if (frameView())
       
    87         frameView()->removeWidgetToUpdate(this);
       
    88 }
       
    89 
       
    90 #if USE(ACCELERATED_COMPOSITING)
       
    91 bool RenderEmbeddedObject::requiresLayer() const
       
    92 {
       
    93     if (RenderPart::requiresLayer())
       
    94         return true;
       
    95     
       
    96     return allowsAcceleratedCompositing();
       
    97 }
       
    98 
       
    99 bool RenderEmbeddedObject::allowsAcceleratedCompositing() const
       
   100 {
       
   101     return widget() && widget()->isPluginViewBase() && static_cast<PluginViewBase*>(widget())->platformLayer();
       
   102 }
       
   103 #endif
       
   104 
       
   105 static bool isURLAllowed(Document* doc, const String& url)
       
   106 {
       
   107     if (doc->frame()->page()->frameCount() >= Page::maxNumberOfFrames)
       
   108         return false;
       
   109 
       
   110     // We allow one level of self-reference because some sites depend on that.
       
   111     // But we don't allow more than one.
       
   112     KURL completeURL = doc->completeURL(url);
       
   113     bool foundSelfReference = false;
       
   114     for (Frame* frame = doc->frame(); frame; frame = frame->tree()->parent()) {
       
   115         if (equalIgnoringFragmentIdentifier(frame->loader()->url(), completeURL)) {
       
   116             if (foundSelfReference)
       
   117                 return false;
       
   118             foundSelfReference = true;
       
   119         }
       
   120     }
       
   121     return true;
       
   122 }
       
   123 
       
   124 typedef HashMap<String, String, CaseFoldingHash> ClassIdToTypeMap;
       
   125 
       
   126 static ClassIdToTypeMap* createClassIdToTypeMap()
       
   127 {
       
   128     ClassIdToTypeMap* map = new ClassIdToTypeMap;
       
   129     map->add("clsid:D27CDB6E-AE6D-11CF-96B8-444553540000", "application/x-shockwave-flash");
       
   130     map->add("clsid:CFCDAA03-8BE4-11CF-B84B-0020AFBBCCFA", "audio/x-pn-realaudio-plugin");
       
   131     map->add("clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B", "video/quicktime");
       
   132     map->add("clsid:166B1BCA-3F9C-11CF-8075-444553540000", "application/x-director");
       
   133     map->add("clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6", "application/x-mplayer2");
       
   134     map->add("clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95", "application/x-mplayer2");
       
   135     return map;
       
   136 }
       
   137 
       
   138 static String serviceTypeForClassId(const String& classId)
       
   139 {
       
   140     // Return early if classId is empty (since we won't do anything below).
       
   141     // Furthermore, if classId is null, calling get() below will crash.
       
   142     if (classId.isEmpty())
       
   143         return String();
       
   144 
       
   145     static ClassIdToTypeMap* map = createClassIdToTypeMap();
       
   146     return map->get(classId);
       
   147 }
       
   148 
       
   149 static void mapDataParamToSrc(Vector<String>* paramNames, Vector<String>* paramValues)
       
   150 {
       
   151     // Some plugins don't understand the "data" attribute of the OBJECT tag (i.e. Real and WMP
       
   152     // require "src" attribute).
       
   153     int srcIndex = -1, dataIndex = -1;
       
   154     for (unsigned int i = 0; i < paramNames->size(); ++i) {
       
   155         if (equalIgnoringCase((*paramNames)[i], "src"))
       
   156             srcIndex = i;
       
   157         else if (equalIgnoringCase((*paramNames)[i], "data"))
       
   158             dataIndex = i;
       
   159     }
       
   160 
       
   161     if (srcIndex == -1 && dataIndex != -1) {
       
   162         paramNames->append("src");
       
   163         paramValues->append((*paramValues)[dataIndex]);
       
   164     }
       
   165 }
       
   166 
       
   167 void RenderEmbeddedObject::updateWidget(bool onlyCreateNonNetscapePlugins)
       
   168 {
       
   169     if (!m_replacementText.isNull() || !node()) // Check the node in case destroy() has been called.
       
   170         return;
       
   171 
       
   172     String url;
       
   173     String serviceType;
       
   174     Vector<String> paramNames;
       
   175     Vector<String> paramValues;
       
   176     Frame* frame = frameView()->frame();
       
   177 
       
   178     // The calls to SubframeLoader::requestObject within this function can result in a plug-in being initialized.
       
   179     // This can run cause arbitrary JavaScript to run and may result in this RenderObject being detached from
       
   180     // the render tree and destroyed, causing a crash like <rdar://problem/6954546>.  By extending our lifetime
       
   181     // artifically to ensure that we remain alive for the duration of plug-in initialization.
       
   182     RenderWidgetProtector protector(this);
       
   183 
       
   184     if (node()->hasTagName(objectTag)) {
       
   185         HTMLObjectElement* objectElement = static_cast<HTMLObjectElement*>(node());
       
   186 
       
   187         objectElement->setNeedWidgetUpdate(false);
       
   188         if (!objectElement->isFinishedParsingChildren())
       
   189           return;
       
   190 
       
   191         // Check for a child EMBED tag.
       
   192         HTMLEmbedElement* embed = 0;
       
   193         for (Node* child = objectElement->firstChild(); child; ) {
       
   194             if (child->hasTagName(embedTag)) {
       
   195                 embed = static_cast<HTMLEmbedElement*>(child);
       
   196                 break;
       
   197             }
       
   198             
       
   199             if (child->hasTagName(objectTag))
       
   200                 child = child->nextSibling(); // Don't descend into nested OBJECT tags
       
   201             else
       
   202                 child = child->traverseNextNode(objectElement); // Otherwise descend (EMBEDs may be inside COMMENT tags)
       
   203         }
       
   204 
       
   205         // Use the attributes from the EMBED tag instead of the OBJECT tag including WIDTH and HEIGHT.
       
   206         HTMLElement* embedOrObject;
       
   207         if (embed) {
       
   208             embedOrObject = embed;
       
   209             url = embed->url();
       
   210             serviceType = embed->serviceType();
       
   211         } else
       
   212             embedOrObject = objectElement;
       
   213 
       
   214         // If there was no URL or type defined in EMBED, try the OBJECT tag.
       
   215         if (url.isEmpty())
       
   216             url = objectElement->url();
       
   217         if (serviceType.isEmpty())
       
   218             serviceType = objectElement->serviceType();
       
   219 
       
   220         HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames;
       
   221 
       
   222         // Scan the PARAM children.
       
   223         // Get the URL and type from the params if we don't already have them.
       
   224         // Get the attributes from the params if there is no EMBED tag.
       
   225         Node* child = objectElement->firstChild();
       
   226         while (child && (url.isEmpty() || serviceType.isEmpty() || !embed)) {
       
   227             if (child->hasTagName(paramTag)) {
       
   228                 HTMLParamElement* p = static_cast<HTMLParamElement*>(child);
       
   229                 String name = p->name();
       
   230                 if (url.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url")))
       
   231                     url = p->value();
       
   232                 if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) {
       
   233                     serviceType = p->value();
       
   234                     int pos = serviceType.find(";");
       
   235                     if (pos != -1)
       
   236                         serviceType = serviceType.left(pos);
       
   237                 }
       
   238                 if (!embed && !name.isEmpty()) {
       
   239                     uniqueParamNames.add(name.impl());
       
   240                     paramNames.append(p->name());
       
   241                     paramValues.append(p->value());
       
   242                 }
       
   243             }
       
   244             child = child->nextSibling();
       
   245         }
       
   246 
       
   247         // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag
       
   248         // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is
       
   249         // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means
       
   250         // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM,
       
   251         // else our Java plugin will misinterpret it. [4004531]
       
   252         String codebase;
       
   253         if (!embed && MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) {
       
   254             codebase = "codebase";
       
   255             uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already
       
   256         }
       
   257         
       
   258         // Turn the attributes of either the EMBED tag or OBJECT tag into arrays, but don't override PARAM values.
       
   259         NamedNodeMap* attributes = embedOrObject->attributes();
       
   260         if (attributes) {
       
   261             for (unsigned i = 0; i < attributes->length(); ++i) {
       
   262                 Attribute* it = attributes->attributeItem(i);
       
   263                 const AtomicString& name = it->name().localName();
       
   264                 if (embed || !uniqueParamNames.contains(name.impl())) {
       
   265                     paramNames.append(name.string());
       
   266                     paramValues.append(it->value().string());
       
   267                 }
       
   268             }
       
   269         }
       
   270 
       
   271         mapDataParamToSrc(&paramNames, &paramValues);
       
   272 
       
   273         // If we still don't have a type, try to map from a specific CLASSID to a type.
       
   274         if (serviceType.isEmpty())
       
   275             serviceType = serviceTypeForClassId(objectElement->classId());
       
   276 
       
   277         if (!isURLAllowed(document(), url))
       
   278             return;
       
   279 
       
   280         // Find out if we support fallback content.
       
   281         m_hasFallbackContent = false;
       
   282         for (Node* child = objectElement->firstChild(); child && !m_hasFallbackContent; child = child->nextSibling()) {
       
   283             if ((!child->isTextNode() && !child->hasTagName(embedTag) && !child->hasTagName(paramTag))  // Discount <embed> and <param>
       
   284                 || (child->isTextNode() && !static_cast<Text*>(child)->containsOnlyWhitespace()))
       
   285                 m_hasFallbackContent = true;
       
   286         }
       
   287 
       
   288         if (onlyCreateNonNetscapePlugins) {
       
   289             KURL completedURL;
       
   290             if (!url.isEmpty())
       
   291                 completedURL = frame->loader()->completeURL(url);
       
   292 
       
   293             if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin)
       
   294                 return;
       
   295         }
       
   296 
       
   297         bool beforeLoadAllowedLoad = objectElement->dispatchBeforeLoadEvent(url);
       
   298         
       
   299         // beforeload events can modify the DOM, potentially causing
       
   300         // RenderWidget::destroy() to be called.  Ensure we haven't been
       
   301         // destroyed before continuing.
       
   302         if (!node())
       
   303             return;
       
   304         
       
   305         bool success = beforeLoadAllowedLoad && frame->loader()->subframeLoader()->requestObject(this, url, objectElement->getAttribute(nameAttr), serviceType, paramNames, paramValues);
       
   306     
       
   307         if (!success && m_hasFallbackContent)
       
   308             objectElement->renderFallbackContent();
       
   309 
       
   310     } else if (node()->hasTagName(embedTag)) {
       
   311         HTMLEmbedElement* embedElement = static_cast<HTMLEmbedElement*>(node());
       
   312         embedElement->setNeedWidgetUpdate(false);
       
   313         url = embedElement->url();
       
   314         serviceType = embedElement->serviceType();
       
   315 
       
   316         if (url.isEmpty() && serviceType.isEmpty())
       
   317             return;
       
   318         if (!isURLAllowed(document(), url))
       
   319             return;
       
   320 
       
   321         // add all attributes set on the embed object
       
   322         NamedNodeMap* attributes = embedElement->attributes();
       
   323         if (attributes) {
       
   324             for (unsigned i = 0; i < attributes->length(); ++i) {
       
   325                 Attribute* it = attributes->attributeItem(i);
       
   326                 paramNames.append(it->name().localName().string());
       
   327                 paramValues.append(it->value().string());
       
   328             }
       
   329         }
       
   330 
       
   331         if (onlyCreateNonNetscapePlugins) {
       
   332             KURL completedURL;
       
   333             if (!url.isEmpty())
       
   334                 completedURL = frame->loader()->completeURL(url);
       
   335 
       
   336             if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin)
       
   337                 return;
       
   338         }
       
   339 
       
   340         if (embedElement->dispatchBeforeLoadEvent(url))
       
   341             frame->loader()->subframeLoader()->requestObject(this, url, embedElement->getAttribute(nameAttr), serviceType, paramNames, paramValues);
       
   342     }
       
   343 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)        
       
   344     else if (node()->hasTagName(videoTag) || node()->hasTagName(audioTag)) {
       
   345         HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(node());
       
   346         KURL kurl;
       
   347 
       
   348         mediaElement->getPluginProxyParams(kurl, paramNames, paramValues);
       
   349         mediaElement->setNeedWidgetUpdate(false);
       
   350         frame->loader()->subframeLoader()->loadMediaPlayerProxyPlugin(node(), kurl, paramNames, paramValues);
       
   351     }
       
   352 #endif
       
   353 }
       
   354 
       
   355 void RenderEmbeddedObject::setShowsMissingPluginIndicator()
       
   356 {
       
   357     ASSERT(m_replacementText.isEmpty());
       
   358     m_replacementText = missingPluginText();
       
   359     m_showsMissingPluginIndicator = true;
       
   360 }
       
   361 
       
   362 void RenderEmbeddedObject::setShowsCrashedPluginIndicator()
       
   363 {
       
   364     ASSERT(m_replacementText.isEmpty());
       
   365     m_replacementText = crashedPluginText();
       
   366 }
       
   367 
       
   368 void RenderEmbeddedObject::setMissingPluginIndicatorIsPressed(bool pressed)
       
   369 {
       
   370     if (m_missingPluginIndicatorIsPressed == pressed)
       
   371         return;
       
   372     
       
   373     m_missingPluginIndicatorIsPressed = pressed;
       
   374     repaint();
       
   375 }
       
   376 
       
   377 void RenderEmbeddedObject::paint(PaintInfo& paintInfo, int tx, int ty)
       
   378 {
       
   379     if (!m_replacementText.isNull()) {
       
   380         RenderReplaced::paint(paintInfo, tx, ty);
       
   381         return;
       
   382     }
       
   383     
       
   384     RenderPart::paint(paintInfo, tx, ty);
       
   385 }
       
   386 
       
   387 void RenderEmbeddedObject::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
       
   388 {
       
   389     if (!m_replacementText)
       
   390         return;
       
   391 
       
   392     if (paintInfo.phase == PaintPhaseSelection)
       
   393         return;
       
   394     
       
   395     GraphicsContext* context = paintInfo.context;
       
   396     if (context->paintingDisabled())
       
   397         return;
       
   398     
       
   399     FloatRect contentRect;
       
   400     Path path;
       
   401     FloatRect replacementTextRect;
       
   402     Font font;
       
   403     TextRun run("");
       
   404     float textWidth;
       
   405     if (!getReplacementTextGeometry(tx, ty, contentRect, path, replacementTextRect, font, run, textWidth))
       
   406         return;
       
   407     
       
   408     context->save();
       
   409     context->clip(contentRect);
       
   410     context->beginPath();
       
   411     context->addPath(path);  
       
   412     context->setAlpha(m_missingPluginIndicatorIsPressed ? replacementTextPressedRoundedRectOpacity : replacementTextRoundedRectOpacity);
       
   413     context->setFillColor(m_missingPluginIndicatorIsPressed ? replacementTextRoundedRectPressedColor() : Color::white, style()->colorSpace());
       
   414     context->fillPath();
       
   415 
       
   416     float labelX = roundf(replacementTextRect.location().x() + (replacementTextRect.size().width() - textWidth) / 2);
       
   417     float labelY = roundf(replacementTextRect.location().y() + (replacementTextRect.size().height() - font.height()) / 2 + font.ascent());
       
   418     context->setAlpha(m_missingPluginIndicatorIsPressed ? replacementTextPressedTextOpacity : replacementTextTextOpacity);
       
   419     context->setFillColor(Color::black, style()->colorSpace());
       
   420     context->drawBidiText(font, run, FloatPoint(labelX, labelY));
       
   421     context->restore();
       
   422 }
       
   423 
       
   424 bool RenderEmbeddedObject::getReplacementTextGeometry(int tx, int ty, FloatRect& contentRect, Path& path, FloatRect& replacementTextRect, Font& font, TextRun& run, float& textWidth)
       
   425 {
       
   426     contentRect = contentBoxRect();
       
   427     contentRect.move(tx, ty);
       
   428     
       
   429     FontDescription fontDescription;
       
   430     RenderTheme::defaultTheme()->systemFont(CSSValueWebkitSmallControl, fontDescription);
       
   431     fontDescription.setWeight(FontWeightBold);
       
   432     Settings* settings = document()->settings();
       
   433     ASSERT(settings);
       
   434     if (!settings)
       
   435         return false;
       
   436     fontDescription.setRenderingMode(settings->fontRenderingMode());
       
   437     fontDescription.setComputedSize(fontDescription.specifiedSize());
       
   438     font = Font(fontDescription, 0, 0);
       
   439     font.update(0);
       
   440     
       
   441     run = TextRun(m_replacementText.characters(), m_replacementText.length());
       
   442     run.disableRoundingHacks();
       
   443     textWidth = font.floatWidth(run);
       
   444     
       
   445     replacementTextRect.setSize(FloatSize(textWidth + replacementTextRoundedRectLeftRightTextMargin * 2, replacementTextRoundedRectHeight));
       
   446     float x = (contentRect.size().width() / 2 - replacementTextRect.size().width() / 2) + contentRect.location().x();
       
   447     float y = (contentRect.size().height() / 2 - replacementTextRect.size().height() / 2) + contentRect.location().y();
       
   448     replacementTextRect.setLocation(FloatPoint(x, y));
       
   449     
       
   450     path = Path::createRoundedRectangle(replacementTextRect, FloatSize(replacementTextRoundedRectRadius, replacementTextRoundedRectRadius));
       
   451 
       
   452     return true;
       
   453 }
       
   454 
       
   455 void RenderEmbeddedObject::layout()
       
   456 {
       
   457     ASSERT(needsLayout());
       
   458 
       
   459     calcWidth();
       
   460     calcHeight();
       
   461 
       
   462     RenderPart::layout();
       
   463 
       
   464     m_overflow.clear();
       
   465     addShadowOverflow();
       
   466 
       
   467     if (!widget() && frameView())
       
   468         frameView()->addWidgetToUpdate(this);
       
   469 
       
   470     setNeedsLayout(false);
       
   471 }
       
   472 
       
   473 void RenderEmbeddedObject::viewCleared()
       
   474 {
       
   475     // This is required for <object> elements whose contents are rendered by WebCore (e.g. src="foo.html").
       
   476     if (node() && widget() && widget()->isFrameView()) {
       
   477         FrameView* view = static_cast<FrameView*>(widget());
       
   478         int marginw = -1;
       
   479         int marginh = -1;
       
   480         if (node()->hasTagName(iframeTag)) {
       
   481             HTMLIFrameElement* frame = static_cast<HTMLIFrameElement*>(node());
       
   482             marginw = frame->getMarginWidth();
       
   483             marginh = frame->getMarginHeight();
       
   484         }
       
   485         if (marginw != -1)
       
   486             view->setMarginWidth(marginw);
       
   487         if (marginh != -1)
       
   488             view->setMarginHeight(marginh);
       
   489     }
       
   490 }
       
   491  
       
   492 bool RenderEmbeddedObject::isInMissingPluginIndicator(MouseEvent* event)
       
   493 {
       
   494     FloatRect contentRect;
       
   495     Path path;
       
   496     FloatRect replacementTextRect;
       
   497     Font font;
       
   498     TextRun run("");
       
   499     float textWidth;
       
   500     if (!getReplacementTextGeometry(0, 0, contentRect, path, replacementTextRect, font, run, textWidth))
       
   501         return false;
       
   502     
       
   503     return path.contains(absoluteToLocal(event->absoluteLocation(), false, true));
       
   504 }
       
   505 
       
   506 void RenderEmbeddedObject::handleMissingPluginIndicatorEvent(Event* event)
       
   507 {
       
   508     if (Page* page = document()->page()) {
       
   509         if (!page->chrome()->client()->shouldMissingPluginMessageBeButton())
       
   510             return;
       
   511     }
       
   512     
       
   513     if (!event->isMouseEvent())
       
   514         return;
       
   515     
       
   516     MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
       
   517     HTMLPlugInElement* element = static_cast<HTMLPlugInElement*>(node());
       
   518     if (event->type() == eventNames().mousedownEvent && static_cast<MouseEvent*>(event)->button() == LeftButton) {
       
   519         m_mouseDownWasInMissingPluginIndicator = isInMissingPluginIndicator(mouseEvent);
       
   520         if (m_mouseDownWasInMissingPluginIndicator) {
       
   521             if (Frame* frame = document()->frame()) {
       
   522                 frame->eventHandler()->setCapturingMouseEventsNode(element);
       
   523                 element->setIsCapturingMouseEvents(true);
       
   524             }
       
   525             setMissingPluginIndicatorIsPressed(true);
       
   526         }
       
   527         event->setDefaultHandled();
       
   528     }        
       
   529     if (event->type() == eventNames().mouseupEvent && static_cast<MouseEvent*>(event)->button() == LeftButton) {
       
   530         if (m_missingPluginIndicatorIsPressed) {
       
   531             if (Frame* frame = document()->frame()) {
       
   532                 frame->eventHandler()->setCapturingMouseEventsNode(0);
       
   533                 element->setIsCapturingMouseEvents(false);
       
   534             }
       
   535             setMissingPluginIndicatorIsPressed(false);
       
   536         }
       
   537         if (m_mouseDownWasInMissingPluginIndicator && isInMissingPluginIndicator(mouseEvent)) {
       
   538             if (Page* page = document()->page())
       
   539                 page->chrome()->client()->missingPluginButtonClicked(element);            
       
   540         }
       
   541         m_mouseDownWasInMissingPluginIndicator = false;
       
   542         event->setDefaultHandled();
       
   543     }
       
   544     if (event->type() == eventNames().mousemoveEvent) {
       
   545         setMissingPluginIndicatorIsPressed(m_mouseDownWasInMissingPluginIndicator && isInMissingPluginIndicator(mouseEvent));
       
   546         event->setDefaultHandled();
       
   547     }
       
   548 }
       
   549 
       
   550 }