~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebKit2/WebProcess/Plugins/PluginView.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2010, 2012 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 "PluginView.h"
 
28
 
 
29
#include "NPRuntimeUtilities.h"
 
30
#include "Plugin.h"
 
31
#include "ShareableBitmap.h"
 
32
#include "WebCoreArgumentCoders.h"
 
33
#include "WebEvent.h"
 
34
#include "WebPage.h"
 
35
#include "WebPageProxyMessages.h"
 
36
#include "WebProcess.h"
 
37
#include <WebCore/Chrome.h>
 
38
#include <WebCore/CookieJar.h>
 
39
#include <WebCore/Credential.h>
 
40
#include <WebCore/CredentialStorage.h>
 
41
#include <WebCore/DocumentLoader.h>
 
42
#include <WebCore/MouseEvent.h>
 
43
#include <WebCore/FocusController.h>
 
44
#include <WebCore/Frame.h>
 
45
#include <WebCore/FrameLoadRequest.h>
 
46
#include <WebCore/FrameLoaderClient.h>
 
47
#include <WebCore/FrameView.h>
 
48
#include <WebCore/GraphicsContext.h>
 
49
#include <WebCore/HTMLPlugInElement.h>
 
50
#include <WebCore/HostWindow.h>
 
51
#include <WebCore/NetscapePlugInStreamLoader.h>
 
52
#include <WebCore/NetworkingContext.h>
 
53
#include <WebCore/Page.h>
 
54
#include <WebCore/ProtectionSpace.h>
 
55
#include <WebCore/ProxyServer.h>
 
56
#include <WebCore/RenderEmbeddedObject.h>
 
57
#include <WebCore/ResourceLoadScheduler.h>
 
58
#include <WebCore/ScriptValue.h>
 
59
#include <WebCore/ScrollView.h>
 
60
#include <WebCore/SecurityOrigin.h>
 
61
#include <WebCore/SecurityPolicy.h>
 
62
#include <WebCore/Settings.h>
 
63
#include <WebCore/UserGestureIndicator.h>
 
64
#include <wtf/text/StringBuilder.h>
 
65
 
 
66
using namespace JSC;
 
67
using namespace WebCore;
 
