Use is<>() / downcast<>() for Element
[WebKit-https.git] / Source / WebKit2 / 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 PassRefPtr<InjectedBundleNodeHandle> InjectedBundleNodeHandle::getOrCreate(JSContextRef, JSObjectRef object)
72 {
73     Node* node = JSNode::toWrapped(toJS(object));
74     return getOrCreate(node);
75 }
76
77 PassRefPtr<InjectedBundleNodeHandle> InjectedBundleNodeHandle::getOrCreate(Node* node)
78 {
79     if (!node)
80         return 0;
81
82     DOMHandleCache::AddResult result = domHandleCache().add(node, nullptr);
83     if (!result.isNewEntry)
84         return PassRefPtr<InjectedBundleNodeHandle>(result.iterator->value);
85
86     RefPtr<InjectedBundleNodeHandle> nodeHandle = InjectedBundleNodeHandle::create(node);
87     result.iterator->value = nodeHandle.get();
88     return nodeHandle.release();
89 }
90
91 PassRefPtr<InjectedBundleNodeHandle> InjectedBundleNodeHandle::create(Node* node)
92 {
93     return adoptRef(new InjectedBundleNodeHandle(node));
94 }
95
96 InjectedBundleNodeHandle::InjectedBundleNodeHandle(Node* node)
97     : m_node(node)
98 {
99 }
100
101 InjectedBundleNodeHandle::~InjectedBundleNodeHandle()
102 {
103     domHandleCache().remove(m_node.get());
104 }
105
106 Node* InjectedBundleNodeHandle::coreNode() const
107 {
108     return m_node.get();
109 }
110
111 PassRefPtr<InjectedBundleNodeHandle> InjectedBundleNodeHandle::document()
112 {
113     return getOrCreate(&m_node->document());
114 }
115
116 // Additional DOM Operations
117 // Note: These should only be operations that are not exposed to JavaScript.
118
119 IntRect InjectedBundleNodeHandle::elementBounds() const
120 {
121     if (!is<Element>(*m_node))
122         return IntRect();
123
124     return downcast<Element>(*m_node).boundsInRootViewSpace();
125 }
126     
127 IntRect InjectedBundleNodeHandle::renderRect(bool* isReplaced) const
128 {
129     return m_node.get()->pixelSnappedRenderRect(isReplaced);
130 }
131
132 static PassRefPtr<WebImage> imageForRect(FrameView* frameView, const IntRect& rect, SnapshotOptions options)
133 {
134     IntSize bitmapSize = rect.size();
135     float scaleFactor = frameView->frame().page()->deviceScaleFactor();
136     bitmapSize.scale(scaleFactor);
137
138     RefPtr<WebImage> snapshot = WebImage::create(bitmapSize, snapshotOptionsToImageOptions(options));
139     if (!snapshot->bitmap())
140         return 0;
141
142     auto graphicsContext = snapshot->bitmap()->createGraphicsContext();
143     graphicsContext->clearRect(IntRect(IntPoint(), bitmapSize));
144     graphicsContext->applyDeviceScaleFactor(scaleFactor);
145     graphicsContext->translate(-rect.x(), -rect.y());
146
147     FrameView::SelectionInSnapshot shouldPaintSelection = FrameView::IncludeSelection;
148     if (options & SnapshotOptionsExcludeSelectionHighlighting)
149         shouldPaintSelection = FrameView::ExcludeSelection;
150
151     PaintBehavior paintBehavior = frameView->paintBehavior() | PaintBehaviorFlattenCompositingLayers;
152     if (options & SnapshotOptionsForceBlackText)
153         paintBehavior |= PaintBehaviorForceBlackText;
154     if (options & SnapshotOptionsForceWhiteText)
155         paintBehavior |= PaintBehaviorForceWhiteText;
156
157     PaintBehavior oldPaintBehavior = frameView->paintBehavior();
158     frameView->setPaintBehavior(paintBehavior);
159     frameView->paintContentsForSnapshot(graphicsContext.get(), rect, shouldPaintSelection, FrameView::DocumentCoordinates);
160     frameView->setPaintBehavior(oldPaintBehavior);
161
162     return snapshot.release();
163 }
164
165 PassRefPtr<WebImage> InjectedBundleNodeHandle::renderedImage(SnapshotOptions options)
166 {
167     Frame* frame = m_node->document().frame();
168     if (!frame)
169         return 0;
170
171     FrameView* frameView = frame->view();
172     if (!frameView)
173         return 0;
174
175     m_node->document().updateLayout();
176
177     RenderObject* renderer = m_node->renderer();
178     if (!renderer)
179         return 0;
180
181     LayoutRect topLevelRect;
182     IntRect paintingRect = snappedIntRect(renderer->paintingRootRect(topLevelRect));
183
184     frameView->setNodeToDraw(m_node.get());
185     RefPtr<WebImage> image = imageForRect(frameView, paintingRect, options);
186     frameView->setNodeToDraw(0);
187
188     return image.release();
189 }
190
191 PassRefPtr<InjectedBundleRangeHandle> InjectedBundleNodeHandle::visibleRange() const
192 {
193     VisiblePosition start = firstPositionInNode(m_node.get());
194     VisiblePosition end = lastPositionInNode(m_node.get());
195
196     RefPtr<Range> range = makeRange(start, end);
197     return InjectedBundleRangeHandle::getOrCreate(range.get());
198 }
199
200 void InjectedBundleNodeHandle::setHTMLInputElementValueForUser(const String& value)
201 {
202     if (!is<HTMLInputElement>(*m_node))
203         return;
204
205     downcast<HTMLInputElement>(*m_node).setValueForUser(value);
206 }
207
208 bool InjectedBundleNodeHandle::isHTMLInputElementAutofilled() const
209 {
210     if (!is<HTMLInputElement>(*m_node))
211         return false;
212     
213     return downcast<HTMLInputElement>(*m_node).isAutofilled();
214 }
215
216 void InjectedBundleNodeHandle::setHTMLInputElementAutofilled(bool filled)
217 {
218     if (!is<HTMLInputElement>(*m_node))
219         return;
220
221     downcast<HTMLInputElement>(*m_node).setAutofilled(filled);
222 }
223
224 bool InjectedBundleNodeHandle::htmlInputElementLastChangeWasUserEdit()
225 {
226     if (!is<HTMLInputElement>(*m_node))
227         return false;
228
229     return downcast<HTMLInputElement>(*m_node).lastChangeWasUserEdit();
230 }
231
232 bool InjectedBundleNodeHandle::htmlTextAreaElementLastChangeWasUserEdit()
233 {
234     if (!is<HTMLTextAreaElement>(*m_node))
235         return false;
236
237     return downcast<HTMLTextAreaElement>(*m_node).lastChangeWasUserEdit();
238 }
239
240 bool InjectedBundleNodeHandle::isTextField() const
241 {
242     return is<HTMLInputElement>(*m_node) && downcast<HTMLInputElement>(*m_node).isText();
243 }
244
245 PassRefPtr<InjectedBundleNodeHandle> InjectedBundleNodeHandle::htmlTableCellElementCellAbove()
246 {
247     if (!m_node->hasTagName(tdTag))
248         return nullptr;
249
250     return getOrCreate(static_cast<HTMLTableCellElement&>(*m_node).cellAbove());
251 }
252
253 PassRefPtr<WebFrame> InjectedBundleNodeHandle::documentFrame()
254 {
255     if (!m_node->isDocumentNode())
256         return nullptr;
257
258     Frame* frame = static_cast<Document*>(m_node.get())->frame();
259     if (!frame)
260         return nullptr;
261
262     return WebFrame::fromCoreFrame(*frame);
263 }
264
265 PassRefPtr<WebFrame> InjectedBundleNodeHandle::htmlFrameElementContentFrame()
266 {
267     if (!m_node->hasTagName(frameTag))
268         return nullptr;
269
270     Frame* frame = static_cast<HTMLFrameElement*>(m_node.get())->contentFrame();
271     if (!frame)
272         return nullptr;
273
274     return WebFrame::fromCoreFrame(*frame);
275 }
276
277 PassRefPtr<WebFrame> InjectedBundleNodeHandle::htmlIFrameElementContentFrame()
278 {
279     if (!is<HTMLIFrameElement>(*m_node))
280         return nullptr;
281
282     Frame* frame = downcast<HTMLIFrameElement>(*m_node).contentFrame();
283     if (!frame)
284         return nullptr;
285
286     return WebFrame::fromCoreFrame(*frame);
287 }
288
289 } // namespace WebKit