Use enum classes and OptionSets for PaintPhase and PaintBehavior
[WebKit-https.git] / Source / WebKit / WebProcess / InjectedBundle / DOM / InjectedBundleNodeHandle.cpp
1 /*
2  * Copyright (C) 2010 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 "InjectedBundleNodeHandle.h"
28
29 #include "InjectedBundleRangeHandle.h"
30 #include "ShareableBitmap.h"
31 #include "WebFrame.h"
32 #include "WebFrameLoaderClient.h"
33 #include "WebImage.h"
34 #include <JavaScriptCore/APICast.h>
35 #include <WebCore/Document.h>
36 #include <WebCore/Frame.h>
37 #include <WebCore/FrameLoader.h>
38 #include <WebCore/FrameView.h>
39 #include <WebCore/GraphicsContext.h>
40 #include <WebCore/HTMLFrameElement.h>
41 #include <WebCore/HTMLIFrameElement.h>
42 #include <WebCore/HTMLInputElement.h>
43 #include <WebCore/HTMLNames.h>
44 #include <WebCore/HTMLTableCellElement.h>
45 #include <WebCore/HTMLTextAreaElement.h>
46 #include <WebCore/IntRect.h>
47 #include <WebCore/JSNode.h>
48 #include <WebCore/Node.h>
49 #include <WebCore/Page.h>
50 #include <WebCore/Position.h>
51 #include <WebCore/Range.h>
52 #include <WebCore/RenderObject.h>
53 #include <WebCore/VisiblePosition.h>
54 #include <wtf/HashMap.h>
55 #include <wtf/NeverDestroyed.h>
56 #include <wtf/text/WTFString.h>
57
58 using namespace WebCore;
59 using namespace HTMLNames;
60
61 namespace WebKit {
62
63 typedef HashMap<Node*, InjectedBundleNodeHandle*> DOMHandleCache;
64
65 static DOMHandleCache& domHandleCache()
66 {
67     static NeverDestroyed<DOMHandleCache> cache;
68     return cache;
69 }
70
71 RefPtr<InjectedBundleNodeHandle> InjectedBundleNodeHandle::getOrCreate(JSContextRef, JSObjectRef object)
72 {
73     Node* node = JSNode::toWrapped(*toJS(object)->vm(), toJS(object));
74     return getOrCreate(node);
75 }
76
77 RefPtr<InjectedBundleNodeHandle> InjectedBundleNodeHandle::getOrCreate(Node* node)
78 {
79     if (!node)
80         return nullptr;
81
82     return InjectedBundleNodeHandle::getOrCreate(*node);
83 }
84
85 Ref<InjectedBundleNodeHandle> InjectedBundleNodeHandle::getOrCreate(Node& node)
86 {
87     DOMHandleCache::AddResult result = domHandleCache().add(&node, nullptr);
88     if (!result.isNewEntry)
89         return Ref<InjectedBundleNodeHandle>(*result.iterator->value);
90
91     Ref<InjectedBundleNodeHandle> nodeHandle = InjectedBundleNodeHandle::create(node);
92     result.iterator->value = nodeHandle.ptr();
93     return nodeHandle;
94 }
95
96 Ref<InjectedBundleNodeHandle> InjectedBundleNodeHandle::create(Node& node)
97 {
98     return adoptRef(*new InjectedBundleNodeHandle(node));
99 }
100
101 InjectedBundleNodeHandle::InjectedBundleNodeHandle(Node& node)
102     : m_node(node)
103 {
104 }
105
106 InjectedBundleNodeHandle::~InjectedBundleNodeHandle()
107 {
108     domHandleCache().remove(m_node.ptr());
109 }
110
111 Node* InjectedBundleNodeHandle::coreNode()
112 {
113     return m_node.ptr();
114 }
115
116 Ref<InjectedBundleNodeHandle> InjectedBundleNodeHandle::document()
117 {
118     return getOrCreate(m_node->document());
119 }
120
121 // Additional DOM Operations
122 // Note: These should only be operations that are not exposed to JavaScript.
123
124 IntRect InjectedBundleNodeHandle::elementBounds()
125 {
126     if (!is<Element>(m_node))
127         return IntRect();
128
129     return downcast<Element>(m_node.get()).boundsInRootViewSpace();
130 }
131     
132 IntRect InjectedBundleNodeHandle::renderRect(bool* isReplaced)
133 {
134     return m_node->pixelSnappedRenderRect(isReplaced);
135 }
136
137 static RefPtr<WebImage> imageForRect(FrameView* frameView, const IntRect& paintingRect, const std::optional<float>& bitmapWidth, SnapshotOptions options)
138 {
139     if (paintingRect.isEmpty())
140         return nullptr;
141
142     float bitmapScaleFactor;
143     IntSize bitmapSize;
144     if (bitmapWidth) {
145         bitmapScaleFactor = bitmapWidth.value() / paintingRect.width();
146         bitmapSize = roundedIntSize(FloatSize(bitmapWidth.value(), paintingRect.height() * bitmapScaleFactor));
147     } else {
148         bitmapScaleFactor = 1;
149         bitmapSize = paintingRect.size();
150     }
151
152     float deviceScaleFactor = frameView->frame().page()->deviceScaleFactor();
153     bitmapSize.scale(deviceScaleFactor);
154
155     if (bitmapSize.isEmpty())
156         return nullptr;
157
158     auto snapshot = WebImage::create(bitmapSize, snapshotOptionsToImageOptions(options));
159     if (!snapshot)
160         return nullptr;
161
162     auto graphicsContext = snapshot->bitmap().createGraphicsContext();
163     graphicsContext->clearRect(IntRect(IntPoint(), bitmapSize));
164     graphicsContext->applyDeviceScaleFactor(deviceScaleFactor);
165     graphicsContext->scale(bitmapScaleFactor);
166     graphicsContext->translate(-paintingRect.location());
167
168     FrameView::SelectionInSnapshot shouldPaintSelection = FrameView::IncludeSelection;
169     if (options & SnapshotOptionsExcludeSelectionHighlighting)
170         shouldPaintSelection = FrameView::ExcludeSelection;
171
172     auto paintBehavior = frameView->paintBehavior() | PaintBehavior::FlattenCompositingLayers | PaintBehavior::Snapshotting;
173     if (options & SnapshotOptionsForceBlackText)
174         paintBehavior |= PaintBehavior::ForceBlackText;
175     if (options & SnapshotOptionsForceWhiteText)
176         paintBehavior |= PaintBehavior::ForceWhiteText;
177
178     auto oldPaintBehavior = frameView->paintBehavior();
179     frameView->setPaintBehavior(paintBehavior);
180     frameView->paintContentsForSnapshot(*graphicsContext.get(), paintingRect, shouldPaintSelection, FrameView::DocumentCoordinates);
181     frameView->setPaintBehavior(oldPaintBehavior);
182
183     return snapshot;
184 }
185
186 RefPtr<WebImage> InjectedBundleNodeHandle::renderedImage(SnapshotOptions options, bool shouldExcludeOverflow, const std::optional<float>& bitmapWidth)
187 {
188     Frame* frame = m_node->document().frame();
189     if (!frame)
190         return nullptr;
191
192     FrameView* frameView = frame->view();
193     if (!frameView)
194         return nullptr;
195
196     m_node->document().updateLayout();
197
198     RenderObject* renderer = m_node->renderer();
199     if (!renderer)
200         return nullptr;
201
202     IntRect paintingRect;
203     if (shouldExcludeOverflow)
204         paintingRect = renderer->absoluteBoundingBoxRectIgnoringTransforms();
205     else {
206         LayoutRect topLevelRect;
207         paintingRect = snappedIntRect(renderer->paintingRootRect(topLevelRect));
208     }
209
210     frameView->setNodeToDraw(m_node.ptr());
211     auto image = imageForRect(frameView, paintingRect, bitmapWidth, options);
212     frameView->setNodeToDraw(0);
213
214     return image;
215 }
216
217 RefPtr<InjectedBundleRangeHandle> InjectedBundleNodeHandle::visibleRange()
218 {
219     VisiblePosition start = firstPositionInNode(m_node.ptr());
220     VisiblePosition end = lastPositionInNode(m_node.ptr());
221
222     RefPtr<Range> range = makeRange(start, end);
223     return InjectedBundleRangeHandle::getOrCreate(range.get());
224 }
225
226 void InjectedBundleNodeHandle::setHTMLInputElementValueForUser(const String& value)
227 {
228     if (!is<HTMLInputElement>(m_node))
229         return;
230
231     downcast<HTMLInputElement>(m_node.get()).setValueForUser(value);
232 }
233
234 void InjectedBundleNodeHandle::setHTMLInputElementSpellcheckEnabled(bool enabled)
235 {
236     if (!is<HTMLInputElement>(m_node))
237         return;
238
239     downcast<HTMLInputElement>(m_node.get()).setSpellcheckDisabledExceptTextReplacement(!enabled);
240 }
241
242 bool InjectedBundleNodeHandle::isHTMLInputElementAutoFilled() const
243 {
244     if (!is<HTMLInputElement>(m_node))
245         return false;
246     
247     return downcast<HTMLInputElement>(m_node.get()).isAutoFilled();
248 }
249
250 void InjectedBundleNodeHandle::setHTMLInputElementAutoFilled(bool filled)
251 {
252     if (!is<HTMLInputElement>(m_node))
253         return;
254
255     downcast<HTMLInputElement>(m_node.get()).setAutoFilled(filled);
256 }
257
258 bool InjectedBundleNodeHandle::isHTMLInputElementAutoFillButtonEnabled() const
259 {
260     if (!is<HTMLInputElement>(m_node))
261         return false;
262     
263     return downcast<HTMLInputElement>(m_node.get()).autoFillButtonType() != AutoFillButtonType::None;
264 }
265
266 void InjectedBundleNodeHandle::setHTMLInputElementAutoFillButtonEnabled(AutoFillButtonType autoFillButtonType)
267 {
268     if (!is<HTMLInputElement>(m_node))
269         return;
270
271     downcast<HTMLInputElement>(m_node.get()).setShowAutoFillButton(autoFillButtonType);
272 }
273
274 AutoFillButtonType InjectedBundleNodeHandle::htmlInputElementAutoFillButtonType() const
275 {
276     if (!is<HTMLInputElement>(m_node))
277         return AutoFillButtonType::None;
278     return downcast<HTMLInputElement>(m_node.get()).autoFillButtonType();
279 }
280
281 AutoFillButtonType InjectedBundleNodeHandle::htmlInputElementLastAutoFillButtonType() const
282 {
283     if (!is<HTMLInputElement>(m_node))
284         return AutoFillButtonType::None;
285     return downcast<HTMLInputElement>(m_node.get()).lastAutoFillButtonType();
286 }
287
288 bool InjectedBundleNodeHandle::isAutoFillAvailable() const
289 {
290     if (!is<HTMLInputElement>(m_node))
291         return false;
292
293     return downcast<HTMLInputElement>(m_node.get()).isAutoFillAvailable();
294 }
295
296 void InjectedBundleNodeHandle::setAutoFillAvailable(bool autoFillAvailable)
297 {
298     if (!is<HTMLInputElement>(m_node))
299         return;
300
301     downcast<HTMLInputElement>(m_node.get()).setAutoFillAvailable(autoFillAvailable);
302 }
303
304 IntRect InjectedBundleNodeHandle::htmlInputElementAutoFillButtonBounds()
305 {
306     if (!is<HTMLInputElement>(m_node))
307         return IntRect();
308
309     auto autoFillButton = downcast<HTMLInputElement>(m_node.get()).autoFillButtonElement();
310     if (!autoFillButton)
311         return IntRect();
312
313     return autoFillButton->boundsInRootViewSpace();
314 }
315
316 bool InjectedBundleNodeHandle::htmlInputElementLastChangeWasUserEdit()
317 {
318     if (!is<HTMLInputElement>(m_node))
319         return false;
320
321     return downcast<HTMLInputElement>(m_node.get()).lastChangeWasUserEdit();
322 }
323
324 bool InjectedBundleNodeHandle::htmlTextAreaElementLastChangeWasUserEdit()
325 {
326     if (!is<HTMLTextAreaElement>(m_node))
327         return false;
328
329     return downcast<HTMLTextAreaElement>(m_node.get()).lastChangeWasUserEdit();
330 }
331
332 bool InjectedBundleNodeHandle::isTextField() const
333 {
334     if (!is<HTMLInputElement>(m_node))
335         return false;
336
337     return downcast<HTMLInputElement>(m_node.get()).isTextField();
338 }
339
340 RefPtr<InjectedBundleNodeHandle> InjectedBundleNodeHandle::htmlTableCellElementCellAbove()
341 {
342     if (!is<HTMLTableCellElement>(m_node))
343         return nullptr;
344
345     return getOrCreate(downcast<HTMLTableCellElement>(m_node.get()).cellAbove());
346 }
347
348 RefPtr<WebFrame> InjectedBundleNodeHandle::documentFrame()
349 {
350     if (!m_node->isDocumentNode())
351         return nullptr;
352
353     Frame* frame = downcast<Document>(m_node.get()).frame();
354     if (!frame)
355         return nullptr;
356
357     return WebFrame::fromCoreFrame(*frame);
358 }
359
360 RefPtr<WebFrame> InjectedBundleNodeHandle::htmlFrameElementContentFrame()
361 {
362     if (!is<HTMLFrameElement>(m_node))
363         return nullptr;
364
365     Frame* frame = downcast<HTMLFrameElement>(m_node.get()).contentFrame();
366     if (!frame)
367         return nullptr;
368
369     return WebFrame::fromCoreFrame(*frame);
370 }
371
372 RefPtr<WebFrame> InjectedBundleNodeHandle::htmlIFrameElementContentFrame()
373 {
374     if (!is<HTMLIFrameElement>(m_node))
375         return nullptr;
376
377     Frame* frame = downcast<HTMLIFrameElement>(m_node.get()).contentFrame();
378     if (!frame)
379         return nullptr;
380
381     return WebFrame::fromCoreFrame(*frame);
382 }
383
384 } // namespace WebKit