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 "core/rendering/RenderEmbeddedObject.h"
     26 
     27 #include "CSSValueKeywords.h"
     28 #include "HTMLNames.h"
     29 #include "core/html/HTMLIFrameElement.h"
     30 #include "core/page/Frame.h"
     31 #include "core/page/Page.h"
     32 #include "core/page/Settings.h"
     33 #include "core/platform/LocalizedStrings.h"
     34 #include "core/platform/graphics/Font.h"
     35 #include "core/platform/graphics/FontSelector.h"
     36 #include "core/platform/graphics/GraphicsContextStateSaver.h"
     37 #include "core/platform/graphics/Path.h"
     38 #include "core/platform/graphics/TextRun.h"
     39 #include "core/plugins/PluginView.h"
     40 #include "core/rendering/PaintInfo.h"
     41 #include "core/rendering/RenderTheme.h"
     42 #include "core/rendering/RenderView.h"
     43 
     44 namespace WebCore {
     45 
     46 using namespace HTMLNames;
     47 
     48 static const float replacementTextRoundedRectHeight = 18;
     49 static const float replacementTextRoundedRectLeftRightTextMargin = 6;
     50 static const float replacementTextRoundedRectOpacity = 0.20f;
     51 static const float replacementTextRoundedRectRadius = 5;
     52 static const float replacementTextTextOpacity = 0.55f;
     53 
     54 static const Color& replacementTextRoundedRectPressedColor()
     55 {
     56     static const Color lightGray(205, 205, 205);
     57     return lightGray;
     58 }
     59 
     60 RenderEmbeddedObject::RenderEmbeddedObject(Element* element)
     61     : RenderPart(element)
     62     , m_hasFallbackContent(false)
     63     , m_showsUnavailablePluginIndicator(false)
     64 {
     65     view()->frameView()->setIsVisuallyNonEmpty();
     66 }
     67 
     68 RenderEmbeddedObject::~RenderEmbeddedObject()
     69 {
     70     if (frameView())
     71         frameView()->removeWidgetToUpdate(this);
     72 }
     73 
     74 bool RenderEmbeddedObject::requiresLayer() const
     75 {
     76     if (RenderPart::requiresLayer())
     77         return true;
     78 
     79     return allowsAcceleratedCompositing();
     80 }
     81 
     82 bool RenderEmbeddedObject::allowsAcceleratedCompositing() const
     83 {
     84     return widget() && widget()->isPluginView() && toPluginView(widget())->platformLayer();
     85 }
     86 
     87 static String unavailablePluginReplacementText(RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason)
     88 {
     89     switch (pluginUnavailabilityReason) {
     90     case RenderEmbeddedObject::PluginMissing:
     91         return missingPluginText();
     92     case RenderEmbeddedObject::PluginBlockedByContentSecurityPolicy:
     93         return blockedPluginByContentSecurityPolicyText();
     94     }
     95 
     96     ASSERT_NOT_REACHED();
     97     return String();
     98 }
     99 
    100 void RenderEmbeddedObject::setPluginUnavailabilityReason(PluginUnavailabilityReason pluginUnavailabilityReason)
    101 {
    102     ASSERT(!m_showsUnavailablePluginIndicator);
    103     m_showsUnavailablePluginIndicator = true;
    104     m_pluginUnavailabilityReason = pluginUnavailabilityReason;
    105 
    106     m_unavailablePluginReplacementText = unavailablePluginReplacementText(pluginUnavailabilityReason);
    107 }
    108 
    109 bool RenderEmbeddedObject::showsUnavailablePluginIndicator() const
    110 {
    111     return m_showsUnavailablePluginIndicator;
    112 }
    113 
    114 void RenderEmbeddedObject::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    115 {
    116     Element* element = toElement(node());
    117     if (!element || !element->isPluginElement())
    118         return;
    119 
    120     RenderPart::paintContents(paintInfo, paintOffset);
    121 }
    122 
    123 void RenderEmbeddedObject::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    124 {
    125     Page* page = 0;
    126     if (Frame* frame = this->frame())
    127         page = frame->page();
    128 
    129     if (showsUnavailablePluginIndicator()) {
    130         if (page && paintInfo.phase == PaintPhaseForeground)
    131             page->addRelevantUnpaintedObject(this, visualOverflowRect());
    132         RenderReplaced::paint(paintInfo, paintOffset);
    133         return;
    134     }
    135 
    136     if (page && paintInfo.phase == PaintPhaseForeground)
    137         page->addRelevantRepaintedObject(this, visualOverflowRect());
    138 
    139     RenderPart::paint(paintInfo, paintOffset);
    140 }
    141 
    142 void RenderEmbeddedObject::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    143 {
    144     if (!showsUnavailablePluginIndicator())
    145         return;
    146 
    147     if (paintInfo.phase == PaintPhaseSelection)
    148         return;
    149 
    150     GraphicsContext* context = paintInfo.context;
    151     if (context->paintingDisabled())
    152         return;
    153 
    154     FloatRect contentRect;
    155     Path path;
    156     FloatRect replacementTextRect;
    157     Font font;
    158     TextRun run("");
    159     float textWidth;
    160     if (!getReplacementTextGeometry(paintOffset, contentRect, path, replacementTextRect, font, run, textWidth))
    161         return;
    162 
    163     GraphicsContextStateSaver stateSaver(*context);
    164     context->clip(contentRect);
    165     context->setAlpha(replacementTextRoundedRectOpacity);
    166     context->setFillColor(Color::white);
    167     context->fillPath(path);
    168 
    169     const FontMetrics& fontMetrics = font.fontMetrics();
    170     float labelX = roundf(replacementTextRect.location().x() + (replacementTextRect.size().width() - textWidth) / 2);
    171     float labelY = roundf(replacementTextRect.location().y() + (replacementTextRect.size().height() - fontMetrics.height()) / 2 + fontMetrics.ascent());
    172     TextRunPaintInfo runInfo(run);
    173     runInfo.bounds = replacementTextRect;
    174     context->setAlpha(replacementTextTextOpacity);
    175     context->setFillColor(Color::black);
    176     context->drawBidiText(font, runInfo, FloatPoint(labelX, labelY));
    177 }
    178 
    179 bool RenderEmbeddedObject::getReplacementTextGeometry(const LayoutPoint& accumulatedOffset, FloatRect& contentRect, Path& path, FloatRect& replacementTextRect, Font& font, TextRun& run, float& textWidth) const
    180 {
    181     contentRect = contentBoxRect();
    182     contentRect.moveBy(roundedIntPoint(accumulatedOffset));
    183 
    184     FontDescription fontDescription;
    185     RenderTheme::defaultTheme()->systemFont(CSSValueWebkitSmallControl, fontDescription);
    186     fontDescription.setWeight(FontWeightBold);
    187     Settings* settings = document()->settings();
    188     ASSERT(settings);
    189     if (!settings)
    190         return false;
    191     fontDescription.setComputedSize(fontDescription.specifiedSize());
    192     font = Font(fontDescription, 0, 0);
    193     font.update(0);
    194 
    195     run = TextRun(m_unavailablePluginReplacementText);
    196     textWidth = font.width(run);
    197 
    198     replacementTextRect.setSize(FloatSize(textWidth + replacementTextRoundedRectLeftRightTextMargin * 2, replacementTextRoundedRectHeight));
    199     float x = (contentRect.size().width() / 2 - replacementTextRect.size().width() / 2) + contentRect.location().x();
    200     float y = (contentRect.size().height() / 2 - replacementTextRect.size().height() / 2) + contentRect.location().y();
    201     replacementTextRect.setLocation(FloatPoint(x, y));
    202 
    203     path.addRoundedRect(replacementTextRect, FloatSize(replacementTextRoundedRectRadius, replacementTextRoundedRectRadius));
    204 
    205     return true;
    206 }
    207 
    208 void RenderEmbeddedObject::layout()
    209 {
    210     StackStats::LayoutCheckPoint layoutCheckPoint;
    211     ASSERT(needsLayout());
    212 
    213     LayoutSize oldSize = contentBoxRect().size();
    214 
    215     updateLogicalWidth();
    216     updateLogicalHeight();
    217 
    218     RenderPart::layout();
    219 
    220     m_overflow.clear();
    221     addVisualEffectOverflow();
    222 
    223     updateLayerTransform();
    224 
    225     if (!widget() && frameView())
    226         frameView()->addWidgetToUpdate(this);
    227 
    228     clearNeedsLayout();
    229 
    230     if (!canHaveChildren())
    231         return;
    232 
    233     // This code copied from RenderMedia::layout().
    234     RenderObject* child = m_children.firstChild();
    235 
    236     if (!child)
    237         return;
    238 
    239     RenderBox* childBox = toRenderBox(child);
    240 
    241     if (!childBox)
    242         return;
    243 
    244     LayoutSize newSize = contentBoxRect().size();
    245     if (newSize == oldSize && !childBox->needsLayout())
    246         return;
    247 
    248     // When calling layout() on a child node, a parent must either push a LayoutStateMaintainter, or
    249     // instantiate LayoutStateDisabler. Since using a LayoutStateMaintainer is slightly more efficient,
    250     // and this method will be called many times per second during playback, use a LayoutStateMaintainer:
    251     LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
    252 
    253     childBox->setLocation(LayoutPoint(borderLeft(), borderTop()) + LayoutSize(paddingLeft(), paddingTop()));
    254     childBox->style()->setHeight(Length(newSize.height(), Fixed));
    255     childBox->style()->setWidth(Length(newSize.width(), Fixed));
    256     childBox->forceLayout();
    257     clearNeedsLayout();
    258 
    259     statePusher.pop();
    260 }
    261 
    262 void RenderEmbeddedObject::viewCleared()
    263 {
    264     // This is required for <object> elements whose contents are rendered by WebCore (e.g. src="foo.html").
    265     if (node() && widget() && widget()->isFrameView()) {
    266         FrameView* view = toFrameView(widget());
    267         int marginWidth = -1;
    268         int marginHeight = -1;
    269         if (node()->hasTagName(iframeTag)) {
    270             HTMLIFrameElement* frame = toHTMLIFrameElement(node());
    271             marginWidth = frame->marginWidth();
    272             marginHeight = frame->marginHeight();
    273         }
    274         if (marginWidth != -1)
    275             view->setMarginWidth(marginWidth);
    276         if (marginHeight != -1)
    277             view->setMarginHeight(marginHeight);
    278     }
    279 }
    280 
    281 bool RenderEmbeddedObject::scroll(ScrollDirection direction, ScrollGranularity granularity, float, Node**)
    282 {
    283     return false;
    284 }
    285 
    286 bool RenderEmbeddedObject::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
    287 {
    288     return false;
    289 }
    290 
    291 bool RenderEmbeddedObject::canHaveChildren() const
    292 {
    293     return false;
    294 }
    295 
    296 }
    297