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