Change visual look of placeholder
[WebKit-https.git] / Source / WebCore / rendering / RenderSnapshottedPlugIn.cpp
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 "Cursor.h"
30 #include "FrameLoaderClient.h"
31 #include "FrameView.h"
32 #include "Gradient.h"
33 #include "HTMLPlugInImageElement.h"
34 #include "MouseEvent.h"
35 #include "PaintInfo.h"
36 #include "Path.h"
37
38 namespace WebCore {
39
40 static const int autoStartPlugInSizeThresholdWidth = 1;
41 static const int autoStartPlugInSizeThresholdHeight = 1;
42 static const int startButtonPadding = 10;
43
44 RenderSnapshottedPlugIn::RenderSnapshottedPlugIn(HTMLPlugInImageElement* element)
45     : RenderEmbeddedObject(element)
46     , m_snapshotResource(RenderImageResource::create())
47     , m_isMouseInButtonRect(false)
48 {
49     m_snapshotResource->initialize(this);
50 }
51
52 RenderSnapshottedPlugIn::~RenderSnapshottedPlugIn()
53 {
54     ASSERT(m_snapshotResource);
55     m_snapshotResource->shutdown();
56 }
57
58 HTMLPlugInImageElement* RenderSnapshottedPlugIn::plugInImageElement() const
59 {
60     return static_cast<HTMLPlugInImageElement*>(node());
61 }
62
63 void RenderSnapshottedPlugIn::updateSnapshot(PassRefPtr<Image> image)
64 {
65     // Zero-size plugins will have no image.
66     if (!image)
67         return;
68
69     m_snapshotResource->setCachedImage(new CachedImage(image.get()));
70     repaint();
71 }
72
73 void RenderSnapshottedPlugIn::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
74 {
75     if (plugInImageElement()->displayState() < HTMLPlugInElement::Playing) {
76         RenderReplaced::paint(paintInfo, paintOffset);
77         return;
78     }
79
80     RenderEmbeddedObject::paint(paintInfo, paintOffset);
81 }
82
83 void RenderSnapshottedPlugIn::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
84 {
85     if (plugInImageElement()->displayState() < HTMLPlugInElement::Playing) {
86         paintReplacedSnapshot(paintInfo, paintOffset);
87         paintButton(paintInfo, paintOffset);
88         return;
89     }
90
91     RenderEmbeddedObject::paintReplaced(paintInfo, paintOffset);
92 }
93
94 void RenderSnapshottedPlugIn::paintReplacedSnapshot(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
95 {
96     // This code should be similar to RenderImage::paintReplaced() and RenderImage::paintIntoRect().
97     LayoutUnit cWidth = contentWidth();
98     LayoutUnit cHeight = contentHeight();
99     if (!cWidth || !cHeight)
100         return;
101
102     RefPtr<Image> image = m_snapshotResource->image();
103     if (!image || image->isNull())
104         return;
105
106     GraphicsContext* context = paintInfo.context;
107 #if PLATFORM(MAC)
108     if (style()->highlight() != nullAtom && !context->paintingDisabled())
109         paintCustomHighlight(toPoint(paintOffset - location()), style()->highlight(), true);
110 #endif
111
112     LayoutSize contentSize(cWidth, cHeight);
113     LayoutPoint contentLocation = paintOffset;
114     contentLocation.move(borderLeft() + paddingLeft(), borderTop() + paddingTop());
115
116     LayoutRect rect(contentLocation, contentSize);
117     IntRect alignedRect = pixelSnappedIntRect(rect);
118     if (alignedRect.width() <= 0 || alignedRect.height() <= 0)
119         return;
120
121     bool useLowQualityScaling = shouldPaintAtLowQuality(context, image.get(), image.get(), alignedRect.size());
122     context->drawImage(image.get(), style()->colorSpace(), alignedRect, CompositeSourceOver, shouldRespectImageOrientation(), useLowQualityScaling);
123 }
124
125 static Image* startButtonImage()
126 {
127     static Image* buttonImage = Image::loadPlatformResource("startButton").leakRef();
128     return buttonImage;
129 }
130
131 static Image* startButtonPressedImage()
132 {
133     static Image* buttonImage = Image::loadPlatformResource("startButtonPressed").leakRef();
134     return buttonImage;
135 }
136
137 void RenderSnapshottedPlugIn::paintButton(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
138 {
139     LayoutRect contentRect = contentBoxRect();
140     if (contentRect.isEmpty())
141         return;
142
143     Image* buttonImage = startButtonImage();
144     if (plugInImageElement()->active()) {
145         if (m_isMouseInButtonRect)
146             buttonImage = startButtonPressedImage();
147     } else if (!plugInImageElement()->hovered())
148         return;
149
150     LayoutPoint contentLocation = paintOffset + contentRect.maxXMaxYCorner() - buttonImage->size() - LayoutSize(startButtonPadding, startButtonPadding);
151     paintInfo.context->drawImage(buttonImage, ColorSpaceDeviceRGB, roundedIntPoint(contentLocation), buttonImage->rect());
152 }
153
154 void RenderSnapshottedPlugIn::repaintButton()
155 {
156     // FIXME: This is unfortunate. We should just repaint the button.
157     repaint();
158 }
159
160 CursorDirective RenderSnapshottedPlugIn::getCursor(const LayoutPoint& point, Cursor& overrideCursor) const
161 {
162     if (plugInImageElement()->displayState() < HTMLPlugInElement::Playing) {
163         overrideCursor = handCursor();
164         return SetCursor;
165     }
166     return RenderEmbeddedObject::getCursor(point, overrideCursor);
167 }
168
169 void RenderSnapshottedPlugIn::handleEvent(Event* event)
170 {
171     if (!event->isMouseEvent())
172         return;
173
174     MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
175
176     if (event->type() == eventNames().clickEvent && mouseEvent->button() == LeftButton) {
177         plugInImageElement()->setDisplayState(HTMLPlugInElement::Playing);
178         if (widget()) {
179             if (Frame* frame = document()->frame())
180                 frame->loader()->client()->recreatePlugin(widget());
181             repaint();
182         }
183         event->setDefaultHandled();
184     } else if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent)
185         repaintButton();
186     else if (event->type() == eventNames().mousedownEvent) {
187         bool isMouseInButtonRect = m_buttonRect.contains(IntPoint(mouseEvent->offsetX(), mouseEvent->offsetY()));
188         if (isMouseInButtonRect != m_isMouseInButtonRect) {
189             m_isMouseInButtonRect = isMouseInButtonRect;
190             repaintButton();
191         }
192     }
193 }
194
195 void RenderSnapshottedPlugIn::layout()
196 {
197     RenderEmbeddedObject::layout();
198     if (plugInImageElement()->displayState() < HTMLPlugInElement::Playing) {
199         LayoutRect rect = contentBoxRect();
200         int width = rect.width();
201         int height = rect.height();
202         if (!width || !height || (width <= autoStartPlugInSizeThresholdWidth && height <= autoStartPlugInSizeThresholdHeight))
203             plugInImageElement()->setDisplayState(HTMLPlugInElement::Playing);
204     }
205
206     LayoutSize buttonSize = startButtonImage()->size();
207     m_buttonRect = LayoutRect(contentBoxRect().maxXMaxYCorner() - LayoutSize(startButtonPadding, startButtonPadding) - buttonSize, buttonSize);
208 }
209
210 } // namespace WebCore