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