• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "PluginProxy.h"
28 
29 #if ENABLE(PLUGIN_PROCESS)
30 
31 #include "DataReference.h"
32 #include "NPRemoteObjectMap.h"
33 #include "NPRuntimeUtilities.h"
34 #include "NPVariantData.h"
35 #include "PluginController.h"
36 #include "PluginControllerProxyMessages.h"
37 #include "PluginProcessConnection.h"
38 #include "PluginProcessConnectionManager.h"
39 #include "ShareableBitmap.h"
40 #include "WebCoreArgumentCoders.h"
41 #include "WebEvent.h"
42 #include "WebProcessConnectionMessages.h"
43 #include <WebCore/GraphicsContext.h>
44 
45 using namespace WebCore;
46 
47 namespace WebKit {
48 
generatePluginInstanceID()49 static uint64_t generatePluginInstanceID()
50 {
51     static uint64_t uniquePluginInstanceID;
52     return ++uniquePluginInstanceID;
53 }
54 
create(const String & pluginPath)55 PassRefPtr<PluginProxy> PluginProxy::create(const String& pluginPath)
56 {
57     return adoptRef(new PluginProxy(pluginPath));
58 }
59 
PluginProxy(const String & pluginPath)60 PluginProxy::PluginProxy(const String& pluginPath)
61     : m_pluginPath(pluginPath)
62     , m_pluginInstanceID(generatePluginInstanceID())
63     , m_pluginController(0)
64     , m_pluginBackingStoreContainsValidData(false)
65     , m_isStarted(false)
66     , m_waitingForPaintInResponseToUpdate(false)
67     , m_remoteLayerClientID(0)
68 {
69 }
70 
~PluginProxy()71 PluginProxy::~PluginProxy()
72 {
73 }
74 
pluginProcessCrashed()75 void PluginProxy::pluginProcessCrashed()
76 {
77     if (m_pluginController)
78         m_pluginController->pluginProcessCrashed();
79 }
80 
initialize(PluginController * pluginController,const Parameters & parameters)81 bool PluginProxy::initialize(PluginController* pluginController, const Parameters& parameters)
82 {
83     ASSERT(!m_pluginController);
84     ASSERT(pluginController);
85 
86     m_pluginController = pluginController;
87 
88     ASSERT(!m_connection);
89     m_connection = PluginProcessConnectionManager::shared().getPluginProcessConnection(m_pluginPath);
90 
91     if (!m_connection)
92         return false;
93 
94     // Add the plug-in proxy before creating the plug-in; it needs to be in the map because CreatePlugin
95     // can call back out to the plug-in proxy.
96     m_connection->addPluginProxy(this);
97 
98     // Ask the plug-in process to create a plug-in.
99     bool result = false;
100 
101     uint32_t remoteLayerClientID = 0;
102     if (!m_connection->connection()->sendSync(Messages::WebProcessConnection::CreatePlugin(m_pluginInstanceID, parameters, pluginController->userAgent(), pluginController->isPrivateBrowsingEnabled(), pluginController->isAcceleratedCompositingEnabled()), Messages::WebProcessConnection::CreatePlugin::Reply(result, remoteLayerClientID), 0) || !result) {
103         m_connection->removePluginProxy(this);
104         return false;
105     }
106 
107     m_remoteLayerClientID = remoteLayerClientID;
108     m_isStarted = true;
109 
110     return true;
111 }
112 
destroy()113 void PluginProxy::destroy()
114 {
115     ASSERT(m_isStarted);
116 
117     m_connection->connection()->sendSync(Messages::WebProcessConnection::DestroyPlugin(m_pluginInstanceID), Messages::WebProcessConnection::DestroyPlugin::Reply(), 0);
118 
119     m_isStarted = false;
120     m_pluginController = 0;
121 
122     m_connection->removePluginProxy(this);
123 }
124 
paint(GraphicsContext * graphicsContext,const IntRect & dirtyRect)125 void PluginProxy::paint(GraphicsContext* graphicsContext, const IntRect& dirtyRect)
126 {
127     if (!needsBackingStore() || !m_backingStore)
128         return;
129 
130     if (!m_pluginBackingStoreContainsValidData) {
131         m_connection->connection()->sendSync(Messages::PluginControllerProxy::PaintEntirePlugin(), Messages::PluginControllerProxy::PaintEntirePlugin::Reply(), m_pluginInstanceID);
132 
133         // Blit the plug-in backing store into our own backing store.
134         OwnPtr<WebCore::GraphicsContext> graphicsContext = m_backingStore->createGraphicsContext();
135         graphicsContext->setCompositeOperation(CompositeCopy);
136 
137         m_pluginBackingStore->paint(*graphicsContext, IntPoint(), IntRect(0, 0, m_frameRect.width(), m_frameRect.height()));
138 
139         m_pluginBackingStoreContainsValidData = true;
140     }
141 
142     IntRect dirtyRectInPluginCoordinates = dirtyRect;
143     dirtyRectInPluginCoordinates.move(-m_frameRect.x(), -m_frameRect.y());
144 
145     m_backingStore->paint(*graphicsContext, dirtyRect.location(), dirtyRectInPluginCoordinates);
146 
147     if (m_waitingForPaintInResponseToUpdate) {
148         m_waitingForPaintInResponseToUpdate = false;
149         m_connection->connection()->send(Messages::PluginControllerProxy::DidUpdate(), m_pluginInstanceID);
150         return;
151     }
152 }
153 
snapshot()154 PassRefPtr<ShareableBitmap> PluginProxy::snapshot()
155 {
156     ShareableBitmap::Handle snapshotStoreHandle;
157     m_connection->connection()->sendSync(Messages::PluginControllerProxy::Snapshot(), Messages::PluginControllerProxy::Snapshot::Reply(snapshotStoreHandle), m_pluginInstanceID);
158 
159     RefPtr<ShareableBitmap> snapshotBuffer = ShareableBitmap::create(snapshotStoreHandle);
160     return snapshotBuffer.release();
161 }
162 
isTransparent()163 bool PluginProxy::isTransparent()
164 {
165     // This should never be called from the web process.
166     ASSERT_NOT_REACHED();
167     return false;
168 }
169 
geometryDidChange(const IntRect & frameRect,const IntRect & clipRect)170 void PluginProxy::geometryDidChange(const IntRect& frameRect, const IntRect& clipRect)
171 {
172     ASSERT(m_isStarted);
173 
174     m_frameRect = frameRect;
175 
176     if (!needsBackingStore()) {
177         ShareableBitmap::Handle pluginBackingStoreHandle;
178         m_connection->connection()->send(Messages::PluginControllerProxy::GeometryDidChange(frameRect, clipRect, pluginBackingStoreHandle), m_pluginInstanceID, CoreIPC::DispatchMessageEvenWhenWaitingForSyncReply);
179         return;
180     }
181 
182     bool didUpdateBackingStore = false;
183     if (!m_backingStore) {
184         m_backingStore = ShareableBitmap::create(frameRect.size(), ShareableBitmap::SupportsAlpha);
185         didUpdateBackingStore = true;
186     } else if (frameRect.size() != m_backingStore->size()) {
187         // The backing store already exists, just resize it.
188         if (!m_backingStore->resize(frameRect.size()))
189             return;
190 
191         didUpdateBackingStore = true;
192     }
193 
194     ShareableBitmap::Handle pluginBackingStoreHandle;
195 
196     if (didUpdateBackingStore) {
197         // Create a new plug-in backing store.
198         m_pluginBackingStore = ShareableBitmap::createShareable(frameRect.size(), ShareableBitmap::SupportsAlpha);
199         if (!m_pluginBackingStore)
200             return;
201 
202         // Create a handle to the plug-in backing store so we can send it over.
203         if (!m_pluginBackingStore->createHandle(pluginBackingStoreHandle)) {
204             m_pluginBackingStore = nullptr;
205             return;
206         }
207 
208         m_pluginBackingStoreContainsValidData = false;
209     }
210 
211     m_connection->connection()->send(Messages::PluginControllerProxy::GeometryDidChange(frameRect, clipRect, pluginBackingStoreHandle), m_pluginInstanceID, CoreIPC::DispatchMessageEvenWhenWaitingForSyncReply);
212 }
213 
frameDidFinishLoading(uint64_t requestID)214 void PluginProxy::frameDidFinishLoading(uint64_t requestID)
215 {
216     m_connection->connection()->send(Messages::PluginControllerProxy::FrameDidFinishLoading(requestID), m_pluginInstanceID);
217 }
218 
frameDidFail(uint64_t requestID,bool wasCancelled)219 void PluginProxy::frameDidFail(uint64_t requestID, bool wasCancelled)
220 {
221     m_connection->connection()->send(Messages::PluginControllerProxy::FrameDidFail(requestID, wasCancelled), m_pluginInstanceID);
222 }
223 
didEvaluateJavaScript(uint64_t requestID,const WTF::String & requestURLString,const WTF::String & result)224 void PluginProxy::didEvaluateJavaScript(uint64_t requestID, const WTF::String& requestURLString, const WTF::String& result)
225 {
226     m_connection->connection()->send(Messages::PluginControllerProxy::DidEvaluateJavaScript(requestID, requestURLString, result), m_pluginInstanceID);
227 }
228 
streamDidReceiveResponse(uint64_t streamID,const KURL & responseURL,uint32_t streamLength,uint32_t lastModifiedTime,const WTF::String & mimeType,const WTF::String & headers)229 void PluginProxy::streamDidReceiveResponse(uint64_t streamID, const KURL& responseURL, uint32_t streamLength, uint32_t lastModifiedTime, const WTF::String& mimeType, const WTF::String& headers)
230 {
231     m_connection->connection()->send(Messages::PluginControllerProxy::StreamDidReceiveResponse(streamID, responseURL.string(), streamLength, lastModifiedTime, mimeType, headers), m_pluginInstanceID);
232 }
233 
streamDidReceiveData(uint64_t streamID,const char * bytes,int length)234 void PluginProxy::streamDidReceiveData(uint64_t streamID, const char* bytes, int length)
235 {
236     m_connection->connection()->send(Messages::PluginControllerProxy::StreamDidReceiveData(streamID, CoreIPC::DataReference(reinterpret_cast<const uint8_t*>(bytes), length)), m_pluginInstanceID);
237 }
238 
streamDidFinishLoading(uint64_t streamID)239 void PluginProxy::streamDidFinishLoading(uint64_t streamID)
240 {
241     m_connection->connection()->send(Messages::PluginControllerProxy::StreamDidFinishLoading(streamID), m_pluginInstanceID);
242 }
243 
streamDidFail(uint64_t streamID,bool wasCancelled)244 void PluginProxy::streamDidFail(uint64_t streamID, bool wasCancelled)
245 {
246     m_connection->connection()->send(Messages::PluginControllerProxy::StreamDidFail(streamID, wasCancelled), m_pluginInstanceID);
247 }
248 
manualStreamDidReceiveResponse(const KURL & responseURL,uint32_t streamLength,uint32_t lastModifiedTime,const WTF::String & mimeType,const WTF::String & headers)249 void PluginProxy::manualStreamDidReceiveResponse(const KURL& responseURL, uint32_t streamLength,  uint32_t lastModifiedTime, const WTF::String& mimeType, const WTF::String& headers)
250 {
251     m_connection->connection()->send(Messages::PluginControllerProxy::ManualStreamDidReceiveResponse(responseURL.string(), streamLength, lastModifiedTime, mimeType, headers), m_pluginInstanceID);
252 }
253 
manualStreamDidReceiveData(const char * bytes,int length)254 void PluginProxy::manualStreamDidReceiveData(const char* bytes, int length)
255 {
256     m_connection->connection()->send(Messages::PluginControllerProxy::ManualStreamDidReceiveData(CoreIPC::DataReference(reinterpret_cast<const uint8_t*>(bytes), length)), m_pluginInstanceID);
257 }
258 
manualStreamDidFinishLoading()259 void PluginProxy::manualStreamDidFinishLoading()
260 {
261     m_connection->connection()->send(Messages::PluginControllerProxy::ManualStreamDidFinishLoading(), m_pluginInstanceID);
262 }
263 
manualStreamDidFail(bool wasCancelled)264 void PluginProxy::manualStreamDidFail(bool wasCancelled)
265 {
266     m_connection->connection()->send(Messages::PluginControllerProxy::ManualStreamDidFail(wasCancelled), m_pluginInstanceID);
267 }
268 
handleMouseEvent(const WebMouseEvent & mouseEvent)269 bool PluginProxy::handleMouseEvent(const WebMouseEvent& mouseEvent)
270 {
271     bool handled = false;
272     if (!m_connection->connection()->sendSync(Messages::PluginControllerProxy::HandleMouseEvent(mouseEvent), Messages::PluginControllerProxy::HandleMouseEvent::Reply(handled), m_pluginInstanceID))
273         return false;
274 
275     return handled;
276 }
277 
handleWheelEvent(const WebWheelEvent & wheelEvent)278 bool PluginProxy::handleWheelEvent(const WebWheelEvent& wheelEvent)
279 {
280     bool handled = false;
281     if (!m_connection->connection()->sendSync(Messages::PluginControllerProxy::HandleWheelEvent(wheelEvent), Messages::PluginControllerProxy::HandleWheelEvent::Reply(handled), m_pluginInstanceID))
282         return false;
283 
284     return handled;
285 }
286 
handleMouseEnterEvent(const WebMouseEvent & mouseEnterEvent)287 bool PluginProxy::handleMouseEnterEvent(const WebMouseEvent& mouseEnterEvent)
288 {
289     bool handled = false;
290     if (!m_connection->connection()->sendSync(Messages::PluginControllerProxy::HandleMouseEnterEvent(mouseEnterEvent), Messages::PluginControllerProxy::HandleMouseEnterEvent::Reply(handled), m_pluginInstanceID))
291         return false;
292 
293     return handled;
294 }
295 
handleMouseLeaveEvent(const WebMouseEvent & mouseLeaveEvent)296 bool PluginProxy::handleMouseLeaveEvent(const WebMouseEvent& mouseLeaveEvent)
297 {
298     bool handled = false;
299     if (!m_connection->connection()->sendSync(Messages::PluginControllerProxy::HandleMouseLeaveEvent(mouseLeaveEvent), Messages::PluginControllerProxy::HandleMouseLeaveEvent::Reply(handled), m_pluginInstanceID))
300         return false;
301 
302     return handled;
303 }
304 
handleKeyboardEvent(const WebKeyboardEvent & keyboardEvent)305 bool PluginProxy::handleKeyboardEvent(const WebKeyboardEvent& keyboardEvent)
306 {
307     bool handled = false;
308     if (!m_connection->connection()->sendSync(Messages::PluginControllerProxy::HandleKeyboardEvent(keyboardEvent), Messages::PluginControllerProxy::HandleKeyboardEvent::Reply(handled), m_pluginInstanceID))
309         return false;
310 
311     return handled;
312 }
313 
setFocus(bool hasFocus)314 void PluginProxy::setFocus(bool hasFocus)
315 {
316     m_connection->connection()->send(Messages::PluginControllerProxy::SetFocus(hasFocus), m_pluginInstanceID);
317 }
318 
pluginScriptableNPObject()319 NPObject* PluginProxy::pluginScriptableNPObject()
320 {
321     uint64_t pluginScriptableNPObjectID = 0;
322 
323     if (!m_connection->connection()->sendSync(Messages::PluginControllerProxy::GetPluginScriptableNPObject(), Messages::PluginControllerProxy::GetPluginScriptableNPObject::Reply(pluginScriptableNPObjectID), m_pluginInstanceID))
324         return 0;
325 
326     if (!pluginScriptableNPObjectID)
327         return 0;
328 
329     return m_connection->npRemoteObjectMap()->createNPObjectProxy(pluginScriptableNPObjectID, this);
330 }
331 
332 #if PLATFORM(MAC)
windowFocusChanged(bool hasFocus)333 void PluginProxy::windowFocusChanged(bool hasFocus)
334 {
335     m_connection->connection()->send(Messages::PluginControllerProxy::WindowFocusChanged(hasFocus), m_pluginInstanceID);
336 }
337 
windowAndViewFramesChanged(const WebCore::IntRect & windowFrameInScreenCoordinates,const WebCore::IntRect & viewFrameInWindowCoordinates)338 void PluginProxy::windowAndViewFramesChanged(const WebCore::IntRect& windowFrameInScreenCoordinates, const WebCore::IntRect& viewFrameInWindowCoordinates)
339 {
340     m_connection->connection()->send(Messages::PluginControllerProxy::WindowAndViewFramesChanged(windowFrameInScreenCoordinates, viewFrameInWindowCoordinates), m_pluginInstanceID);
341 }
342 
windowVisibilityChanged(bool isVisible)343 void PluginProxy::windowVisibilityChanged(bool isVisible)
344 {
345     m_connection->connection()->send(Messages::PluginControllerProxy::WindowVisibilityChanged(isVisible), m_pluginInstanceID);
346 }
347 
pluginComplexTextInputIdentifier() const348 uint64_t PluginProxy::pluginComplexTextInputIdentifier() const
349 {
350     return m_pluginInstanceID;
351 }
352 
sendComplexTextInput(const String & textInput)353 void PluginProxy::sendComplexTextInput(const String& textInput)
354 {
355     m_connection->connection()->send(Messages::PluginControllerProxy::SendComplexTextInput(textInput), m_pluginInstanceID);
356 }
357 
358 #endif
359 
privateBrowsingStateChanged(bool isPrivateBrowsingEnabled)360 void PluginProxy::privateBrowsingStateChanged(bool isPrivateBrowsingEnabled)
361 {
362     m_connection->connection()->send(Messages::PluginControllerProxy::PrivateBrowsingStateChanged(isPrivateBrowsingEnabled), m_pluginInstanceID);
363 }
364 
controller()365 PluginController* PluginProxy::controller()
366 {
367     return m_pluginController;
368 }
369 
loadURL(uint64_t requestID,const String & method,const String & urlString,const String & target,const HTTPHeaderMap & headerFields,const Vector<uint8_t> & httpBody,bool allowPopups)370 void PluginProxy::loadURL(uint64_t requestID, const String& method, const String& urlString, const String& target, const HTTPHeaderMap& headerFields, const Vector<uint8_t>& httpBody, bool allowPopups)
371 {
372     m_pluginController->loadURL(requestID, method, urlString, target, headerFields, httpBody, allowPopups);
373 }
374 
proxiesForURL(const String & urlString,String & proxyString)375 void PluginProxy::proxiesForURL(const String& urlString, String& proxyString)
376 {
377     proxyString = m_pluginController->proxiesForURL(urlString);
378 }
379 
cookiesForURL(const String & urlString,String & cookieString)380 void PluginProxy::cookiesForURL(const String& urlString, String& cookieString)
381 {
382     cookieString = m_pluginController->cookiesForURL(urlString);
383 }
384 
setCookiesForURL(const String & urlString,const String & cookieString)385 void PluginProxy::setCookiesForURL(const String& urlString, const String& cookieString)
386 {
387     m_pluginController->setCookiesForURL(urlString, cookieString);
388 }
389 
getWindowScriptNPObject(uint64_t & windowScriptNPObjectID)390 void PluginProxy::getWindowScriptNPObject(uint64_t& windowScriptNPObjectID)
391 {
392     NPObject* windowScriptNPObject = m_pluginController->windowScriptNPObject();
393     if (!windowScriptNPObject) {
394         windowScriptNPObjectID = 0;
395         return;
396     }
397 
398     windowScriptNPObjectID = m_connection->npRemoteObjectMap()->registerNPObject(windowScriptNPObject, this);
399     releaseNPObject(windowScriptNPObject);
400 }
401 
getPluginElementNPObject(uint64_t & pluginElementNPObjectID)402 void PluginProxy::getPluginElementNPObject(uint64_t& pluginElementNPObjectID)
403 {
404     NPObject* pluginElementNPObject = m_pluginController->pluginElementNPObject();
405     if (!pluginElementNPObject) {
406         pluginElementNPObjectID = 0;
407         return;
408     }
409 
410     pluginElementNPObjectID = m_connection->npRemoteObjectMap()->registerNPObject(pluginElementNPObject, this);
411     releaseNPObject(pluginElementNPObject);
412 }
413 
evaluate(const NPVariantData & npObjectAsVariantData,const String & scriptString,bool allowPopups,bool & returnValue,NPVariantData & resultData)414 void PluginProxy::evaluate(const NPVariantData& npObjectAsVariantData, const String& scriptString, bool allowPopups, bool& returnValue, NPVariantData& resultData)
415 {
416     PluginController::PluginDestructionProtector protector(m_pluginController);
417 
418     NPVariant npObjectAsVariant = m_connection->npRemoteObjectMap()->npVariantDataToNPVariant(npObjectAsVariantData, this);
419     if (!NPVARIANT_IS_OBJECT(npObjectAsVariant) || !(NPVARIANT_TO_OBJECT(npObjectAsVariant))) {
420         returnValue = false;
421         return;
422     }
423 
424     NPVariant result;
425     returnValue = m_pluginController->evaluate(NPVARIANT_TO_OBJECT(npObjectAsVariant), scriptString, &result, allowPopups);
426     if (!returnValue)
427         return;
428 
429     // Convert the NPVariant to an NPVariantData.
430     resultData = m_connection->npRemoteObjectMap()->npVariantToNPVariantData(result, this);
431 
432     // And release the result.
433     releaseNPVariantValue(&result);
434 
435     releaseNPVariantValue(&npObjectAsVariant);
436 }
437 
cancelStreamLoad(uint64_t streamID)438 void PluginProxy::cancelStreamLoad(uint64_t streamID)
439 {
440     m_pluginController->cancelStreamLoad(streamID);
441 }
442 
cancelManualStreamLoad()443 void PluginProxy::cancelManualStreamLoad()
444 {
445     m_pluginController->cancelManualStreamLoad();
446 }
447 
setStatusbarText(const String & statusbarText)448 void PluginProxy::setStatusbarText(const String& statusbarText)
449 {
450     m_pluginController->setStatusbarText(statusbarText);
451 }
452 
453 #if PLATFORM(MAC)
setComplexTextInputEnabled(bool complexTextInputEnabled)454 void PluginProxy::setComplexTextInputEnabled(bool complexTextInputEnabled)
455 {
456     m_pluginController->setComplexTextInputEnabled(complexTextInputEnabled);
457 }
458 #endif
459 
update(const IntRect & paintedRect)460 void PluginProxy::update(const IntRect& paintedRect)
461 {
462     if (paintedRect == m_frameRect)
463         m_pluginBackingStoreContainsValidData = true;
464 
465     IntRect paintedRectPluginCoordinates = paintedRect;
466     paintedRectPluginCoordinates.move(-m_frameRect.x(), -m_frameRect.y());
467 
468     if (m_backingStore) {
469         // Blit the plug-in backing store into our own backing store.
470         OwnPtr<GraphicsContext> graphicsContext = m_backingStore->createGraphicsContext();
471         graphicsContext->setCompositeOperation(CompositeCopy);
472         m_pluginBackingStore->paint(*graphicsContext, paintedRectPluginCoordinates.location(),
473                                     paintedRectPluginCoordinates);
474     }
475 
476     // Ask the controller to invalidate the rect for us.
477     m_waitingForPaintInResponseToUpdate = true;
478     m_pluginController->invalidate(paintedRectPluginCoordinates);
479 }
480 
481 } // namespace WebKit
482 
483 #endif // ENABLE(PLUGIN_PROCESS)
484