68
 
 
69
namespace WebKit {
 
70
 
 
71
// This simulated mouse click delay in HTMLPlugInImageElement.cpp should generally be the same or shorter than this delay.
 
72
static const double pluginSnapshotTimerDelay = 1.1;
 
73
 
 
74
class PluginView::URLRequest : public RefCounted<URLRequest> {
 
75
public:
 
76
    static PassRefPtr<PluginView::URLRequest> create(uint64_t requestID, const FrameLoadRequest& request, bool allowPopups)
 
77
    {
 
78
        return adoptRef(new URLRequest(requestID, request, allowPopups));
 
79
    }
 
80
 
 
81
    uint64_t requestID() const { return m_requestID; }
 
82
    const String& target() const { return m_request.frameName(); }
 
83
    const ResourceRequest & request() const { return m_request.resourceRequest(); }
 
84
    bool allowPopups() const { return m_allowPopups; }
 
85
 
 
86
private:
 
87
    URLRequest(uint64_t requestID, const FrameLoadRequest& request, bool allowPopups)
 
88
        : m_requestID(requestID)
 
89
        , m_request(request)
 
90
        , m_allowPopups(allowPopups)
 
91
    {
 
92
    }
 
93
 
 
94
    uint64_t m_requestID;
 
95
    FrameLoadRequest m_request;
 
96
    bool m_allowPopups;
 
97
};
 
98
 
 
99
class PluginView::Stream : public RefCounted<PluginView::Stream>, NetscapePlugInStreamLoaderClient {
 
100
public:
 
101
    static PassRefPtr<Stream> create(PluginView* pluginView, uint64_t streamID, const ResourceRequest& request)
 
102
    {
 
103
        return adoptRef(new Stream(pluginView, streamID, request));
 
104
    }
 
105
    ~Stream();
 
106
 
 
107
    void start();
 
108
    void cancel();
 
109
 
 
110
    uint64_t streamID() const { return m_streamID; }
 
111
 
 
112
private:
 
113
    Stream(PluginView* pluginView, uint64_t streamID, const ResourceRequest& request)
 
114
        : m_pluginView(pluginView)
 
115
        , m_streamID(streamID)
 
116
        , m_request(request)
 
117
        , m_streamWasCancelled(false)
 
118
    {
 
119
    }
 
120
 
 
121
    // NetscapePluginStreamLoaderClient
 
122
    virtual void didReceiveResponse(NetscapePlugInStreamLoader*, const ResourceResponse&);
 
123
    virtual void didReceiveData(NetscapePlugInStreamLoader*, const char*, int);
 
124
    virtual void didFail(NetscapePlugInStreamLoader*, const ResourceError&);
 
125
    virtual void didFinishLoading(NetscapePlugInStreamLoader*);
 
126
 
 
127
    PluginView* m_pluginView;
 
128
    uint64_t m_streamID;
 
129
    const ResourceRequest m_request;
 
130
    
 
131
    // True if the stream was explicitly cancelled by calling cancel().
 
132
    // (As opposed to being cancelled by the user hitting the stop button for example.
 
133
    bool m_streamWasCancelled;
 
134
    
 
135
    RefPtr<NetscapePlugInStreamLoader> m_loader;
 
136
};
 
137
 
 
138
PluginView::Stream::~Stream()
 
139
{
 
140
    ASSERT(!m_pluginView);
 
141
}
 
142
    
 
143
void PluginView::Stream::start()
 
144
{
 
145
    ASSERT(!m_loader);
 
146
 
 
147
    Frame* frame = m_pluginView->m_pluginElement->document()->frame();
 
148
    ASSERT(frame);
 
149
 
 
150
    m_loader = resourceLoadScheduler()->schedulePluginStreamLoad(frame, this, m_request);
 
151
}
 
152
 
 
153
void PluginView::Stream::cancel()
 
154
{
 
155
    ASSERT(m_loader);
 
156
 
 
157
    m_streamWasCancelled = true;
 
158
    m_loader->cancel(m_loader->cancelledError());
 
159
    m_loader = 0;
 
160
}
 
161
 
 
162
static String buildHTTPHeaders(const ResourceResponse& response, long long& expectedContentLength)
 
163
{
 
164
    if (!response.isHTTP())
 
165
        return String();
 
166
 
 
167
    StringBuilder stringBuilder;
 
168
    
 
169
    String statusLine = String::format("HTTP %d ", response.httpStatusCode());
 
170
    stringBuilder.append(statusLine);
 
171
    stringBuilder.append(response.httpStatusText());
 
172
    stringBuilder.append('\n');
 
173
    
 
174
    HTTPHeaderMap::const_iterator end = response.httpHeaderFields().end();
 
175
    for (HTTPHeaderMap::const_iterator it = response.httpHeaderFields().begin(); it != end; ++it) {
 
176
        stringBuilder.append(it->key);
 
177
        stringBuilder.appendLiteral(": ");
 
178
        stringBuilder.append(it->value);
 
179
        stringBuilder.append('\n');
 
180
    }
 
181
    
 
182
    String headers = stringBuilder.toString();
 
183
    
 
184
    // If the content is encoded (most likely compressed), then don't send its length to the plugin,
 
185
    // which is only interested in the decoded length, not yet known at the moment.
 
186
    // <rdar://problem/4470599> tracks a request for -[NSURLResponse expectedContentLength] to incorporate this logic.
 
187
    String contentEncoding = response.httpHeaderField("Content-Encoding");
 
188
    if (!contentEncoding.isNull() && contentEncoding != "identity")
 
189
        expectedContentLength = -1;
 
190
 
 
191
    return headers;
 
192
}
 
193
 
 
194
void PluginView::Stream::didReceiveResponse(NetscapePlugInStreamLoader*, const ResourceResponse& response)
 
195
{
 
196
    // Compute the stream related data from the resource response.
 
197
    const KURL& responseURL = response.url();
 
198
    const String& mimeType = response.mimeType();
 
199
    long long expectedContentLength = response.expectedContentLength();
 
200
    
 
201
    String headers = buildHTTPHeaders(response, expectedContentLength);
 
202
 
 
203
    uint32_t streamLength = 0;
 
204
    if (expectedContentLength > 0)
 
205
        streamLength = expectedContentLength;
 
206
 
 
207
    m_pluginView->m_plugin->streamDidReceiveResponse(m_streamID, responseURL, streamLength, response.lastModifiedDate(), mimeType, headers, response.suggestedFilename());
 
208
}
 
209
 
 
210
void PluginView::Stream::didReceiveData(NetscapePlugInStreamLoader*, const char* bytes, int length)
 
211
{
 
212
    m_pluginView->m_plugin->streamDidReceiveData(m_streamID, bytes, length);
 
213
}
 
214
 
 
215
void PluginView::Stream::didFail(NetscapePlugInStreamLoader*, const ResourceError& error) 
 
216
{
 
217
    // Calling streamDidFail could cause us to be deleted, so we hold on to a reference here.
 
218
    RefPtr<Stream> protect(this);
 
219
 
 
220
    // We only want to call streamDidFail if the stream was not explicitly cancelled by the plug-in.
 
221
    if (!m_streamWasCancelled)
 
222
        m_pluginView->m_plugin->streamDidFail(m_streamID, error.isCancellation());
 
223
 
 
224
    m_pluginView->removeStream(this);
 
225
    m_pluginView = 0;
 
226
}
 
227
 
 
228
void PluginView::Stream::didFinishLoading(NetscapePlugInStreamLoader*)
 
229
{
 
230
    // Calling streamDidFinishLoading could cause us to be deleted, so we hold on to a reference here.
 
231
    RefPtr<Stream> protectStream(this);
 
232
 
 
233
#if ENABLE(NETSCAPE_PLUGIN_API)
 
234
    // Protect the plug-in while we're calling into it.
 
235
    NPRuntimeObjectMap::PluginProtector pluginProtector(&m_pluginView->m_npRuntimeObjectMap);
 
236
#endif
 
237
    m_pluginView->m_plugin->streamDidFinishLoading(m_streamID);
 
238
 
 
239
    m_pluginView->removeStream(this);
 
240
    m_pluginView = 0;
 
241
}
 
242
 
 
243
static inline WebPage* webPage(HTMLPlugInElement* pluginElement)
 
244
{
 
245
    Frame* frame = pluginElement->document()->frame();
 
246
    ASSERT(frame);
 
247
 
 
248
    WebPage* webPage = static_cast<WebFrameLoaderClient*>(frame->loader()->client())->webFrame()->page();
 
249
    ASSERT(webPage);
 
250
 
 
251
    return webPage;
 
252
}
 
253
 
 
254
PassRefPtr<PluginView> PluginView::create(PassRefPtr<HTMLPlugInElement> pluginElement, PassRefPtr<Plugin> plugin, const Plugin::Parameters& parameters)
 
255
{
 
256
    return adoptRef(new PluginView(pluginElement, plugin, parameters));
 
257
}
 
258
 
 
259
PluginView::PluginView(PassRefPtr<HTMLPlugInElement> pluginElement, PassRefPtr<Plugin> plugin, const Plugin::Parameters& parameters)
 
260
    : PluginViewBase(0)
 
261
    , m_pluginElement(pluginElement)
 
262
    , m_plugin(plugin)
 
263
    , m_webPage(webPage(m_pluginElement.get()))
 
264
    , m_parameters(parameters)
 
265
    , m_isInitialized(false)
 
266
    , m_isWaitingForSynchronousInitialization(false)
 
267
    , m_isWaitingUntilMediaCanStart(false)
 
268
    , m_isBeingDestroyed(false)
 
269
    , m_pendingURLRequestsTimer(RunLoop::main(), this, &PluginView::pendingURLRequestsTimerFired)
 
270
#if ENABLE(NETSCAPE_PLUGIN_API)
 
271
    , m_npRuntimeObjectMap(this)
 
272
#endif
 
273
    , m_manualStreamState(StreamStateInitial)
 
274
    , m_pluginSnapshotTimer(this, &PluginView::pluginSnapshotTimerFired, pluginSnapshotTimerDelay)
 
275
    , m_pageScaleFactor(1)
 
276
{
 
277
    m_webPage->addPluginView(this);
 
278
}
 
279
 
 
280
PluginView::~PluginView()
 
281
{
 
282
    if (m_webPage)
 
283
        m_webPage->removePluginView(this);
 
284
 
 
285
    ASSERT(!m_isBeingDestroyed);
 
286
 
 
287
    if (m_isWaitingUntilMediaCanStart)
 
288
        m_pluginElement->document()->removeMediaCanStartListener(this);
 
289
 
 
290
    destroyPluginAndReset();
 
291
 
 
292
    // Null out the plug-in element explicitly so we'll crash earlier if we try to use
 
293
    // the plug-in view after it's been destroyed.
 
294
    m_pluginElement = nullptr;
 
295
}
 
296
 
 
297
void PluginView::destroyPluginAndReset()
 
298
{
 
299
    // Cancel all pending frame loads.
 
300
    for (FrameLoadMap::iterator it = m_pendingFrameLoads.begin(), end = m_pendingFrameLoads.end(); it != end; ++it)
 
301
        it->key->setLoadListener(0);
 
302
 
 
303
    if (m_plugin) {
 
304
        m_isBeingDestroyed = true;
 
305
        m_plugin->destroyPlugin();
 
306
        m_isBeingDestroyed = false;
 
307
#if PLATFORM(MAC)
 
308
        if (m_webPage)
 
309
            pluginFocusOrWindowFocusChanged(false);
 
310
#endif
 
311
    }
 
312
 
 
313
#if ENABLE(NETSCAPE_PLUGIN_API)
 
314
    // Invalidate the object map.
 
315
    m_npRuntimeObjectMap.invalidate();
 
316
#endif
 
317
 
 
318
    cancelAllStreams();
 
319
}
 
320
 
 
321
void PluginView::recreateAndInitialize(PassRefPtr<Plugin> plugin)
 
322
{
 
323
    if (m_plugin) {
 
324
        if (m_pluginSnapshotTimer.isActive())
 
325
            m_pluginSnapshotTimer.stop();
 
326
        destroyPluginAndReset();
 
327
    }
 
328
 
 
329
    // Reset member variables to initial values.
 
330
    m_plugin = plugin;
 
331
    m_isInitialized = false;
 
332
    m_isWaitingForSynchronousInitialization = false;
 
333
    m_isWaitingUntilMediaCanStart = false;
 
334
    m_isBeingDestroyed = false;
 
335
    m_manualStreamState = StreamStateInitial;
 
336
    m_transientPaintingSnapshot = nullptr;
 
337
 
 
338
    initializePlugin();
 
339
}
 
340
 
 
341
Frame* PluginView::frame() const
 
342
{
 
343
    return m_pluginElement->document()->frame();
 
344
}
 
345
 
 
346
void PluginView::manualLoadDidReceiveResponse(const ResourceResponse& response)
 
347
{
 
348
    // The plug-in can be null here if it failed to initialize.
 
349
    if (!m_plugin)
 
350
        return;
 
351
 
 
352
    if (!m_isInitialized) {
 
353
        ASSERT(m_manualStreamState == StreamStateInitial);
 
354
        m_manualStreamState = StreamStateHasReceivedResponse;
 
355
        m_manualStreamResponse = response;
 
356
        return;
 
357
    }
 
358
 
 
359
    // Compute the stream related data from the resource response.
 
360
    const KURL& responseURL = response.url();
 
361
    const String& mimeType = response.mimeType();
 
362
    long long expectedContentLength = response.expectedContentLength();
 
363
    
 
364
    String headers = buildHTTPHeaders(response, expectedContentLength);
 
365
    
 
366
    uint32_t streamLength = 0;
 
367
    if (expectedContentLength > 0)
 
368
        streamLength = expectedContentLength;
 
369
 
 
370
    m_plugin->manualStreamDidReceiveResponse(responseURL, streamLength, response.lastModifiedDate(), mimeType, headers, response.suggestedFilename());
 
371
}
 
372
 
 
373
void PluginView::manualLoadDidReceiveData(const char* bytes, int length)
 
374
{
 
375
    // The plug-in can be null here if it failed to initialize.
 
376
    if (!m_plugin)
 
377
        return;
 
378
 
 
379
    if (!m_isInitialized) {
 
380
        ASSERT(m_manualStreamState == StreamStateHasReceivedResponse);
 
381
        if (!m_manualStreamData)
 
382
            m_manualStreamData = SharedBuffer::create();
 
383
 
 
384
        m_manualStreamData->append(bytes, length);
 
385
        return;
 
386
    }
 
387
 
 
388
    m_plugin->manualStreamDidReceiveData(bytes, length);
 
389
}
 
390
 
 
391
void PluginView::manualLoadDidFinishLoading()
 
392
{
 
393
    // The plug-in can be null here if it failed to initialize.
 
394
    if (!m_plugin)
 
395
        return;
 
396
 
 
397
    if (!m_isInitialized) {
 
398
        ASSERT(m_manualStreamState == StreamStateHasReceivedResponse);
 
399
        m_manualStreamState = StreamStateFinished;
 
400
        return;
 
401
    }
 
402
 
 
403
    m_plugin->manualStreamDidFinishLoading();
 
404
}
 
405
 
 
406
void PluginView::manualLoadDidFail(const ResourceError& error)
 
407
{
 
408
    // The plug-in can be null here if it failed to initialize.
 
409
    if (!m_plugin)
 
410
        return;
 
411
 
 
412
    if (!m_isInitialized) {
 
413
        m_manualStreamState = StreamStateFinished;
 
414
        m_manualStreamError = error;
 
415
        m_manualStreamData = nullptr;
 
416
        return;
 
417
    }
 
418
 
 
419
    m_plugin->manualStreamDidFail(error.isCancellation());
 
420
}
 
421
 
 
422
RenderBoxModelObject* PluginView::renderer() const
 
423
{
 
424
    return toRenderBoxModelObject(m_pluginElement->renderer());
 
425
}
 
426
 
 
427
void PluginView::pageScaleFactorDidChange()
 
428
{
 
429
    viewGeometryDidChange();
 
430
}
 
431
 
 
432
void PluginView::setPageScaleFactor(double scaleFactor, IntPoint)
 
433
{
 
434
    m_pageScaleFactor = scaleFactor;
 
435
    m_webPage->send(Messages::WebPageProxy::PageScaleFactorDidChange(scaleFactor));
 
436
    pageScaleFactorDidChange();
 
437
}
 
438
 
 
439
double PluginView::pageScaleFactor()
 
440
{
 
441
    return m_pageScaleFactor;
 
442
}
 
443
 
 
444
void PluginView::webPageDestroyed()
 
445
{
 
446
    m_webPage = 0;
 
447
}
 
448
 
 
449
#if PLATFORM(MAC)    
 
450
void PluginView::setWindowIsVisible(bool windowIsVisible)
 
451
{
 
452
    if (!m_isInitialized || !m_plugin)
 
453
        return;
 
454
 
 
455
    m_plugin->windowVisibilityChanged(windowIsVisible);
 
456
}
 
457
 
 
458
void PluginView::setWindowIsFocused(bool windowIsFocused)
 
459
{
 
460
    if (!m_isInitialized || !m_plugin)
 
461
        return;
 
462
 
 
463
    m_plugin->windowFocusChanged(windowIsFocused);    
 
464
}
 
465
 
 
466
void PluginView::setDeviceScaleFactor(float scaleFactor)
 
467
{
 
468
    if (!m_isInitialized || !m_plugin)
 
469
        return;
 
470
 
 
471
    m_plugin->contentsScaleFactorChanged(scaleFactor);
 
472
}
 
473
 
 
474
void PluginView::windowAndViewFramesChanged(const IntRect& windowFrameInScreenCoordinates, const IntRect& viewFrameInWindowCoordinates)
 
475
{
 
476
    if (!m_isInitialized || !m_plugin)
 
477
        return;
 
478
 
 
479
    m_plugin->windowAndViewFramesChanged(windowFrameInScreenCoordinates, viewFrameInWindowCoordinates);
 
480
}
 
481
 
 
482
bool PluginView::sendComplexTextInput(uint64_t pluginComplexTextInputIdentifier, const String& textInput)
 
483
{
 
484
    if (!m_plugin)
 
485
        return false;
 
486
 
 
487
    if (m_plugin->pluginComplexTextInputIdentifier() != pluginComplexTextInputIdentifier)
 
488
        return false;
 
489
 
 
490
    m_plugin->sendComplexTextInput(textInput);
 
491
    return true;
 
492
}
 
493
 
 
494
void PluginView::setLayerHostingMode(LayerHostingMode layerHostingMode)
 
495
{
 
496
    if (!m_plugin)
 
497
        return;
 
498
 
 
499
    if (!m_isInitialized) {
 
500
        m_parameters.layerHostingMode = layerHostingMode;
 
501
        return;
 
502
    }
 
503
 
 
504
    m_plugin->setLayerHostingMode(layerHostingMode);
 
505
}
 
506
 
 
507
#endif
 
508
 
 
509
void PluginView::initializePlugin()
 
510
{
 
511
    if (m_isInitialized)
 
512
        return;
 
513
 
 
514
    if (!m_plugin) {
 
515
        // We've already tried and failed to initialize the plug-in.
 
516
        return;
 
517
    }
 
518
 
 
519
    if (Frame* frame = m_pluginElement->document()->frame()) {
 
520
        if (Page* page = frame->page()) {
 
521
            
 
522
            // We shouldn't initialize the plug-in right now, add a listener.
 
523
            if (!page->canStartMedia()) {
 
524
                if (m_isWaitingUntilMediaCanStart)
 
525
                    return;
 
526
                
 
527
                m_isWaitingUntilMediaCanStart = true;
 
528
                m_pluginElement->document()->addMediaCanStartListener(this);
 
529
                return;
 
530
            }
 
531
        }
 
532
    }
 
533
 
 
534
    m_plugin->initialize(this, m_parameters);
 
535
    
 
536
    // Plug-in initialization continued in didFailToInitializePlugin() or didInitializePlugin().
 
537
}
 
538
 
 
539
void PluginView::didFailToInitializePlugin()
 
540
{
 
541
    m_plugin = 0;
 
542
    m_webPage->send(Messages::WebPageProxy::DidFailToInitializePlugin(m_parameters.mimeType));
 
543
}
 
544
 
 
545
void PluginView::didInitializePlugin()
 
546
{
 
547
    m_isInitialized = true;
 
548
 
 
549
#if PLATFORM(MAC)
 
550
    windowAndViewFramesChanged(m_webPage->windowFrameInScreenCoordinates(), m_webPage->viewFrameInWindowCoordinates());
 
551
#endif
 
552
 
 
553
    viewGeometryDidChange();
 
554
 
 
555
    redeliverManualStream();
 
556
 
 
557
#if PLATFORM(MAC)
 
558
    if (m_pluginElement->displayState() < HTMLPlugInElement::PlayingWithPendingMouseClick)
 
559
        m_pluginSnapshotTimer.restart();
 
560
    else {
 
561
        if (m_plugin->pluginLayer()) {
 
562
            if (frame()) {
 
563
                frame()->view()->enterCompositingMode();
 
564
                m_pluginElement->setNeedsStyleRecalc(SyntheticStyleChange);
 
565
            }
 
566
        }
 
567
        if (m_pluginElement->displayState() < HTMLPlugInElement::Playing)
 
568
            m_pluginElement->dispatchPendingMouseClick();
 
569
    }
 
570
 
 
571
    setWindowIsVisible(m_webPage->windowIsVisible());
 
572
    setWindowIsFocused(m_webPage->windowIsFocused());
 
573
#endif
 
574
 
 
575
    if (wantsWheelEvents()) {
 
576
        if (Frame* frame = m_pluginElement->document()->frame()) {
 
577
            if (FrameView* frameView = frame->view())
 
578
                frameView->setNeedsLayout();
 
579
        }
 
580
    }
 
581
}
 
582
 
 
583
#if PLATFORM(MAC)
 
584
PlatformLayer* PluginView::platformLayer() const
 
585
{
 
586
    // The plug-in can be null here if it failed to initialize.
 
587
    if (!m_isInitialized || !m_plugin)
 
588
        return 0;
 
589
        
 
590
    return m_plugin->pluginLayer();
 
591
}
 
592
#endif
 
593
 
 
594
JSObject* PluginView::scriptObject(JSGlobalObject* globalObject)
 
595
{
 
596
    // If we're already waiting for synchronous initialization of the plugin,
 
597
    // calls to scriptObject() are from the plug-in itself and need to return 0;
 
598
    if (m_isWaitingForSynchronousInitialization)
 
599
        return 0;
 
600
 
 
601
    // We might not have started initialization of the plug-in yet, the plug-in might be in the middle
 
602
    // of being initializing asynchronously, or initialization might have previously failed.
 
603
    if (!m_isInitialized || !m_plugin)
 
604
        return 0;
 
605
 
 
606
#if ENABLE(NETSCAPE_PLUGIN_API)
 
607
    NPObject* scriptableNPObject = m_plugin->pluginScriptableNPObject();
 
608
    if (!scriptableNPObject)
 
609
        return 0;
 
610
 
 
611
    JSObject* jsObject = m_npRuntimeObjectMap.getOrCreateJSObject(globalObject, scriptableNPObject);
 
612
    releaseNPObject(scriptableNPObject);
 
613
 
 
614
    return jsObject;
 
615
#else
 
616
    UNUSED_PARAM(globalObject);
 
617
    return 0;
 
618
#endif
 
619
}
 
620
 
 
621
void PluginView::storageBlockingStateChanged()
 
622
{
 
623
    // The plug-in can be null here if it failed to initialize.
 
624
    if (!m_isInitialized || !m_plugin)
 
625
        return;
 
626
 
 
627
    bool storageBlockingPolicy = !frame()->document()->securityOrigin()->canAccessPluginStorage(frame()->tree()->top()->document()->securityOrigin());
 
628
 
 
629
    m_plugin->storageBlockingStateChanged(storageBlockingPolicy);
 
630
}
 
631
 
 
632
void PluginView::privateBrowsingStateChanged(bool privateBrowsingEnabled)
 
633
{
 
634
    // The plug-in can be null here if it failed to initialize.
 
635
    if (!m_isInitialized || !m_plugin)
 
636
        return;
 
637
 
 
638
    m_plugin->privateBrowsingStateChanged(privateBrowsingEnabled);
 
639
}
 
640
 
 
641
bool PluginView::getFormValue(String& formValue)
 
642
{
 
643
    // The plug-in can be null here if it failed to initialize.
 
644
    if (!m_isInitialized || !m_plugin)
 
645
        return false;
 
646
 
 
647
    return m_plugin->getFormValue(formValue);
 
648
}
 
649
 
 
650
bool PluginView::scroll(ScrollDirection direction, ScrollGranularity granularity)
 
651
{
 
652
    // The plug-in can be null here if it failed to initialize.
 
653
    if (!m_isInitialized || !m_plugin)
 
654
        return false;
 
655
 
 
656
    return m_plugin->handleScroll(direction, granularity);
 
657
}
 
658
 
 
659
Scrollbar* PluginView::horizontalScrollbar()
 
660
{
 
661
    // The plug-in can be null here if it failed to initialize.
 
662
    if (!m_isInitialized || !m_plugin)
 
663
        return 0;
 
664
 
 
665
    return m_plugin->horizontalScrollbar();
 
666
}
 
667
 
 
668
Scrollbar* PluginView::verticalScrollbar()
 
669
{
 
670
    // The plug-in can be null here if it failed to initialize.
 
671
    if (!m_isInitialized || !m_plugin)
 
672
        return 0;
 
673
 
 
674
    return m_plugin->verticalScrollbar();
 
675
}
 
676
 
 
677
bool PluginView::wantsWheelEvents()
 
678
{
 
679
    // The plug-in can be null here if it failed to initialize.
 
680
    if (!m_isInitialized || !m_plugin)
 
681
        return 0;
 
682
    
 
683
    return m_plugin->wantsWheelEvents();
 
684
}
 
685
 
 
686
void PluginView::setFrameRect(const WebCore::IntRect& rect)
 
687
{
 
688
    Widget::setFrameRect(rect);
 
689
    viewGeometryDidChange();
 
690
}
 
691
 
 
692
void PluginView::paint(GraphicsContext* context, const IntRect& /*dirtyRect*/)
 
693
{
 
694
    if (!m_plugin || !m_isInitialized || m_pluginElement->displayState() < HTMLPlugInElement::PlayingWithPendingMouseClick)
 
695
        return;
 
696
 
 
697
    if (context->paintingDisabled()) {
 
698
        if (context->updatingControlTints())
 
699
            m_plugin->updateControlTints(context);
 
700
        return;
 
701
    }
 
702
 
 
703
    // FIXME: We should try to intersect the dirty rect with the plug-in's clip rect here.
 
704
    IntRect paintRect = IntRect(IntPoint(), frameRect().size());
 
705
 
 
706
    if (paintRect.isEmpty())
 
707
        return;
 
708
 
 
709
    if (m_transientPaintingSnapshot) {
 
710
        m_transientPaintingSnapshot->paint(*context, contentsScaleFactor(), frameRect().location(), m_transientPaintingSnapshot->bounds());
 
711
        return;
 
712
    }
 
713
    
 
714
    GraphicsContextStateSaver stateSaver(*context);
 
715
 
 
716
    // Translate the coordinate system so that the origin is in the top-left corner of the plug-in.
 
717
    context->translate(frameRect().location().x(), frameRect().location().y());
 
718
 
 
719
    m_plugin->paint(context, paintRect);
 
720
}
 
721
 
 
722
void PluginView::frameRectsChanged()
 
723
{
 
724
    Widget::frameRectsChanged();
 
725
    viewGeometryDidChange();
 
726
}
 
727
 
 
728
void PluginView::setParent(ScrollView* scrollView)
 
729
{
 
730
    Widget::setParent(scrollView);
 
731
    
 
732
    if (scrollView)
 
733
        initializePlugin();
 
734
}
 
735
 
 
736
PassOwnPtr<WebEvent> PluginView::createWebEvent(MouseEvent* event) const
 
737
{
 
738
    WebEvent::Type type = WebEvent::NoType;
 
739
    unsigned clickCount = 1;
 
740
    if (event->type() == eventNames().mousedownEvent)
 
741
        type = WebEvent::MouseDown;
 
742
    else if (event->type() == eventNames().mouseupEvent)
 
743
        type = WebEvent::MouseUp;
 
744
    else if (event->type() == eventNames().mouseoverEvent) {
 
745
        type = WebEvent::MouseMove;
 
746
        clickCount = 0;
 
747
    } else if (event->type() == eventNames().clickEvent)
 
748
        return nullptr;
 
749
    else
 
750
        ASSERT_NOT_REACHED();
 
751
 
 
752
    WebMouseEvent::Button button = WebMouseEvent::NoButton;
 
753
    switch (event->button()) {
 
754
    case WebCore::LeftButton:
 
755
        button = WebMouseEvent::LeftButton;
 
756
        break;
 
757
    case WebCore::MiddleButton:
 
758
        button = WebMouseEvent::MiddleButton;
 
759
        break;
 
760
    case WebCore::RightButton:
 
761
        button = WebMouseEvent::RightButton;
 
762
        break;
 
763
    default:
 
764
        ASSERT_NOT_REACHED();
 
765
        break;
 
766
    }
 
767
 
 
768
    unsigned modifiers = 0;
 
769
    if (event->shiftKey())
 
770
        modifiers |= WebEvent::ShiftKey;
 
771
    if (event->ctrlKey())
 
772
        modifiers |= WebEvent::ControlKey;
 
773
    if (event->altKey())
 
774
        modifiers |= WebEvent::AltKey;
 
775
    if (event->metaKey())
 
776
        modifiers |= WebEvent::MetaKey;
 
777
 
 
778
    return adoptPtr(new WebMouseEvent(type, button, m_plugin->convertToRootView(IntPoint(event->offsetX(), event->offsetY())), event->screenLocation(), 0, 0, 0, clickCount, static_cast<WebEvent::Modifiers>(modifiers), 0));
 
779
}
 
780
 
 
781
void PluginView::handleEvent(Event* event)
 
782
{
 
783
    if (!m_isInitialized || !m_plugin)
 
784
        return;
 
785
 
 
786
    const WebEvent* currentEvent = WebPage::currentEvent();
 
787
    OwnPtr<WebEvent> simulatedWebEvent;
 
788
    if (event->isMouseEvent() && toMouseEvent(event)->isSimulated()) {
 
789
        simulatedWebEvent = createWebEvent(toMouseEvent(event));
 
790
        currentEvent = simulatedWebEvent.get();
 
791
    }
 
792
    if (!currentEvent)
 
793
        return;
 
794
 
 
795
    bool didHandleEvent = false;
 
796
 
 
797
    if ((event->type() == eventNames().mousemoveEvent && currentEvent->type() == WebEvent::MouseMove)
 
798
        || (event->type() == eventNames().mousedownEvent && currentEvent->type() == WebEvent::MouseDown)
 
799
        || (event->type() == eventNames().mouseupEvent && currentEvent->type() == WebEvent::MouseUp)) {
 
800
        // We have a mouse event.
 
801
 
 
802
        // FIXME: Clicking in a scroll bar should not change focus.
 
803
        if (currentEvent->type() == WebEvent::MouseDown) {
 
804
            focusPluginElement();
 
805
            frame()->eventHandler()->setCapturingMouseEventsNode(m_pluginElement.get());
 
806
        } else if (currentEvent->type() == WebEvent::MouseUp)
 
807
            frame()->eventHandler()->setCapturingMouseEventsNode(0);
 
808
 
 
809
        didHandleEvent = m_plugin->handleMouseEvent(static_cast<const WebMouseEvent&>(*currentEvent));
 
810
    } else if (event->type() == eventNames().mousewheelEvent && currentEvent->type() == WebEvent::Wheel && m_plugin->wantsWheelEvents()) {
 
811
        // We have a wheel event.
 
812
        didHandleEvent = m_plugin->handleWheelEvent(static_cast<const WebWheelEvent&>(*currentEvent));
 
813
    } else if (event->type() == eventNames().mouseoverEvent && currentEvent->type() == WebEvent::MouseMove) {
 
814
        // We have a mouse enter event.
 
815
        didHandleEvent = m_plugin->handleMouseEnterEvent(static_cast<const WebMouseEvent&>(*currentEvent));
 
816
    } else if (event->type() == eventNames().mouseoutEvent && currentEvent->type() == WebEvent::MouseMove) {
 
817
        // We have a mouse leave event.
 
818
        didHandleEvent = m_plugin->handleMouseLeaveEvent(static_cast<const WebMouseEvent&>(*currentEvent));
 
819
    } else if (event->type() == eventNames().contextmenuEvent && currentEvent->type() == WebEvent::MouseDown) {
 
820
        // We have a context menu event.
 
821
        didHandleEvent = m_plugin->handleContextMenuEvent(static_cast<const WebMouseEvent&>(*currentEvent));
 
822
    } else if ((event->type() == eventNames().keydownEvent && currentEvent->type() == WebEvent::KeyDown)
 
823
               || (event->type() == eventNames().keyupEvent && currentEvent->type() == WebEvent::KeyUp)) {
 
824
        // We have a keyboard event.
 
825
        didHandleEvent = m_plugin->handleKeyboardEvent(static_cast<const WebKeyboardEvent&>(*currentEvent));
 
826
    }
 
827
 
 
828
    if (didHandleEvent)
 
829
        event->setDefaultHandled();
 
830
}
 
831
    
 
832
bool PluginView::handleEditingCommand(const String& commandName, const String& argument)
 
833
{
 
834
    if (!m_isInitialized || !m_plugin)
 
835
        return false;
 
836
 
 
837
    return m_plugin->handleEditingCommand(commandName, argument);
 
838
}
 
839
    
 
840
bool PluginView::isEditingCommandEnabled(const String& commandName)
 
841
{
 
842
    if (!m_isInitialized || !m_plugin)
 
843
        return false;
 
844
 
 
845
    return m_plugin->isEditingCommandEnabled(commandName);
 
846
}
 
847
 
 
848
bool PluginView::shouldAllowScripting()
 
849
{
 
850
    if (!m_isInitialized || !m_plugin)
 
851
        return false;
 
852
 
 
853
    return m_plugin->shouldAllowScripting();
 
854
}
 
855
 
 
856
void PluginView::notifyWidget(WidgetNotification notification)
 
857
{
 
858
    switch (notification) {
 
859
    case WillPaintFlattened:
 
860
        if (m_plugin && m_isInitialized)
 
861
            m_transientPaintingSnapshot = m_plugin->snapshot();
 
862
        break;
 
863
    case DidPaintFlattened:
 
864
        m_transientPaintingSnapshot = nullptr;
 
865
        break;
 
866
    }
 
867
}
 
868
 
 
869
void PluginView::show()
 
870
{
 
871
    bool wasVisible = isVisible();
 
872
 
 
873
    setSelfVisible(true);
 
874
 
 
875
    if (!wasVisible)
 
876
        viewVisibilityDidChange();
 
877
 
 
878
    Widget::show();
 
879
}
 
880
 
 
881
void PluginView::hide()
 
882
{
 
883
    bool wasVisible = isVisible();
 
884
 
 
885
    setSelfVisible(false);
 
886
 
 
887
    if (wasVisible)
 
888
        viewVisibilityDidChange();
 
889
 
 
890
    Widget::hide();
 
891
}
 
892
 
 
893
bool PluginView::transformsAffectFrameRect()
 
894
{
 
895
    return false;
 
896
}
 
897
 
 
898
void PluginView::viewGeometryDidChange()
 
899
{
 
900
    if (!m_isInitialized || !m_plugin || !parent())
 
901
        return;
 
902
 
 
903
    ASSERT(frame());
 
904
    float pageScaleFactor = frame()->page() ? frame()->page()->pageScaleFactor() : 1;
 
905
 
 
906
    IntPoint scaledFrameRectLocation(frameRect().location().x() * pageScaleFactor, frameRect().location().y() * pageScaleFactor);
 
907
    IntPoint scaledLocationInRootViewCoordinates(parent()->contentsToRootView(scaledFrameRectLocation));
 
908
 
 
909
    // FIXME: We still don't get the right coordinates for transformed plugins.
 
910
    AffineTransform transform;
 
911
    transform.translate(scaledLocationInRootViewCoordinates.x(), scaledLocationInRootViewCoordinates.y());
 
912
    transform.scale(pageScaleFactor);
 
913
 
 
914
    // FIXME: The way we calculate this clip rect isn't correct.
 
915
    // But it is still important to distinguish between empty and non-empty rects so we can notify the plug-in when it becomes invisible.
 
916
    // Making the rect actually correct is covered by https://bugs.webkit.org/show_bug.cgi?id=95362
 
917
    IntRect clipRect = boundsRect();
 
918
    
 
919
    // FIXME: We can only get a semi-reliable answer from clipRectInWindowCoordinates() when the page is not scaled.
 
920
    // Fixing that is tracked in <rdar://problem/9026611> - Make the Widget hierarchy play nicely with transforms, for zoomed plug-ins and iframes
 
921
    if (pageScaleFactor == 1) {
 
922
        clipRect = clipRectInWindowCoordinates();
 
923
        if (!clipRect.isEmpty())
 
924
            clipRect = boundsRect();
 
925
    }
 
926
    
 
927
    m_plugin->geometryDidChange(size(), clipRect, transform);
 
928
}
 
929
 
 
930
void PluginView::viewVisibilityDidChange()
 
931
{
 
932
    if (!m_isInitialized || !m_plugin || !parent())
 
933
        return;
 
934
 
 
935
    m_plugin->visibilityDidChange();
 
936
}
 
937
 
 
938
IntRect PluginView::clipRectInWindowCoordinates() const
 
939
{
 
940
    // Get the frame rect in window coordinates.
 
941
    IntRect frameRectInWindowCoordinates = parent()->contentsToWindow(frameRect());
 
942
 
 
943
    Frame* frame = this->frame();
 
944
 
 
945
    // Get the window clip rect for the plugin element (in window coordinates).
 
946
    IntRect windowClipRect = frame->view()->windowClipRectForFrameOwner(m_pluginElement.get(), true);
 
947
 
 
948
    // Intersect the two rects to get the view clip rect in window coordinates.
 
949
    frameRectInWindowCoordinates.intersect(windowClipRect);
 
950
 
 
951
    return frameRectInWindowCoordinates;
 
952
}
 
953
 
 
954
void PluginView::focusPluginElement()
 
955
{
 
956
    ASSERT(frame());
 
957
    
 
958
    if (Page* page = frame()->page())
 
959
       page->focusController()->setFocusedNode(m_pluginElement.get(), frame());
 
960
    else
 
961
       frame()->document()->setFocusedNode(m_pluginElement);
 
962
}
 
963
 
 
964
void PluginView::pendingURLRequestsTimerFired()
 
965
{
 
966
    ASSERT(!m_pendingURLRequests.isEmpty());
 
967
    
 
968
    RefPtr<URLRequest> urlRequest = m_pendingURLRequests.takeFirst();
 
969
 
 
970
    // If there are more requests to perform, reschedule the timer.
 
971
    if (!m_pendingURLRequests.isEmpty())
 
972
        m_pendingURLRequestsTimer.startOneShot(0);
 
973
    
 
974
    performURLRequest(urlRequest.get());
 
975
}
 
976
    
 
977
void PluginView::performURLRequest(URLRequest* request)
 
978
{
 
979
    // This protector is needed to make sure the PluginView is not destroyed while it is still needed.
 
980
    RefPtr<PluginView> protect(this);
 
981
 
 
982
    // First, check if this is a javascript: url.
 
983
    if (protocolIsJavaScript(request->request().url())) {
 
984
        performJavaScriptURLRequest(request);
 
985
        return;
 
986
    }
 
987
 
 
988
    if (!request->target().isNull()) {
 
989
        performFrameLoadURLRequest(request);
 
990
        return;
 
991
    }
 
992
 
 
993
    // This request is to load a URL and create a stream.
 
994
    RefPtr<Stream> stream = PluginView::Stream::create(this, request->requestID(), request->request());
 
995
    addStream(stream.get());
 
996
    stream->start();
 
997
}
 
998
 
 
999
void PluginView::performFrameLoadURLRequest(URLRequest* request)
 
1000
{
 
1001
    ASSERT(!request->target().isNull());
 
1002
 
 
1003
    Frame* frame = m_pluginElement->document()->frame();
 
1004
    if (!frame)
 
1005
        return;
 
1006
 
 
1007
    if (!m_pluginElement->document()->securityOrigin()->canDisplay(request->request().url())) {
 
1008
        // We can't load the request, send back a reply to the plug-in.
 
1009
        m_plugin->frameDidFail(request->requestID(), false);
 
1010
        return;
 
1011
    }
 
1012
 
 
1013
    // First, try to find a target frame.
 
1014
    Frame* targetFrame = frame->loader()->findFrameForNavigation(request->target());
 
1015
    if (!targetFrame) {
 
1016
        // We did not find a target frame. Ask our frame to load the page. This may or may not create a popup window.
 
1017
        FrameLoadRequest frameRequest(frame, request->request());
 
1018
        frameRequest.setFrameName(request->target());
 
1019
        frameRequest.setShouldCheckNewWindowPolicy(true);
 
1020
        frame->loader()->load(frameRequest);
 
1021
 
 
1022
        // FIXME: We don't know whether the window was successfully created here so we just assume that it worked.
 
1023
        // It's better than not telling the plug-in anything.
 
1024
        m_plugin->frameDidFinishLoading(request->requestID());
 
1025
        return;
 
1026
    }
 
1027
 
 
1028
    // Now ask the frame to load the request.
 
1029
    targetFrame->loader()->load(FrameLoadRequest(targetFrame, request->request()));
 
1030
 
 
1031
    WebFrame* targetWebFrame = static_cast<WebFrameLoaderClient*>(targetFrame->loader()->client())->webFrame();
 
1032
    if (WebFrame::LoadListener* loadListener = targetWebFrame->loadListener()) {
 
1033
        // Check if another plug-in view or even this view is waiting for the frame to load.
 
1034
        // If it is, tell it that the load was cancelled because it will be anyway.
 
1035
        loadListener->didFailLoad(targetWebFrame, true);
 
1036
    }
 
1037
    
 
1038
    m_pendingFrameLoads.set(targetWebFrame, request);
 
1039
    targetWebFrame->setLoadListener(this);
 
1040
}
 
1041
 
 
1042
void PluginView::performJavaScriptURLRequest(URLRequest* request)
 
1043
{
 
1044
    ASSERT(protocolIsJavaScript(request->request().url()));
 
1045
 
 
1046
    RefPtr<Frame> frame = m_pluginElement->document()->frame();
 
1047
    if (!frame)
 
1048
        return;
 
1049
    
 
1050
    String jsString = decodeURLEscapeSequences(request->request().url().string().substring(sizeof("javascript:") - 1));
 
1051
 
 
1052
    if (!request->target().isNull()) {
 
1053
        // For security reasons, only allow JS requests to be made on the frame that contains the plug-in.
 
1054
        if (frame->tree()->find(request->target()) != frame) {
 
1055
            // Let the plug-in know that its frame load failed.
 
1056
            m_plugin->frameDidFail(request->requestID(), false);
 
1057
            return;
 
1058
        }
 
1059
    }
 
1060
 
 
1061
    // Evaluate the JavaScript code. Note that running JavaScript here could cause the plug-in to be destroyed, so we
 
1062
    // grab references to the plug-in here.
 
1063
    RefPtr<Plugin> plugin = m_plugin;
 
1064
    ScriptValue result = frame->script()->executeScript(jsString, request->allowPopups());
 
1065
 
 
1066
    // Check if evaluating the JavaScript destroyed the plug-in.
 
1067
    if (!plugin->controller())
 
1068
        return;
 
1069
 
 
1070
    // Don't notify the plug-in at all about targeted javascript: requests. This matches Mozilla and WebKit1.
 
1071
    if (!request->target().isNull())
 
1072
        return;
 
1073
 
 
1074
    ScriptState* scriptState = frame->script()->globalObject(pluginWorld())->globalExec();
 
1075
    String resultString;
 
1076
    result.getString(scriptState, resultString);
 
1077
  
 
1078
    // Send the result back to the plug-in.
 
1079
    plugin->didEvaluateJavaScript(request->requestID(), resultString);
 
1080
}
 
1081
 
 
1082
void PluginView::addStream(Stream* stream)
 
1083
{
 
1084
    ASSERT(!m_streams.contains(stream->streamID()));
 
1085
    m_streams.set(stream->streamID(), stream);
 
1086
}
 
1087
    
 
1088
void PluginView::removeStream(Stream* stream)
 
1089
{
 
1090
    ASSERT(m_streams.get(stream->streamID()) == stream);
 
1091
    
 
1092
    m_streams.remove(stream->streamID());
 
1093
}
 
1094
 
 
1095
void PluginView::cancelAllStreams()
 
1096
{
 
1097
    Vector<RefPtr<Stream> > streams;
 
1098
    copyValuesToVector(m_streams, streams);
 
1099
    
 
1100
    for (size_t i = 0; i < streams.size(); ++i)
 
1101
        streams[i]->cancel();
 
1102
 
 
1103
    // Cancelling a stream removes it from the m_streams map, so if we cancel all streams the map should be empty.
 
1104
    ASSERT(m_streams.isEmpty());
 
1105
}
 
1106
 
 
1107
void PluginView::redeliverManualStream()
 
1108
{
 
1109
    if (m_manualStreamState == StreamStateInitial) {
 
1110
        // Nothing to do.
 
1111
        return;
 
1112
    }
 
1113
 
 
1114
    if (m_manualStreamState == StreamStateFailed) {
 
1115
        manualLoadDidFail(m_manualStreamError);
 
1116
        return;
 
1117
    }
 
1118
 
 
1119
    // Deliver the response.
 
1120
    manualLoadDidReceiveResponse(m_manualStreamResponse);
 
1121
 
 
1122
    // Deliver the data.
 
1123
    if (m_manualStreamData) {
 
1124
        const char* data;
 
1125
        unsigned position = 0;
 
1126
 
 
1127
        while (unsigned length = m_manualStreamData->getSomeData(data, position)) {
 
1128
            manualLoadDidReceiveData(data, length);
 
1129
            position += length;
 
1130
        }
 
1131
 
 
1132
        m_manualStreamData = nullptr;
 
1133
    }
 
1134
 
 
1135
    if (m_manualStreamState == StreamStateFinished)
 
1136
        manualLoadDidFinishLoading();
 
1137
}
 
1138
 
 
1139
void PluginView::invalidateRect(const IntRect& dirtyRect)
 
1140
{
 
1141
    if (!parent() || !m_plugin || !m_isInitialized)
 
1142
        return;
 
1143
 
 
1144
#if PLATFORM(MAC)
 
1145
    if (m_plugin->pluginLayer())
 
1146
        return;
 
1147
#endif
 
1148
 
 
1149
    if (m_pluginElement->displayState() < HTMLPlugInElement::PlayingWithPendingMouseClick)
 
1150
        return;
 
1151
 
 
1152
    RenderBoxModelObject* renderer = toRenderBoxModelObject(m_pluginElement->renderer());
 
1153
    if (!renderer)
 
1154
        return;
 
1155
    
 
1156
    IntRect contentRect(dirtyRect);
 
1157
    contentRect.move(renderer->borderLeft() + renderer->paddingLeft(), renderer->borderTop() + renderer->paddingTop());
 
1158
    renderer->repaintRectangle(contentRect);
 
1159
}
 
1160
 
 
1161
void PluginView::setFocus(bool hasFocus)
 
1162
{
 
1163
    Widget::setFocus(hasFocus);
 
1164
 
 
1165
    if (!m_isInitialized || !m_plugin)
 
1166
        return;
 
1167
 
 
1168
    m_plugin->setFocus(hasFocus);
 
1169
}
 
1170
 
 
1171
void PluginView::mediaCanStart()
 
1172
{
 
1173
    ASSERT(m_isWaitingUntilMediaCanStart);
 
1174
    m_isWaitingUntilMediaCanStart = false;
 
1175
    
 
1176
    initializePlugin();
 
1177
}
 
1178
 
 
1179
bool PluginView::isPluginVisible()
 
1180
{
 
1181
    return isVisible();
 
1182
}
 
1183
 
 
1184
void PluginView::invalidate(const IntRect& dirtyRect)
 
1185
{
 
1186
    invalidateRect(dirtyRect);
 
1187
}
 
1188
 
 
1189
String PluginView::userAgent()
 
1190
{
 
1191
    Frame* frame = m_pluginElement->document()->frame();
 
1192
    if (!frame)
 
1193
        return String();
 
1194
    
 
1195
    return frame->loader()->client()->userAgent(KURL());
 
1196
}
 
1197
 
 
1198
void PluginView::loadURL(uint64_t requestID, const String& method, const String& urlString, const String& target, 
 
1199
                         const HTTPHeaderMap& headerFields, const Vector<uint8_t>& httpBody, bool allowPopups)
 
1200
{
 
1201
    FrameLoadRequest frameLoadRequest(m_pluginElement->document()->securityOrigin());
 
1202
    frameLoadRequest.resourceRequest().setHTTPMethod(method);
 
1203
    frameLoadRequest.resourceRequest().setURL(m_pluginElement->document()->completeURL(urlString));
 
1204
    frameLoadRequest.resourceRequest().addHTTPHeaderFields(headerFields);
 
1205
    frameLoadRequest.resourceRequest().setHTTPBody(FormData::create(httpBody.data(), httpBody.size()));
 
1206
    frameLoadRequest.setFrameName(target);
 
1207
 
 
1208
    String referrer = SecurityPolicy::generateReferrerHeader(frame()->document()->referrerPolicy(), frameLoadRequest.resourceRequest().url(), frame()->loader()->outgoingReferrer());
 
1209
    if (!referrer.isEmpty())
 
1210
        frameLoadRequest.resourceRequest().setHTTPReferrer(referrer);
 
1211
 
 
1212
    m_pendingURLRequests.append(URLRequest::create(requestID, frameLoadRequest, allowPopups));
 
1213
    m_pendingURLRequestsTimer.startOneShot(0);
 
1214
}
 
1215
 
 
1216
void PluginView::cancelStreamLoad(uint64_t streamID)
 
1217
{
 
1218
    // Keep a reference to the stream. Stream::cancel might remove the stream from the map, and thus
 
1219
    // releasing its last reference.
 
1220
    RefPtr<Stream> stream = m_streams.get(streamID).get();
 
1221
    if (!stream)
 
1222
        return;
 
1223
 
 
1224
    // Cancelling the stream here will remove it from the map.
 
1225
    stream->cancel();
 
1226
    ASSERT(!m_streams.contains(streamID));
 
1227
}
 
1228
 
 
1229
void PluginView::cancelManualStreamLoad()
 
1230
{
 
1231
    if (!frame())
 
1232
        return;
 
1233
 
 
1234
    DocumentLoader* documentLoader = frame()->loader()->activeDocumentLoader();
 
1235
    ASSERT(documentLoader);
 
1236
    
 
1237
    if (documentLoader->isLoadingMainResource())
 
1238
        documentLoader->cancelMainResourceLoad(frame()->loader()->cancelledError(m_parameters.url));
 
1239
}
 
1240
 
 
1241
#if ENABLE(NETSCAPE_PLUGIN_API)
 
1242
NPObject* PluginView::windowScriptNPObject()
 
1243
{
 
1244
    if (!frame())
 
1245
        return 0;
 
1246
 
 
1247
    if (!frame()->script()->canExecuteScripts(NotAboutToExecuteScript)) {
 
1248
        // FIXME: Investigate if other browsers allow plug-ins to access JavaScript objects even if JavaScript is disabled.
 
1249
        return 0;
 
1250
    }
 
1251
 
 
1252
    return m_npRuntimeObjectMap.getOrCreateNPObject(*pluginWorld()->globalData(), frame()->script()->windowShell(pluginWorld())->window());
 
1253
}
 
1254
 
 
1255
NPObject* PluginView::pluginElementNPObject()
 
1256
{
 
1257
    if (!frame())
 
1258
        return 0;
 
1259
 
 
1260
    if (!frame()->script()->canExecuteScripts(NotAboutToExecuteScript)) {
 
1261
        // FIXME: Investigate if other browsers allow plug-ins to access JavaScript objects even if JavaScript is disabled.
 
1262
        return 0;
 
1263
    }
 
1264
 
 
1265
    JSObject* object = frame()->script()->jsObjectForPluginElement(m_pluginElement.get());
 
1266
    ASSERT(object);
 
1267
 
 
1268
    return m_npRuntimeObjectMap.getOrCreateNPObject(*pluginWorld()->globalData(), object);
 
1269
}
 
1270
 
 
1271
bool PluginView::evaluate(NPObject* npObject, const String& scriptString, NPVariant* result, bool allowPopups)
 
1272
{
 
1273
    // FIXME: Is this check necessary?
 
1274
    if (!m_pluginElement->document()->frame())
 
1275
        return false;
 
1276
 
 
1277
    // Calling evaluate will run JavaScript that can potentially remove the plug-in element, so we need to
 
1278
    // protect the plug-in view from destruction.
 
1279
    NPRuntimeObjectMap::PluginProtector pluginProtector(&m_npRuntimeObjectMap);
 
1280
 
 
1281
    UserGestureIndicator gestureIndicator(allowPopups ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture);
 
1282
    return m_npRuntimeObjectMap.evaluate(npObject, scriptString, result);
 
1283
}
 
1284
#endif
 
1285
 
 
1286
void PluginView::setStatusbarText(const String& statusbarText)
 
1287
{
 
1288
    if (!frame())
 
1289
        return;
 
1290
    
 
1291
    Page* page = frame()->page();
 
1292
    if (!page)
 
1293
        return;
 
1294
 
 
1295
    page->chrome()->setStatusbarText(frame(), statusbarText);
 
1296
}
 
1297
 
 
1298
bool PluginView::isAcceleratedCompositingEnabled()
 
1299
{
 
1300
    if (!frame())
 
1301
        return false;
 
1302
    
 
1303
    Settings* settings = frame()->settings();
 
1304
    if (!settings)
 
1305
        return false;
 
1306
 
 
1307
    if (m_pluginElement->displayState() < HTMLPlugInElement::PlayingWithPendingMouseClick)
 
1308
        return false;
 
1309
    return settings->acceleratedCompositingEnabled();
 
1310
}
 
1311
 
 
1312
void PluginView::pluginProcessCrashed()
 
1313
{
 
1314
    if (!m_pluginElement->renderer())
 
1315
        return;
 
1316
 
 
1317
    // FIXME: The renderer could also be a RenderApplet, we should handle that.
 
1318
    if (!m_pluginElement->renderer()->isEmbeddedObject())
 
1319
        return;
 
1320
        
 
1321
    RenderEmbeddedObject* renderer = toRenderEmbeddedObject(m_pluginElement->renderer());
 
1322
    renderer->setPluginUnavailabilityReason(RenderEmbeddedObject::PluginCrashed);
 
1323
    
 
1324
    Widget::invalidate();
 
1325
}
 
1326
 
 
1327
void PluginView::willSendEventToPlugin()
 
1328
{
 
1329
    // If we're sending an event to a plug-in, we can't control how long the plug-in
 
1330
    // takes to process it (e.g. it may display a context menu), so we tell the UI process
 
1331
    // to stop the responsiveness timer in this case.
 
1332
    m_webPage->send(Messages::WebPageProxy::StopResponsivenessTimer());
 
1333
}
 
1334
 
 
1335
#if PLATFORM(WIN)
 
1336
HWND PluginView::nativeParentWindow()
 
1337
{
 
1338
    return m_webPage->nativeWindow();
 
1339
}
 
1340
 
 
1341
void PluginView::scheduleWindowedPluginGeometryUpdate(const WindowGeometry& geometry)
 
1342
{
 
1343
    m_webPage->drawingArea()->scheduleChildWindowGeometryUpdate(geometry);
 
1344
}
 
1345
#endif
 
1346
 
 
1347
#if PLATFORM(MAC)
 
1348
void PluginView::pluginFocusOrWindowFocusChanged(bool pluginHasFocusAndWindowHasFocus)
 
1349
{
 
1350
    if (m_webPage)
 
1351
        m_webPage->send(Messages::WebPageProxy::PluginFocusOrWindowFocusChanged(m_plugin->pluginComplexTextInputIdentifier(), pluginHasFocusAndWindowHasFocus));
 
1352
}
 
1353
 
 
1354
void PluginView::setComplexTextInputState(PluginComplexTextInputState pluginComplexTextInputState)
 
1355
{
 
1356
    if (m_webPage)
 
1357
        m_webPage->send(Messages::WebPageProxy::SetPluginComplexTextInputState(m_plugin->pluginComplexTextInputIdentifier(), pluginComplexTextInputState));
 
1358
}
 
1359
 
 
1360
mach_port_t PluginView::compositingRenderServerPort()
 
1361
{
 
1362
    return WebProcess::shared().compositingRenderServerPort();
 
1363
}
 
1364
#endif
 
1365
 
 
1366
float PluginView::contentsScaleFactor()
 
1367
{
 
1368
    if (Page* page = frame() ? frame()->page() : 0)
 
1369
        return page->deviceScaleFactor();
 
1370
        
 
1371
    return 1;
 
1372
}
 
1373
    
 
1374
String PluginView::proxiesForURL(const String& urlString)
 
1375
{
 
1376
    const FrameLoader* frameLoader = frame() ? frame()->loader() : 0;
 
1377
    const NetworkingContext* context = frameLoader ? frameLoader->networkingContext() : 0;
 
1378
    Vector<ProxyServer> proxyServers = proxyServersForURL(KURL(KURL(), urlString), context);
 
1379
    return toString(proxyServers);
 
1380
}
 
1381
 
 
1382
String PluginView::cookiesForURL(const String& urlString)
 
1383
{
 
1384
    return cookies(m_pluginElement->document(), KURL(KURL(), urlString));
 
1385
}
 
1386
 
 
1387
void PluginView::setCookiesForURL(const String& urlString, const String& cookieString)
 
1388
{
 
1389
    setCookies(m_pluginElement->document(), KURL(KURL(), urlString), cookieString);
 
1390
}
 
1391
 
 
1392
bool PluginView::getAuthenticationInfo(const ProtectionSpace& protectionSpace, String& username, String& password)
 
1393
{
 
1394
    Credential credential = CredentialStorage::get(protectionSpace);
 
1395
    if (credential.isEmpty())
 
1396
        credential = CredentialStorage::getFromPersistentStorage(protectionSpace);
 
1397
 
 
1398
    if (!credential.hasPassword())
 
1399
        return false;
 
1400
 
 
1401
    username = credential.user();
 
1402
    password = credential.password();
 
1403
 
 
1404
    return true;
 
1405
}
 
1406
 
 
1407
bool PluginView::isPrivateBrowsingEnabled()
 
1408
{
 
1409
    // If we can't get the real setting, we'll assume that private browsing is enabled.
 
1410
    if (!frame())
 
1411
        return true;
 
1412
 
 
1413
    if (!frame()->document()->securityOrigin()->canAccessPluginStorage(frame()->tree()->top()->document()->securityOrigin()))
 
1414
        return true;
 
1415
 
 
1416
    Settings* settings = frame()->settings();
 
1417
    if (!settings)
 
1418
        return true;
 
1419
 
 
1420
    return settings->privateBrowsingEnabled();
 
1421
}
 
1422
 
 
1423
bool PluginView::asynchronousPluginInitializationEnabled() const
 
1424
{
 
1425
    return m_webPage->asynchronousPluginInitializationEnabled();
 
1426
}
 
1427
 
 
1428
bool PluginView::asynchronousPluginInitializationEnabledForAllPlugins() const
 
1429
{
 
1430
    return m_webPage->asynchronousPluginInitializationEnabledForAllPlugins();
 
1431
}
 
1432
 
 
1433
bool PluginView::artificialPluginInitializationDelayEnabled() const
 
1434
{
 
1435
    return m_webPage->artificialPluginInitializationDelayEnabled();
 
1436
}
 
1437
 
 
1438
void PluginView::protectPluginFromDestruction()
 
1439
{
 
1440
    if (!m_isBeingDestroyed)
 
1441
        ref();
 
1442
}
 
1443
 
 
1444
static void derefPluginView(PluginView* pluginView)
 
1445
{
 
1446
    pluginView->deref();
 
1447
}
 
1448
 
 
1449
void PluginView::unprotectPluginFromDestruction()
 
1450
{
 
1451
    if (m_isBeingDestroyed)
 
1452
        return;
 
1453
 
 
1454
    // A plug-in may ask us to evaluate JavaScript that removes the plug-in from the
 
1455
    // page, but expect the object to still be alive when the call completes. Flash,
 
1456
    // for example, may crash if the plug-in is destroyed and we return to code for
 
1457
    // the destroyed object higher on the stack. To prevent this, if the plug-in has
 
1458
    // only one remaining reference, call deref() asynchronously.
 
1459
    if (hasOneRef())
 
1460
        RunLoop::main()->dispatch(bind(derefPluginView, this));
 
1461
    else
 
1462
        deref();
 
1463
}
 
1464
 
 
1465
void PluginView::didFinishLoad(WebFrame* webFrame)
 
1466
{
 
1467
    RefPtr<URLRequest> request = m_pendingFrameLoads.take(webFrame);
 
1468
    ASSERT(request);
 
1469
    webFrame->setLoadListener(0);
 
1470
 
 
1471
    m_plugin->frameDidFinishLoading(request->requestID());
 
1472
}
 
1473
 
 
1474
void PluginView::didFailLoad(WebFrame* webFrame, bool wasCancelled)
 
1475
{
 
1476
    RefPtr<URLRequest> request = m_pendingFrameLoads.take(webFrame);
 
1477
    ASSERT(request);
 
1478
    webFrame->setLoadListener(0);
 
1479
    
 
1480
    m_plugin->frameDidFail(request->requestID(), wasCancelled);
 
1481
}
 
1482
 
 
1483
#if PLUGIN_ARCHITECTURE(X11)
 
1484
uint64_t PluginView::createPluginContainer()
 
1485
{
 
1486
    uint64_t windowID = 0;
 
1487
    m_webPage->sendSync(Messages::WebPageProxy::CreatePluginContainer(), Messages::WebPageProxy::CreatePluginContainer::Reply(windowID));
 
1488
    return windowID;
 
1489
}
 
1490
 
 
1491
void PluginView::windowedPluginGeometryDidChange(const WebCore::IntRect& frameRect, const WebCore::IntRect& clipRect, uint64_t windowID)
 
1492
{
 
1493
    m_webPage->send(Messages::WebPageProxy::WindowedPluginGeometryDidChange(frameRect, clipRect, windowID));
 
1494
}
 
1495
#endif
 
1496
 
 
1497
void PluginView::pluginSnapshotTimerFired(DeferrableOneShotTimer<PluginView>* timer)
 
1498
{
 
1499
    ASSERT_UNUSED(timer, timer == &m_pluginSnapshotTimer);
 
1500
    ASSERT(m_plugin);
 
1501
 
 
1502
    // Snapshot might be 0 if plugin size is 0x0.
 
1503
    RefPtr<ShareableBitmap> snapshot = m_plugin->snapshot();
 
1504
    RefPtr<Image> snapshotImage;
 
1505
    if (snapshot)
 
1506
        snapshotImage = snapshot->createImage();
 
1507
    m_pluginElement->updateSnapshot(snapshotImage.release());
 
1508
    destroyPluginAndReset();
 
1509
    m_plugin = 0;
 
1510
}
 
1511
 
 
1512
} // namespace WebKit