1 /*
2 * Copyright (C) 2008 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. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "EmbeddedWidget.h"
28
29 #include <WebCore/Document.h>
30 #include <WebCore/Element.h>
31 #include <WebCore/FrameView.h>
32 #include <WebCore/RenderObject.h>
33
34 #include "MemoryStream.h"
35 #include "WebError.h"
36 #include "WebURLResponse.h"
37
38 using namespace WebCore;
39
create(IWebEmbeddedView * view,Element * element,HWND parentWindow,const IntSize & size)40 PassRefPtr<EmbeddedWidget> EmbeddedWidget::create(IWebEmbeddedView* view, Element* element, HWND parentWindow, const IntSize& size)
41 {
42 RefPtr<EmbeddedWidget> widget = adoptRef(new EmbeddedWidget(view, element));
43
44 widget->createWindow(parentWindow, size);
45 return widget.release();
46 }
47
~EmbeddedWidget()48 EmbeddedWidget::~EmbeddedWidget()
49 {
50 if (m_window)
51 DestroyWindow(m_window);
52 }
53
createWindow(HWND parentWindow,const IntSize & size)54 bool EmbeddedWidget::createWindow(HWND parentWindow, const IntSize& size)
55 {
56 ASSERT(!m_window);
57
58 HWND window;
59
60 SIZE pluginSize(size);
61
62 HRESULT hr = m_view->createViewWindow((OLE_HANDLE)parentWindow, &pluginSize, (OLE_HANDLE*)&window);
63
64 if (FAILED(hr) || !window)
65 return false;
66
67 m_window = window;
68 return true;
69 }
70
invalidateRect(const IntRect & rect)71 void EmbeddedWidget::invalidateRect(const IntRect& rect)
72 {
73 if (!m_window)
74 return;
75
76 RECT r = rect;
77 ::InvalidateRect(m_window, &r, false);
78 }
79
setFrameRect(const IntRect & rect)80 void EmbeddedWidget::setFrameRect(const IntRect& rect)
81 {
82 if (m_element->document()->printing())
83 return;
84
85 if (rect != frameRect())
86 Widget::setFrameRect(rect);
87
88 frameRectsChanged();
89 }
90
frameRectsChanged()91 void EmbeddedWidget::frameRectsChanged()
92 {
93 if (!parent())
94 return;
95
96 ASSERT(parent()->isFrameView());
97 FrameView* frameView = static_cast<FrameView*>(parent());
98
99 IntRect oldWindowRect = m_windowRect;
100 IntRect oldClipRect = m_clipRect;
101
102 m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size());
103 m_clipRect = windowClipRect();
104 m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
105
106 if (!m_window)
107 return;
108
109 if (m_windowRect == oldWindowRect && m_clipRect == oldClipRect)
110 return;
111
112 HRGN rgn;
113
114 // To prevent flashes while scrolling, we disable drawing during the window
115 // update process by clipping the window to the zero rect.
116
117 bool clipToZeroRect = true;
118
119 if (clipToZeroRect) {
120 rgn = ::CreateRectRgn(0, 0, 0, 0);
121 ::SetWindowRgn(m_window, rgn, FALSE);
122 } else {
123 rgn = ::CreateRectRgn(m_clipRect.x(), m_clipRect.y(), m_clipRect.maxX(), m_clipRect.maxY());
124 ::SetWindowRgn(m_window, rgn, TRUE);
125 }
126
127 if (m_windowRect != oldWindowRect)
128 ::MoveWindow(m_window, m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height(), TRUE);
129
130 if (clipToZeroRect) {
131 rgn = ::CreateRectRgn(m_clipRect.x(), m_clipRect.y(), m_clipRect.maxX(), m_clipRect.maxY());
132 ::SetWindowRgn(m_window, rgn, TRUE);
133 }
134 }
135
setFocus(bool focused)136 void EmbeddedWidget::setFocus(bool focused)
137 {
138 if (m_window && focused)
139 SetFocus(m_window);
140
141 Widget::setFocus(focused);
142 }
143
show()144 void EmbeddedWidget::show()
145 {
146 m_isVisible = true;
147
148 if (m_attachedToWindow && m_window)
149 ShowWindow(m_window, SW_SHOWNA);
150
151 Widget::show();
152 }
153
hide()154 void EmbeddedWidget::hide()
155 {
156 m_isVisible = false;
157
158 if (m_attachedToWindow && m_window)
159 ShowWindow(m_window, SW_HIDE);
160
161 Widget::hide();
162 }
163
windowClipRect() const164 IntRect EmbeddedWidget::windowClipRect() const
165 {
166 // Start by clipping to our bounds.
167 IntRect clipRect(m_windowRect);
168
169 // Take our element and get the clip rect from the enclosing layer and frame view.
170 RenderLayer* layer = m_element->renderer()->enclosingLayer();
171 FrameView* parentView = m_element->document()->view();
172 clipRect.intersect(parentView->windowClipRectForLayer(layer, true));
173
174 return clipRect;
175 }
176
setParent(ScrollView * parent)177 void EmbeddedWidget::setParent(ScrollView* parent)
178 {
179 Widget::setParent(parent);
180
181 if (!m_window)
182 return;
183
184 if (parent)
185 return;
186
187 // If the embedded window or one of its children have the focus, we need to
188 // clear it to prevent the web view window from being focused because that can
189 // trigger a layout while the plugin element is being detached.
190 HWND focusedWindow = ::GetFocus();
191 if (m_window == focusedWindow || ::IsChild(m_window, focusedWindow))
192 ::SetFocus(0);
193 }
194
attachToWindow()195 void EmbeddedWidget::attachToWindow()
196 {
197 if (m_attachedToWindow)
198 return;
199
200 m_attachedToWindow = true;
201 if (m_isVisible && m_window)
202 ShowWindow(m_window, SW_SHOWNA);
203 }
204
detachFromWindow()205 void EmbeddedWidget::detachFromWindow()
206 {
207 if (!m_attachedToWindow)
208 return;
209
210 if (m_isVisible && m_window)
211 ShowWindow(m_window, SW_HIDE);
212 m_attachedToWindow = false;
213 }
214
didReceiveResponse(const ResourceResponse & response)215 void EmbeddedWidget::didReceiveResponse(const ResourceResponse& response)
216 {
217 ASSERT(m_view);
218
219 COMPtr<IWebURLResponse> urlResponse(AdoptCOM, WebURLResponse::createInstance(response));
220 m_view->didReceiveResponse(urlResponse.get());
221 }
222
didReceiveData(const char * data,int length)223 void EmbeddedWidget::didReceiveData(const char* data, int length)
224 {
225 COMPtr<MemoryStream> stream = MemoryStream::createInstance(SharedBuffer::create(data, length));
226 m_view->didReceiveData(stream.get());
227 }
228
didFinishLoading()229 void EmbeddedWidget::didFinishLoading()
230 {
231 m_view->didFinishLoading();
232 }
233
didFail(const ResourceError & error)234 void EmbeddedWidget::didFail(const ResourceError& error)
235 {
236 COMPtr<IWebError> webError(AdoptCOM, WebError::createInstance(error));
237 m_view->didFail(webError.get());
238 }
239