|
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(¶mNames, ¶mValues); |
|
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 } |