Followup (r220289): RenderImageResourceStyleImage code clean up
[WebKit-https.git] / Source / WebCore / rendering / RenderSnapshottedPlugIn.cpp
1 /*
2  * Copyright (C) 2012-2017 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 "Cursor.h"
31 #include "EventNames.h"
32 #include "Filter.h"
33 #include "Frame.h"
34 #include "FrameLoaderClient.h"
35 #include "FrameView.h"
36 #include "Gradient.h"
37 #include "HTMLPlugInImageElement.h"
38 #include "ImageBuffer.h"
39 #include "MouseEvent.h"
40 #include "Page.h"
41 #include "PaintInfo.h"
42 #include "Path.h"
43 #include "PlatformMouseEvent.h"
44 #include "RenderImageResource.h"
45 #include "RenderIterator.h"
46 #include "RenderView.h"
47 #include <wtf/StackStats.h>
48
49 namespace WebCore {
50
51 RenderSnapshottedPlugIn::RenderSnapshottedPlugIn(HTMLPlugInImageElement& element, RenderStyle&& style)
52     : RenderEmbeddedObject(element, WTFMove(style))
53     , m_snapshotResource(std::make_unique<RenderImageResource>())
54 {
55     m_snapshotResource->initialize(*this);
56 }
57
58 RenderSnapshottedPlugIn::~RenderSnapshottedPlugIn()
59 {
60     // Do not add any code here. Add it to willBeDestroyed() instead.
61 }
62
63 void RenderSnapshottedPlugIn::willBeDestroyed()
64 {
65     ASSERT(m_snapshotResource);
66     m_snapshotResource->shutdown();
67
68     RenderEmbeddedObject::willBeDestroyed();
69 }
70
71 HTMLPlugInImageElement& RenderSnapshottedPlugIn::plugInImageElement() const
72 {
73     return downcast<HTMLPlugInImageElement>(RenderEmbeddedObject::frameOwnerElement());
74 }
75
76 void RenderSnapshottedPlugIn::layout()
77 {
78     StackStats::LayoutCheckPoint layoutCheckPoint;
79     LayoutSize oldSize = contentBoxRect().size();
80
81     RenderEmbeddedObject::layout();
82
83     LayoutSize newSize = contentBoxRect().size();
84     if (newSize == oldSize)
85         return;
86
87     view().frameView().addEmbeddedObjectToUpdate(*this);
88 }
89
90 void RenderSnapshottedPlugIn::updateSnapshot(Image* image)
91 {
92     // Zero-size plugins will have no image.
93     if (!image)
94         return;
95
96     m_snapshotResource->setCachedImage(new CachedImage(image, page().sessionID()));
97     repaint();
98 }
99
100 void RenderSnapshottedPlugIn::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
101 {
102     if (paintInfo.phase == PaintPhaseForeground && plugInImageElement().displayState() < HTMLPlugInElement::Restarting) {
103         paintSnapshot(paintInfo, paintOffset);
104     }
105
106     PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase;
107     newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase;
108
109     PaintInfo paintInfoForChild(paintInfo);
110     paintInfoForChild.phase = newPhase;
111     paintInfoForChild.updateSubtreePaintRootForChildren(this);
112
113     for (auto& child : childrenOfType<RenderBox>(*this)) {
114         LayoutPoint childPoint = flipForWritingModeForChild(&child, paintOffset);
115         if (!child.hasSelfPaintingLayer() && !child.isFloating())
116             child.paint(paintInfoForChild, childPoint);
117     }
118
119     RenderEmbeddedObject::paint(paintInfo, paintOffset);
120 }
121
122 void RenderSnapshottedPlugIn::paintSnapshot(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
123 {
124     Image* image = m_snapshotResource->image().get();
125     if (!image || image->isNull())
126         return;
127
128     LayoutUnit cWidth = contentWidth();
129     LayoutUnit cHeight = contentHeight();
130     if (!cWidth || !cHeight)
131         return;
132
133     GraphicsContext& context = paintInfo.context();
134
135     LayoutSize contentSize(cWidth, cHeight);
136     LayoutPoint contentLocation = location() + paintOffset;
137     contentLocation.move(borderLeft() + paddingLeft(), borderTop() + paddingTop());
138
139     LayoutRect rect(contentLocation, contentSize);
140     IntRect alignedRect = snappedIntRect(rect);
141     if (alignedRect.width() <= 0 || alignedRect.height() <= 0)
142         return;
143
144     InterpolationQuality interpolation = chooseInterpolationQuality(context, *image, image, alignedRect.size());
145     ImageOrientationDescription orientationDescription(shouldRespectImageOrientation(), style().imageOrientation());
146     context.drawImage(*image, alignedRect, ImagePaintingOptions(orientationDescription, interpolation));
147 }
148
149 CursorDirective RenderSnapshottedPlugIn::getCursor(const LayoutPoint& point, Cursor& overrideCursor) const
150 {
151     if (plugInImageElement().displayState() < HTMLPlugInElement::Restarting) {
152         overrideCursor = handCursor();
153         return SetCursor;
154     }
155     return RenderEmbeddedObject::getCursor(point, overrideCursor);
156 }
157
158 void RenderSnapshottedPlugIn::handleEvent(Event& event)
159 {
160     if (!is<MouseEvent>(event))
161         return;
162
163     auto& mouseEvent = downcast<MouseEvent>(event);
164
165     // If we're a snapshotted plugin, we want to make sure we activate on
166     // clicks even if the page is preventing our default behaviour. Otherwise
167     // we can never restart. One we do restart, then the page will happily
168     // block the new plugin in the normal renderer. All this means we have to
169     // be on the lookout for a mouseup event that comes after a mousedown
170     // event. The code below is not completely foolproof, but the worst that
171     // could happen is that a snapshotted plugin restarts.
172
173     if (mouseEvent.type() == eventNames().mouseoutEvent)
174         m_isPotentialMouseActivation = false;
175
176     if (mouseEvent.button() != LeftButton)
177         return;
178
179     if (mouseEvent.type() == eventNames().clickEvent || (m_isPotentialMouseActivation && mouseEvent.type() == eventNames().mouseupEvent)) {
180         m_isPotentialMouseActivation = false;
181         bool clickWasOnOverlay = plugInImageElement().partOfSnapshotOverlay(mouseEvent.target()->toNode());
182         plugInImageElement().userDidClickSnapshot(mouseEvent, !clickWasOnOverlay);
183         mouseEvent.setDefaultHandled();
184     } else if (mouseEvent.type() == eventNames().mousedownEvent) {
185         m_isPotentialMouseActivation = true;
186         mouseEvent.setDefaultHandled();
187     }
188 }
189
190 } // namespace WebCore