Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 2000 Simon Hausmann <hausmann (at) kde.org>
      4  *           (C) 2000 Stefan Schimanski (1Stein (at) 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 "PaintInfo.h"
     45 #include "Path.h"
     46 #include "PluginViewBase.h"
     47 #include "RenderTheme.h"
     48 #include "RenderView.h"
     49 #include "RenderWidgetProtector.h"
     50 #include "Settings.h"
     51 #include "Text.h"
     52 #include "TextRun.h"
     53 
     54 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
     55 #include "HTMLVideoElement.h"
     56 #endif
     57 
     58 namespace WebCore {
     59 
     60 using namespace HTMLNames;
     61 
     62 static const float replacementTextRoundedRectHeight = 18;
     63 static const float replacementTextRoundedRectLeftRightTextMargin = 6;
     64 static const float replacementTextRoundedRectOpacity = 0.20f;
     65 static const float replacementTextPressedRoundedRectOpacity = 0.65f;
     66 static const float replacementTextRoundedRectRadius = 5;
     67 static const float replacementTextTextOpacity = 0.55f;
     68 static const float replacementTextPressedTextOpacity = 0.65f;
     69 
     70 static const Color& replacementTextRoundedRectPressedColor()
     71 {
     72     static const Color lightGray(205, 205, 205);
     73     return lightGray;
     74 }
     75 
     76 RenderEmbeddedObject::RenderEmbeddedObject(Element* element)
     77     : RenderPart(element)
     78     , m_hasFallbackContent(false)
     79     , m_showsMissingPluginIndicator(false)
     80     , m_missingPluginIndicatorIsPressed(false)
     81     , m_mouseDownWasInMissingPluginIndicator(false)
     82 {
     83     view()->frameView()->setIsVisuallyNonEmpty();
     84 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
     85     if (element->hasTagName(videoTag) || element->hasTagName(audioTag))
     86         setHasIntrinsicSize();
     87 #endif
     88 }
     89 
     90 RenderEmbeddedObject::~RenderEmbeddedObject()
     91 {
     92     if (frameView())
     93         frameView()->removeWidgetToUpdate(this);
     94 }
     95 
     96 #if USE(ACCELERATED_COMPOSITING)
     97 bool RenderEmbeddedObject::requiresLayer() const
     98 {
     99     if (RenderPart::requiresLayer())
    100         return true;
    101 
    102     return allowsAcceleratedCompositing();
    103 }
    104 
    105 bool RenderEmbeddedObject::allowsAcceleratedCompositing() const
    106 {
    107     return widget() && widget()->isPluginViewBase() && static_cast<PluginViewBase*>(widget())->platformLayer();
    108 }
    109 #endif
    110 
    111 void RenderEmbeddedObject::setShowsMissingPluginIndicator()
    112 {
    113     ASSERT(m_replacementText.isEmpty());
    114     m_replacementText = missingPluginText();
    115     m_showsMissingPluginIndicator = true;
    116 }
    117 
    118 void RenderEmbeddedObject::setShowsCrashedPluginIndicator()
    119 {
    120     ASSERT(m_replacementText.isEmpty());
    121     m_replacementText = crashedPluginText();
    122 }
    123 
    124 bool RenderEmbeddedObject::pluginCrashedOrWasMissing() const
    125 {
    126     return !m_replacementText.isNull();
    127 }
    128 
    129 void RenderEmbeddedObject::setMissingPluginIndicatorIsPressed(bool pressed)
    130 {
    131     if (m_missingPluginIndicatorIsPressed == pressed)
    132         return;
    133 
    134     m_missingPluginIndicatorIsPressed = pressed;
    135     repaint();
    136 }
    137 
    138 void RenderEmbeddedObject::paint(PaintInfo& paintInfo, int tx, int ty)
    139 {
    140     if (pluginCrashedOrWasMissing()) {
    141         RenderReplaced::paint(paintInfo, tx, ty);
    142         return;
    143     }
    144 
    145     RenderPart::paint(paintInfo, tx, ty);
    146 }
    147 
    148 void RenderEmbeddedObject::paintReplaced(PaintInfo& paintInfo, int tx, int ty)
    149 {
    150     if (!pluginCrashedOrWasMissing())
    151         return;
    152 
    153     if (paintInfo.phase == PaintPhaseSelection)
    154         return;
    155 
    156     GraphicsContext* context = paintInfo.context;
    157     if (context->paintingDisabled())
    158         return;
    159 
    160     FloatRect contentRect;
    161     Path path;
    162     FloatRect replacementTextRect;
    163     Font font;
    164     TextRun run("");
    165     float textWidth;
    166     if (!getReplacementTextGeometry(tx, ty, contentRect, path, replacementTextRect, font, run, textWidth))
    167         return;
    168 
    169     context->save();
    170     context->clip(contentRect);
    171     context->setAlpha(m_missingPluginIndicatorIsPressed ? replacementTextPressedRoundedRectOpacity : replacementTextRoundedRectOpacity);
    172     context->setFillColor(m_missingPluginIndicatorIsPressed ? replacementTextRoundedRectPressedColor() : Color::white, style()->colorSpace());
    173     context->fillPath(path);
    174 
    175     const FontMetrics& fontMetrics = font.fontMetrics();
    176     float labelX = roundf(replacementTextRect.location().x() + (replacementTextRect.size().width() - textWidth) / 2);
    177     float labelY = roundf(replacementTextRect.location().y() + (replacementTextRect.size().height() - fontMetrics.height()) / 2 + fontMetrics.ascent());
    178     context->setAlpha(m_missingPluginIndicatorIsPressed ? replacementTextPressedTextOpacity : replacementTextTextOpacity);
    179     context->setFillColor(Color::black, style()->colorSpace());
    180     context->drawBidiText(font, run, FloatPoint(labelX, labelY));
    181     context->restore();
    182 }
    183 
    184 bool RenderEmbeddedObject::getReplacementTextGeometry(int tx, int ty, FloatRect& contentRect, Path& path, FloatRect& replacementTextRect, Font& font, TextRun& run, float& textWidth)
    185 {
    186     contentRect = contentBoxRect();
    187     contentRect.move(tx, ty);
    188 
    189     FontDescription fontDescription;
    190     RenderTheme::defaultTheme()->systemFont(CSSValueWebkitSmallControl, fontDescription);
    191     fontDescription.setWeight(FontWeightBold);
    192     Settings* settings = document()->settings();
    193     ASSERT(settings);
    194     if (!settings)
    195         return false;
    196     fontDescription.setRenderingMode(settings->fontRenderingMode());
    197     fontDescription.setComputedSize(fontDescription.specifiedSize());
    198     font = Font(fontDescription, 0, 0);
    199     font.update(0);
    200 
    201     run = TextRun(m_replacementText.characters(), m_replacementText.length());
    202     textWidth = font.width(run);
    203 
    204     replacementTextRect.setSize(FloatSize(textWidth + replacementTextRoundedRectLeftRightTextMargin * 2, replacementTextRoundedRectHeight));
    205     float x = (contentRect.size().width() / 2 - replacementTextRect.size().width() / 2) + contentRect.location().x();
    206     float y = (contentRect.size().height() / 2 - replacementTextRect.size().height() / 2) + contentRect.location().y();
    207     replacementTextRect.setLocation(FloatPoint(x, y));
    208 
    209     path.addRoundedRect(replacementTextRect, FloatSize(replacementTextRoundedRectRadius, replacementTextRoundedRectRadius));
    210 
    211     return true;
    212 }
    213 
    214 void RenderEmbeddedObject::layout()
    215 {
    216     ASSERT(needsLayout());
    217 
    218     computeLogicalWidth();
    219     computeLogicalHeight();
    220 
    221     RenderPart::layout();
    222 
    223     m_overflow.clear();
    224     addShadowOverflow();
    225 
    226     updateLayerTransform();
    227 
    228     if (!widget() && frameView())
    229         frameView()->addWidgetToUpdate(this);
    230 
    231     setNeedsLayout(false);
    232 }
    233 
    234 void RenderEmbeddedObject::viewCleared()
    235 {
    236     // This is required for <object> elements whose contents are rendered by WebCore (e.g. src="foo.html").
    237     if (node() && widget() && widget()->isFrameView()) {
    238         FrameView* view = static_cast<FrameView*>(widget());
    239         int marginWidth = -1;
    240         int marginHeight = -1;
    241         if (node()->hasTagName(iframeTag)) {
    242             HTMLIFrameElement* frame = static_cast<HTMLIFrameElement*>(node());
    243             marginWidth = frame->marginWidth();
    244             marginHeight = frame->marginHeight();
    245         }
    246         if (marginWidth != -1)
    247             view->setMarginWidth(marginWidth);
    248         if (marginHeight != -1)
    249             view->setMarginHeight(marginHeight);
    250     }
    251 }
    252 
    253 bool RenderEmbeddedObject::isInMissingPluginIndicator(MouseEvent* event)
    254 {
    255     FloatRect contentRect;
    256     Path path;
    257     FloatRect replacementTextRect;
    258     Font font;
    259     TextRun run("");
    260     float textWidth;
    261     if (!getReplacementTextGeometry(0, 0, contentRect, path, replacementTextRect, font, run, textWidth))
    262         return false;
    263 
    264     return path.contains(absoluteToLocal(event->absoluteLocation(), false, true));
    265 }
    266 
    267 void RenderEmbeddedObject::handleMissingPluginIndicatorEvent(Event* event)
    268 {
    269     if (Page* page = document()->page()) {
    270         if (!page->chrome()->client()->shouldMissingPluginMessageBeButton())
    271             return;
    272     }
    273 
    274     if (!event->isMouseEvent())
    275         return;
    276 
    277     MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
    278     HTMLPlugInElement* element = static_cast<HTMLPlugInElement*>(node());
    279     if (event->type() == eventNames().mousedownEvent && static_cast<MouseEvent*>(event)->button() == LeftButton) {
    280         m_mouseDownWasInMissingPluginIndicator = isInMissingPluginIndicator(mouseEvent);
    281         if (m_mouseDownWasInMissingPluginIndicator) {
    282             if (Frame* frame = document()->frame()) {
    283                 frame->eventHandler()->setCapturingMouseEventsNode(element);
    284                 element->setIsCapturingMouseEvents(true);
    285             }
    286             setMissingPluginIndicatorIsPressed(true);
    287         }
    288         event->setDefaultHandled();
    289     }
    290     if (event->type() == eventNames().mouseupEvent && static_cast<MouseEvent*>(event)->button() == LeftButton) {
    291         if (m_missingPluginIndicatorIsPressed) {
    292             if (Frame* frame = document()->frame()) {
    293                 frame->eventHandler()->setCapturingMouseEventsNode(0);
    294                 element->setIsCapturingMouseEvents(false);
    295             }
    296             setMissingPluginIndicatorIsPressed(false);
    297         }
    298         if (m_mouseDownWasInMissingPluginIndicator && isInMissingPluginIndicator(mouseEvent)) {
    299             if (Page* page = document()->page())
    300                 page->chrome()->client()->missingPluginButtonClicked(element);
    301         }
    302         m_mouseDownWasInMissingPluginIndicator = false;
    303         event->setDefaultHandled();
    304     }
    305     if (event->type() == eventNames().mousemoveEvent) {
    306         setMissingPluginIndicatorIsPressed(m_mouseDownWasInMissingPluginIndicator && isInMissingPluginIndicator(mouseEvent));
    307         event->setDefaultHandled();
    308     }
    309 }
    310 
    311 }
    312