1/* 2 * Copyright (C) 2012 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "RenderSnapshottedPlugIn.h" 28 29#include "CachedImage.h" 30#include "Chrome.h" 31#include "ChromeClient.h" 32#include "Cursor.h" 33#include "Filter.h" 34#include "Frame.h" 35#include "FrameLoaderClient.h" 36#include "FrameView.h" 37#include "Gradient.h" 38#include "HTMLPlugInImageElement.h" 39#include "ImageBuffer.h" 40#include "MouseEvent.h" 41#include "Page.h" 42#include "PaintInfo.h" 43#include "Path.h" 44#include "PlatformMouseEvent.h" 45#include "RenderIterator.h" 46#include "RenderView.h" 47#include <wtf/StackStats.h> 48 49namespace WebCore { 50 51RenderSnapshottedPlugIn::RenderSnapshottedPlugIn(HTMLPlugInImageElement& element, PassRef<RenderStyle> style) 52 : RenderEmbeddedObject(element, WTF::move(style)) 53 , m_snapshotResource(std::make_unique<RenderImageResource>()) 54 , m_isPotentialMouseActivation(false) 55{ 56 m_snapshotResource->initialize(this); 57} 58 59RenderSnapshottedPlugIn::~RenderSnapshottedPlugIn() 60{ 61 ASSERT(m_snapshotResource); 62 m_snapshotResource->shutdown(); 63} 64 65HTMLPlugInImageElement& RenderSnapshottedPlugIn::plugInImageElement() const 66{ 67 return toHTMLPlugInImageElement(RenderEmbeddedObject::frameOwnerElement()); 68} 69 70void RenderSnapshottedPlugIn::layout() 71{ 72 StackStats::LayoutCheckPoint layoutCheckPoint; 73 LayoutSize oldSize = contentBoxRect().size(); 74 75 RenderEmbeddedObject::layout(); 76 77 LayoutSize newSize = contentBoxRect().size(); 78 if (newSize == oldSize) 79 return; 80 81 view().frameView().addEmbeddedObjectToUpdate(*this); 82} 83 84void RenderSnapshottedPlugIn::updateSnapshot(PassRefPtr<Image> image) 85{ 86 // Zero-size plugins will have no image. 87 if (!image) 88 return; 89 90 m_snapshotResource->setCachedImage(new CachedImage(image.get(), view().frameView().frame().page()->sessionID())); 91 repaint(); 92} 93 94void RenderSnapshottedPlugIn::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 95{ 96 if (paintInfo.phase == PaintPhaseForeground && plugInImageElement().displayState() < HTMLPlugInElement::Restarting) { 97 paintSnapshot(paintInfo, paintOffset); 98 } 99 100 PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase; 101 newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase; 102 103 PaintInfo paintInfoForChild(paintInfo); 104 paintInfoForChild.phase = newPhase; 105 paintInfoForChild.updateSubtreePaintRootForChildren(this); 106 107 for (auto& child : childrenOfType<RenderBox>(*this)) { 108 LayoutPoint childPoint = flipForWritingModeForChild(&child, paintOffset); 109 if (!child.hasSelfPaintingLayer() && !child.isFloating()) 110 child.paint(paintInfoForChild, childPoint); 111 } 112 113 RenderEmbeddedObject::paint(paintInfo, paintOffset); 114} 115 116void RenderSnapshottedPlugIn::paintSnapshot(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 117{ 118 Image* image = m_snapshotResource->image().get(); 119 if (!image || image->isNull()) 120 return; 121 122 LayoutUnit cWidth = contentWidth(); 123 LayoutUnit cHeight = contentHeight(); 124 if (!cWidth || !cHeight) 125 return; 126 127 GraphicsContext* context = paintInfo.context; 128 129 LayoutSize contentSize(cWidth, cHeight); 130 LayoutPoint contentLocation = location() + paintOffset; 131 contentLocation.move(borderLeft() + paddingLeft(), borderTop() + paddingTop()); 132 133 LayoutRect rect(contentLocation, contentSize); 134 IntRect alignedRect = pixelSnappedIntRect(rect); 135 if (alignedRect.width() <= 0 || alignedRect.height() <= 0) 136 return; 137 138 bool useLowQualityScaling = shouldPaintAtLowQuality(context, image, image, alignedRect.size()); 139 140 ImageOrientationDescription orientationDescription(shouldRespectImageOrientation()); 141#if ENABLE(CSS_IMAGE_ORIENTATION) 142 orientationDescription.setImageOrientationEnum(style().imageOrientation()); 143#endif 144 context->drawImage(image, style().colorSpace(), alignedRect, ImagePaintingOptions(orientationDescription, useLowQualityScaling)); 145} 146 147CursorDirective RenderSnapshottedPlugIn::getCursor(const LayoutPoint& point, Cursor& overrideCursor) const 148{ 149 if (plugInImageElement().displayState() < HTMLPlugInElement::Restarting) { 150 overrideCursor = handCursor(); 151 return SetCursor; 152 } 153 return RenderEmbeddedObject::getCursor(point, overrideCursor); 154} 155 156void RenderSnapshottedPlugIn::handleEvent(Event* event) 157{ 158 if (!event->isMouseEvent()) 159 return; 160 161 MouseEvent* mouseEvent = toMouseEvent(event); 162 163 // If we're a snapshotted plugin, we want to make sure we activate on 164 // clicks even if the page is preventing our default behaviour. Otherwise 165 // we can never restart. One we do restart, then the page will happily 166 // block the new plugin in the normal renderer. All this means we have to 167 // be on the lookout for a mouseup event that comes after a mousedown 168 // event. The code below is not completely foolproof, but the worst that 169 // could happen is that a snapshotted plugin restarts. 170 171 if (event->type() == eventNames().mouseoutEvent) 172 m_isPotentialMouseActivation = false; 173 174 if (mouseEvent->button() != LeftButton) 175 return; 176 177 if (event->type() == eventNames().clickEvent || (m_isPotentialMouseActivation && event->type() == eventNames().mouseupEvent)) { 178 m_isPotentialMouseActivation = false; 179 bool clickWasOnOverlay = plugInImageElement().partOfSnapshotOverlay(event->target()->toNode()); 180 plugInImageElement().userDidClickSnapshot(mouseEvent, !clickWasOnOverlay); 181 event->setDefaultHandled(); 182 } else if (event->type() == eventNames().mousedownEvent) { 183 m_isPotentialMouseActivation = true; 184 event->setDefaultHandled(); 185 } 186} 187 188} // namespace WebCore 189