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