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