WebView.cpp 198 KB
Newer Older
aroben's avatar
aroben committed
1
/*
2
 * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple, Inc.  All rights reserved.
aroben's avatar
aroben committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

#include "config.h"
#include "WebView.h"

beidson's avatar
beidson committed
29
#include "CFDictionaryPropertyBag.h"
aroben's avatar
aroben committed
30
#include "DOMCoreClasses.h"
31
#include "FullscreenVideoController.h"
32
#include "MarshallingHelpers.h"
33
#include "SoftLinking.h"
34
35
36
37
#include "WebBackForwardList.h"
#include "WebChromeClient.h"
#include "WebContextMenuClient.h"
#include "WebCoreTextRenderer.h"
beidson's avatar
beidson committed
38
#include "WebDatabaseManager.h"
aroben's avatar
aroben committed
39
#include "WebDocumentLoader.h"
40
#include "WebDownload.h"
41
#include "WebDragClient.h"
aroben's avatar
aroben committed
42
43
44
#include "WebEditorClient.h"
#include "WebElementPropertyBag.h"
#include "WebFrame.h"
45
46
#include "WebGeolocationControllerClient.h"
#include "WebGeolocationPosition.h"
beidson's avatar
beidson committed
47
#include "WebIconDatabase.h"
48
#include "WebInspector.h"
aroben's avatar
aroben committed
49
#include "WebInspectorClient.h"
aroben's avatar
aroben committed
50
#include "WebKit.h"
51
#include "WebKitDLL.h"
ap@apple.com's avatar
ap@apple.com committed
52
#include "WebKitLogging.h"
aroben's avatar
aroben committed
53
#include "WebKitStatisticsPrivate.h"
weinig's avatar
weinig committed
54
#include "WebKitSystemBits.h"
aroben's avatar
aroben committed
55
56
#include "WebMutableURLRequest.h"
#include "WebNotificationCenter.h"
57
#include "WebPluginHalterClient.h"
aroben's avatar
aroben committed
58
#include "WebPreferences.h"
59
#include "WebScriptWorld.h"
60
#include "WindowsTouch.h"
61
#include <JavaScriptCore/APICast.h>
62
63
64
#include <JavaScriptCore/InitializeThreading.h>
#include <JavaScriptCore/JSLock.h>
#include <JavaScriptCore/JSValue.h>
65
#include <WebCore/AXObjectCache.h>
66
67
#include <WebCore/ApplicationCacheStorage.h>
#include <WebCore/BString.h>
68
#include <WebCore/BackForwardList.h>
bfulgham@webkit.org's avatar
bfulgham@webkit.org committed
69
#include <WebCore/BitmapInfo.h>
aroben's avatar
aroben committed
70
#include <WebCore/Cache.h>
71
#include <WebCore/Chrome.h>
72
#include <WebCore/ContextMenu.h>
aroben's avatar
aroben committed
73
#include <WebCore/ContextMenuController.h>
74
#include <WebCore/CookieStorageWin.h>
aroben's avatar
aroben committed
75
#include <WebCore/Cursor.h>
76
#include <WebCore/Database.h>
aroben's avatar
aroben committed
77
78
79
80
81
#include <WebCore/Document.h>
#include <WebCore/DragController.h>
#include <WebCore/DragData.h>
#include <WebCore/Editor.h>
#include <WebCore/EventHandler.h>
ap@webkit.org's avatar
ap@webkit.org committed
82
#include <WebCore/EventNames.h>
weinig's avatar
weinig committed
83
#include <WebCore/FileSystem.h>
84
#include <WebCore/FloatQuad.h>
85
#include <WebCore/FocusController.h>
aroben's avatar
aroben committed
86
87
88
89
90
91
#include <WebCore/FrameLoader.h>
#include <WebCore/FrameTree.h>
#include <WebCore/FrameView.h>
#include <WebCore/FrameWin.h>
#include <WebCore/GDIObjectCounter.h>
#include <WebCore/GraphicsContext.h>
92
93
#include <WebCore/HTMLMediaElement.h>
#include <WebCore/HTMLNames.h>
aroben's avatar
aroben committed
94
#include <WebCore/HistoryItem.h>
95
#include <WebCore/HitTestRequest.h>
aroben's avatar
aroben committed
96
97
98
#include <WebCore/HitTestResult.h>
#include <WebCore/IntRect.h>
#include <WebCore/KeyboardEvent.h>
99
#include <WebCore/Language.h>
100
#include <WebCore/Logging.h>
weinig's avatar
weinig committed
101
#include <WebCore/MIMETypeRegistry.h>
aroben's avatar
aroben committed
102
103
#include <WebCore/Page.h>
#include <WebCore/PageCache.h>
104
#include <WebCore/PageGroup.h>
aroben's avatar
aroben committed
105
106
107
#include <WebCore/PlatformKeyboardEvent.h>
#include <WebCore/PlatformMouseEvent.h>
#include <WebCore/PlatformWheelEvent.h>
108
109
110
#include <WebCore/PluginDatabase.h>
#include <WebCore/PluginInfoStore.h>
#include <WebCore/PluginView.h>
111
#include <WebCore/PopupMenu.h>
aroben's avatar
aroben committed
112
#include <WebCore/ProgressTracker.h>
hyatt@apple.com's avatar
hyatt@apple.com committed
113
#include <WebCore/RenderTheme.h>
114
#include <WebCore/RenderView.h>
115
#include <WebCore/RenderWidget.h>
aroben's avatar
aroben committed
116
117
#include <WebCore/ResourceHandle.h>
#include <WebCore/ResourceHandleClient.h>
118
#include <WebCore/ScriptValue.h>
119
#include <WebCore/Scrollbar.h>
hyatt@apple.com's avatar
hyatt@apple.com committed
120
#include <WebCore/ScrollbarTheme.h>
abarth@webkit.org's avatar
abarth@webkit.org committed
121
#include <WebCore/SecurityOrigin.h>
aroben's avatar
aroben committed
122
123
#include <WebCore/SelectionController.h>
#include <WebCore/Settings.h>
mitz@apple.com's avatar
mitz@apple.com committed
124
#include <WebCore/SimpleFontData.h>
aroben's avatar
aroben committed
125
#include <WebCore/TypingCommand.h>
126
#include <WebCore/WindowMessageBroadcaster.h>
127
#include <wtf/Threading.h>
128

129
130
131
132
133
#if ENABLE(CLIENT_BASED_GEOLOCATION)
#include <WebCore/GeolocationController.h>
#include <WebCore/GeolocationError.h>
#endif

134
135
136
137
138
139
140
141
142
#if PLATFORM(CG)
#include <CoreGraphics/CGContext.h>
#endif

#if PLATFORM(CF)
#include <CoreFoundation/CoreFoundation.h>
#endif

#if USE(CFNETWORK)
weinig's avatar
weinig committed
143
#include <CFNetwork/CFURLCachePriv.h>
aroben's avatar
aroben committed
144
#include <CFNetwork/CFURLProtocolPriv.h>
145
#include <WebKitSystemInterface/WebKitSystemInterface.h> 
146
147
#endif

148
#include <ShlObj.h>
149
#include <comutil.h>
oliver's avatar
oliver committed
150
#include <dimm.h>
151
152
153
#include <oleacc.h>
#include <tchar.h>
#include <windowsx.h>
154
#include <wtf/HashSet.h>
155
#include <wtf/text/CString.h>
aroben's avatar
aroben committed
156

157
158
159
160
161
162
163
164
165
166
// Soft link functions for gestures and panning feedback
SOFT_LINK_LIBRARY(USER32);
SOFT_LINK_OPTIONAL(USER32, GetGestureInfo, BOOL, WINAPI, (HGESTUREINFO, PGESTUREINFO));
SOFT_LINK_OPTIONAL(USER32, SetGestureConfig, BOOL, WINAPI, (HWND, DWORD, UINT, PGESTURECONFIG, UINT));
SOFT_LINK_OPTIONAL(USER32, CloseGestureInfoHandle, BOOL, WINAPI, (HGESTUREINFO));
SOFT_LINK_LIBRARY(Uxtheme);
SOFT_LINK_OPTIONAL(Uxtheme, BeginPanningFeedback, BOOL, WINAPI, (HWND));
SOFT_LINK_OPTIONAL(Uxtheme, EndPanningFeedback, BOOL, WINAPI, (HWND, BOOL));
SOFT_LINK_OPTIONAL(Uxtheme, UpdatePanningFeedback, BOOL, WINAPI, (HWND, LONG, LONG, BOOL));

aroben's avatar
aroben committed
167
using namespace WebCore;
168
using namespace std;
169
using JSC::JSLock;
weinig's avatar
weinig committed
170

171
static HMODULE accessibilityLib;
172
static HashSet<WebView*> pendingDeleteBackingStoreSet;
173

174
175
176
static String osVersion();
static String webKitVersion();

177
178
179
180
181
WebView* kit(Page* page)
{
    return page ? static_cast<WebChromeClient*>(page->chrome()->client())->webView() : 0;
}

weinig's avatar
weinig committed
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
class PreferencesChangedOrRemovedObserver : public IWebNotificationObserver {
public:
    static PreferencesChangedOrRemovedObserver* sharedInstance();

private:
    PreferencesChangedOrRemovedObserver() {}
    ~PreferencesChangedOrRemovedObserver() {}

    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void**) { return E_FAIL; }
    virtual ULONG STDMETHODCALLTYPE AddRef(void) { return 0; }
    virtual ULONG STDMETHODCALLTYPE Release(void) { return 0; }

public:
    // IWebNotificationObserver
    virtual HRESULT STDMETHODCALLTYPE onNotify( 
        /* [in] */ IWebNotification* notification);

private:
    HRESULT notifyPreferencesChanged(WebCacheModel);
    HRESULT notifyPreferencesRemoved(WebCacheModel);
};

PreferencesChangedOrRemovedObserver* PreferencesChangedOrRemovedObserver::sharedInstance()
{
    static PreferencesChangedOrRemovedObserver* shared = new PreferencesChangedOrRemovedObserver;
    return shared;
}

HRESULT PreferencesChangedOrRemovedObserver::onNotify(IWebNotification* notification)
{
    HRESULT hr = S_OK;

    COMPtr<IUnknown> unkPrefs;
215
    hr = notification->getObject(&unkPrefs);
weinig's avatar
weinig committed
216
217
218
219
    if (FAILED(hr))
        return hr;

    COMPtr<IWebPreferences> preferences(Query, unkPrefs);
darin@apple.com's avatar
darin@apple.com committed
220
    if (!preferences)
weinig's avatar
weinig committed
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
        return E_NOINTERFACE;

    WebCacheModel cacheModel;
    hr = preferences->cacheModel(&cacheModel);
    if (FAILED(hr))
        return hr;

    BSTR nameBSTR;
    hr = notification->name(&nameBSTR);
    if (FAILED(hr))
        return hr;
    BString name;
    name.adoptBSTR(nameBSTR);

    if (wcscmp(name, WebPreferences::webPreferencesChangedNotification()) == 0)
        return notifyPreferencesChanged(cacheModel);

    if (wcscmp(name, WebPreferences::webPreferencesRemovedNotification()) == 0)
        return notifyPreferencesRemoved(cacheModel);

    ASSERT_NOT_REACHED();
    return E_FAIL;
}

HRESULT PreferencesChangedOrRemovedObserver::notifyPreferencesChanged(WebCacheModel cacheModel)
{
    HRESULT hr = S_OK;

sfalken@apple.com's avatar
sfalken@apple.com committed
249
    if (!WebView::didSetCacheModel() || cacheModel > WebView::cacheModel())
weinig's avatar
weinig committed
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
        WebView::setCacheModel(cacheModel);
    else if (cacheModel < WebView::cacheModel()) {
        WebCacheModel sharedPreferencesCacheModel;
        hr = WebPreferences::sharedStandardPreferences()->cacheModel(&sharedPreferencesCacheModel);
        if (FAILED(hr))
            return hr;
        WebView::setCacheModel(max(sharedPreferencesCacheModel, WebView::maxCacheModelInAnyInstance()));
    }

    return hr;
}

HRESULT PreferencesChangedOrRemovedObserver::notifyPreferencesRemoved(WebCacheModel cacheModel)
{
    HRESULT hr = S_OK;

    if (cacheModel == WebView::cacheModel()) {
        WebCacheModel sharedPreferencesCacheModel;
        hr = WebPreferences::sharedStandardPreferences()->cacheModel(&sharedPreferencesCacheModel);
        if (FAILED(hr))
            return hr;
        WebView::setCacheModel(max(sharedPreferencesCacheModel, WebView::maxCacheModelInAnyInstance()));
    }

    return hr;
}

aroben's avatar
aroben committed
277
278
279
280

const LPCWSTR kWebViewWindowClassName = L"WebViewWindowClass";

const int WM_XP_THEMECHANGED = 0x031A;
281
const int WM_VISTA_MOUSEHWHEEL = 0x020E;
aroben's avatar
aroben committed
282

283
284
static const int maxToolTipWidth = 250;

285
286
static const int delayBeforeDeletingBackingStoreMsec = 5000;

aroben's avatar
aroben committed
287
288
static ATOM registerWebView();

weinig's avatar
weinig committed
289
290
291
292
static void initializeStaticObservers();

static HRESULT updateSharedSettingsFromPreferencesIfNeeded(IWebPreferences*);

aroben's avatar
aroben committed
293
294
295
296
297
HRESULT createMatchEnumerator(Vector<IntRect>* rects, IEnumTextMatches** matches);

static bool continuousSpellCheckingEnabled;
static bool grammarCheckingEnabled;

weinig's avatar
weinig committed
298
299
300
static bool s_didSetCacheModel;
static WebCacheModel s_cacheModel = WebCacheModelDocumentViewer;

301
302
enum {
    UpdateActiveStateTimer = 1,
303
    DeleteBackingStoreTimer = 2,
304
305
};

aroben's avatar
aroben committed
306
307
308
309
310
// WebView ----------------------------------------------------------------

bool WebView::s_allowSiteSpecificHacks = false;

WebView::WebView()
311
    : m_refCount(0)
312
313
314
#if !ASSERT_DISABLED
    , m_deletionHasBegun(false)
#endif
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
    , m_hostWindow(0)
    , m_viewWindow(0)
    , m_mainFrame(0)
    , m_page(0)
    , m_hasCustomDropTarget(false)
    , m_useBackForwardList(true)
    , m_userAgentOverridden(false)
    , m_zoomMultiplier(1.0f)
    , m_mouseActivated(false)
    , m_dragData(0)
    , m_currentCharacterCode(0)
    , m_isBeingDestroyed(false)
    , m_paintCount(0)
    , m_hasSpellCheckerDocumentTag(false)
    , m_smartInsertDeleteEnabled(false)
    , m_didClose(false)
    , m_inIMEComposition(0)
    , m_toolTipHwnd(0)
    , m_closeWindowTimer(this, &WebView::closeWindowTimerFired)
    , m_topLevelParent(0)
    , m_deleteBackingStoreTimerActive(false)
    , m_transparent(false)
    , m_selectTrailingWhitespaceEnabled(false)
    , m_lastPanX(0)
    , m_lastPanY(0)
    , m_xOverpan(0)
    , m_yOverpan(0)
342
#if USE(ACCELERATED_COMPOSITING)
343
    , m_isAcceleratedCompositing(false)
344
#endif
345
    , m_nextDisplayIsSynchronous(false)
aroben's avatar
aroben committed
346
{
347
    JSC::initializeThreading();
348
    WTF::initializeMainThread();
ap@webkit.org's avatar
ap@webkit.org committed
349

aroben's avatar
aroben committed
350
351
352
353
    m_backingStoreSize.cx = m_backingStoreSize.cy = 0;

    CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER, IID_IDropTargetHelper,(void**)&m_dropTargetHelper);

weinig's avatar
weinig committed
354
355
356
357
358
359
360
361
    initializeStaticObservers();

    WebPreferences* sharedPreferences = WebPreferences::sharedStandardPreferences();
    BOOL enabled;
    if (SUCCEEDED(sharedPreferences->continuousSpellCheckingEnabled(&enabled)))
        continuousSpellCheckingEnabled = !!enabled;
    if (SUCCEEDED(sharedPreferences->grammarCheckingEnabled(&enabled)))
        grammarCheckingEnabled = !!enabled;
aroben's avatar
aroben committed
362
363
364

    WebViewCount++;
    gClassCount++;
365
    gClassNameCount.add("WebView");
aroben's avatar
aroben committed
366
367
368
369
370
371
}

WebView::~WebView()
{
    deleteBackingStore();

372
373
374
375
    // the tooltip window needs to be explicitly destroyed since it isn't a WS_CHILD
    if (::IsWindow(m_toolTipHwnd))
        ::DestroyWindow(m_toolTipHwnd);

weinig's avatar
weinig committed
376
377
    ASSERT(!m_page);
    ASSERT(!m_preferences);
378
    ASSERT(!m_viewWindow);
aroben's avatar
aroben committed
379
380
381

    WebViewCount--;
    gClassCount--;
382
    gClassNameCount.remove("WebView");
aroben's avatar
aroben committed
383
384
385
386
387
388
389
390
391
}

WebView* WebView::createInstance()
{
    WebView* instance = new WebView();
    instance->AddRef();
    return instance;
}

weinig's avatar
weinig committed
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
void initializeStaticObservers()
{
    static bool initialized;
    if (initialized)
        return;
    initialized = true;

    IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
    notifyCenter->addObserver(PreferencesChangedOrRemovedObserver::sharedInstance(), WebPreferences::webPreferencesChangedNotification(), 0);
    notifyCenter->addObserver(PreferencesChangedOrRemovedObserver::sharedInstance(), WebPreferences::webPreferencesRemovedNotification(), 0);
}

static HashSet<WebView*>& allWebViewsSet()
{
    static HashSet<WebView*> allWebViewsSet;
    return allWebViewsSet;
}

void WebView::addToAllWebViewsSet()
{
    allWebViewsSet().add(this);
}

void WebView::removeFromAllWebViewsSet()
{
    allWebViewsSet().remove(this);
}

void WebView::setCacheModel(WebCacheModel cacheModel)
{
422
#if USE(CFNETWORK)
weinig's avatar
weinig committed
423
424
425
    if (s_didSetCacheModel && cacheModel == s_cacheModel)
        return;

mitz@apple.com's avatar
mitz@apple.com committed
426
    RetainPtr<CFURLCacheRef> cfurlCache(AdoptCF, CFURLCacheCopySharedURLCache());
427
    RetainPtr<CFStringRef> cfurlCacheDirectory(AdoptCF, wkCopyFoundationCacheDirectory());
weinig's avatar
weinig committed
428
429
430
431
432
433
434
435
436
437
438
    if (!cfurlCacheDirectory)
        cfurlCacheDirectory.adoptCF(WebCore::localUserSpecificStorageDirectory().createCFString());

    // As a fudge factor, use 1000 instead of 1024, in case the reported byte 
    // count doesn't align exactly to a megabyte boundary.
    unsigned long long memSize = WebMemorySize() / 1024 / 1000;
    unsigned long long diskFreeSize = WebVolumeFreeSize(cfurlCacheDirectory.get()) / 1024 / 1000;

    unsigned cacheTotalCapacity = 0;
    unsigned cacheMinDeadCapacity = 0;
    unsigned cacheMaxDeadCapacity = 0;
mitz@apple.com's avatar
mitz@apple.com committed
439
    double deadDecodedDataDeletionInterval = 0;
weinig's avatar
weinig committed
440
441
442
443
444
445
446
447
448
449
450
451

    unsigned pageCacheCapacity = 0;

    CFIndex cfurlCacheMemoryCapacity = 0;
    CFIndex cfurlCacheDiskCapacity = 0;

    switch (cacheModel) {
    case WebCacheModelDocumentViewer: {
        // Page cache capacity (in pages)
        pageCacheCapacity = 0;

        // Object cache capacities (in bytes)
452
        if (memSize >= 2048)
453
            cacheTotalCapacity = 96 * 1024 * 1024;
weinig's avatar
weinig committed
454
455
        else if (memSize >= 1536)
            cacheTotalCapacity = 64 * 1024 * 1024;
456
        else if (memSize >= 1024)
weinig's avatar
weinig committed
457
            cacheTotalCapacity = 32 * 1024 * 1024;
458
        else if (memSize >= 512)
weinig's avatar
weinig committed
459
460
461
462
463
464
465
466
467
            cacheTotalCapacity = 16 * 1024 * 1024; 

        cacheMinDeadCapacity = 0;
        cacheMaxDeadCapacity = 0;

        // Foundation memory cache capacity (in bytes)
        cfurlCacheMemoryCapacity = 0;

        // Foundation disk cache capacity (in bytes)
468
        cfurlCacheDiskCapacity = CFURLCacheDiskCapacity(cfurlCache.get());
weinig's avatar
weinig committed
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483

        break;
    }
    case WebCacheModelDocumentBrowser: {
        // Page cache capacity (in pages)
        if (memSize >= 1024)
            pageCacheCapacity = 3;
        else if (memSize >= 512)
            pageCacheCapacity = 2;
        else if (memSize >= 256)
            pageCacheCapacity = 1;
        else
            pageCacheCapacity = 0;

        // Object cache capacities (in bytes)
484
        if (memSize >= 2048)
485
            cacheTotalCapacity = 96 * 1024 * 1024;
weinig's avatar
weinig committed
486
487
        else if (memSize >= 1536)
            cacheTotalCapacity = 64 * 1024 * 1024;
488
        else if (memSize >= 1024)
weinig's avatar
weinig committed
489
            cacheTotalCapacity = 32 * 1024 * 1024;
490
        else if (memSize >= 512)
weinig's avatar
weinig committed
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
            cacheTotalCapacity = 16 * 1024 * 1024; 

        cacheMinDeadCapacity = cacheTotalCapacity / 8;
        cacheMaxDeadCapacity = cacheTotalCapacity / 4;

        // Foundation memory cache capacity (in bytes)
        if (memSize >= 2048)
            cfurlCacheMemoryCapacity = 4 * 1024 * 1024;
        else if (memSize >= 1024)
            cfurlCacheMemoryCapacity = 2 * 1024 * 1024;
        else if (memSize >= 512)
            cfurlCacheMemoryCapacity = 1 * 1024 * 1024;
        else
            cfurlCacheMemoryCapacity =      512 * 1024; 

        // Foundation disk cache capacity (in bytes)
        if (diskFreeSize >= 16384)
            cfurlCacheDiskCapacity = 50 * 1024 * 1024;
        else if (diskFreeSize >= 8192)
            cfurlCacheDiskCapacity = 40 * 1024 * 1024;
        else if (diskFreeSize >= 4096)
            cfurlCacheDiskCapacity = 30 * 1024 * 1024;
        else
            cfurlCacheDiskCapacity = 20 * 1024 * 1024;

        break;
    }
    case WebCacheModelPrimaryWebBrowser: {
        // Page cache capacity (in pages)
        // (Research indicates that value / page drops substantially after 3 pages.)
521
        if (memSize >= 2048)
weinig's avatar
weinig committed
522
523
524
525
526
527
528
529
530
531
532
533
534
535
            pageCacheCapacity = 5;
        else if (memSize >= 1024)
            pageCacheCapacity = 4;
        else if (memSize >= 512)
            pageCacheCapacity = 3;
        else if (memSize >= 256)
            pageCacheCapacity = 2;
        else
            pageCacheCapacity = 1;

        // Object cache capacities (in bytes)
        // (Testing indicates that value / MB depends heavily on content and
        // browsing pattern. Even growth above 128MB can have substantial 
        // value / MB for some content / browsing patterns.)
536
        if (memSize >= 2048)
537
            cacheTotalCapacity = 128 * 1024 * 1024;
weinig's avatar
weinig committed
538
        else if (memSize >= 1536)
539
            cacheTotalCapacity = 96 * 1024 * 1024;
weinig's avatar
weinig committed
540
541
        else if (memSize >= 1024)
            cacheTotalCapacity = 64 * 1024 * 1024;
542
        else if (memSize >= 512)
weinig's avatar
weinig committed
543
544
545
546
547
548
549
550
551
            cacheTotalCapacity = 32 * 1024 * 1024; 

        cacheMinDeadCapacity = cacheTotalCapacity / 4;
        cacheMaxDeadCapacity = cacheTotalCapacity / 2;

        // This code is here to avoid a PLT regression. We can remove it if we
        // can prove that the overall system gain would justify the regression.
        cacheMaxDeadCapacity = max(24u, cacheMaxDeadCapacity);

mitz@apple.com's avatar
mitz@apple.com committed
552
553
        deadDecodedDataDeletionInterval = 60;

weinig's avatar
weinig committed
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
        // Foundation memory cache capacity (in bytes)
        // (These values are small because WebCore does most caching itself.)
        if (memSize >= 1024)
            cfurlCacheMemoryCapacity = 4 * 1024 * 1024;
        else if (memSize >= 512)
            cfurlCacheMemoryCapacity = 2 * 1024 * 1024;
        else if (memSize >= 256)
            cfurlCacheMemoryCapacity = 1 * 1024 * 1024;
        else
            cfurlCacheMemoryCapacity =      512 * 1024; 

        // Foundation disk cache capacity (in bytes)
        if (diskFreeSize >= 16384)
            cfurlCacheDiskCapacity = 175 * 1024 * 1024;
        else if (diskFreeSize >= 8192)
            cfurlCacheDiskCapacity = 150 * 1024 * 1024;
        else if (diskFreeSize >= 4096)
            cfurlCacheDiskCapacity = 125 * 1024 * 1024;
        else if (diskFreeSize >= 2048)
            cfurlCacheDiskCapacity = 100 * 1024 * 1024;
        else if (diskFreeSize >= 1024)
            cfurlCacheDiskCapacity = 75 * 1024 * 1024;
        else
            cfurlCacheDiskCapacity = 50 * 1024 * 1024;

        break;
    }
    default:
        ASSERT_NOT_REACHED();
583
    }
weinig's avatar
weinig committed
584
585

    // Don't shrink a big disk cache, since that would cause churn.
586
    cfurlCacheDiskCapacity = max(cfurlCacheDiskCapacity, CFURLCacheDiskCapacity(cfurlCache.get()));
weinig's avatar
weinig committed
587
588

    cache()->setCapacities(cacheMinDeadCapacity, cacheMaxDeadCapacity, cacheTotalCapacity);
mitz@apple.com's avatar
mitz@apple.com committed
589
    cache()->setDeadDecodedDataDeletionInterval(deadDecodedDataDeletionInterval);
weinig's avatar
weinig committed
590
591
    pageCache()->setCapacity(pageCacheCapacity);

592
593
    CFURLCacheSetMemoryCapacity(cfurlCache.get(), cfurlCacheMemoryCapacity);
    CFURLCacheSetDiskCapacity(cfurlCache.get(), cfurlCacheDiskCapacity);
weinig's avatar
weinig committed
594
595
596
597

    s_didSetCacheModel = true;
    s_cacheModel = cacheModel;
    return;
598
#endif
weinig's avatar
weinig committed
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
}

WebCacheModel WebView::cacheModel()
{
    return s_cacheModel;
}

bool WebView::didSetCacheModel()
{
    return s_didSetCacheModel;
}

WebCacheModel WebView::maxCacheModelInAnyInstance()
{
    WebCacheModel cacheModel = WebCacheModelDocumentViewer;

    HashSet<WebView*>::iterator end = allWebViewsSet().end();
    for (HashSet<WebView*>::iterator it = allWebViewsSet().begin(); it != end; ++it) {
        COMPtr<IWebPreferences> pref;
618
        if (FAILED((*it)->preferences(&pref)))
weinig's avatar
weinig committed
619
620
621
622
623
624
625
626
627
628
629
            continue;
        WebCacheModel prefCacheModel = WebCacheModelDocumentViewer;
        if (FAILED(pref->cacheModel(&prefCacheModel)))
            continue;

        cacheModel = max(cacheModel, prefCacheModel);
    }

    return cacheModel;
}

mitz@apple.com's avatar
mitz@apple.com committed
630
HRESULT STDMETHODCALLTYPE WebView::close()
aroben's avatar
aroben committed
631
{
aroben's avatar
aroben committed
632
    if (m_didClose)
mitz@apple.com's avatar
mitz@apple.com committed
633
        return S_OK;
aroben's avatar
aroben committed
634
635
636

    m_didClose = true;

637
638
639
640
#if USE(ACCELERATED_COMPOSITING)
    setAcceleratedCompositing(false);
#endif

641
642
    WebNotificationCenter::defaultCenterInternal()->postNotificationName(_bstr_t(WebViewWillCloseNotification).GetBSTR(), static_cast<IWebView*>(this), 0);

sfalken@apple.com's avatar
sfalken@apple.com committed
643
644
    if (m_uiDelegatePrivate)
        m_uiDelegatePrivate->webViewClosing(this);
645

weinig's avatar
weinig committed
646
647
    removeFromAllWebViewsSet();

648
649
650
651
    if (m_page) {
        if (Frame* frame = m_page->mainFrame())
            frame->loader()->detachFromParent();
    }
ggaren's avatar
ggaren committed
652

653
654
655
656
657
    if (m_mouseOutTracker) {
        m_mouseOutTracker->dwFlags = TME_CANCEL;
        ::TrackMouseEvent(m_mouseOutTracker.get());
        m_mouseOutTracker.set(0);
    }
658
    
659
660
661
662
663
664
665
666
667
668
669
670
    revokeDragDrop();

    if (m_viewWindow) {
        // We can't check IsWindow(m_viewWindow) here, because that will return true even while
        // we're already handling WM_DESTROY. So we check !isBeingDestroyed() instead.
        if (!isBeingDestroyed())
            DestroyWindow(m_viewWindow);
        // Either we just destroyed m_viewWindow, or it's in the process of being destroyed. Either
        // way, we clear it out to make sure we don't try to use it later.
        m_viewWindow = 0;
    }

ggaren's avatar
ggaren committed
671
672
673
674
675
676
    setHostWindow(0);

    setDownloadDelegate(0);
    setEditingDelegate(0);
    setFrameLoadDelegate(0);
    setFrameLoadDelegatePrivate(0);
677
    setHistoryDelegate(0);
ggaren's avatar
ggaren committed
678
679
680
681
    setPolicyDelegate(0);
    setResourceLoadDelegate(0);
    setUIDelegate(0);
    setFormDelegate(0);
682
    setPluginHalterDelegate(0);
ggaren's avatar
ggaren committed
683

684
685
686
    if (m_webInspector)
        m_webInspector->webViewClosed();

ggaren's avatar
ggaren committed
687
688
689
    delete m_page;
    m_page = 0;

beidson's avatar
beidson committed
690
    registerForIconNotification(false);
aroben's avatar
aroben committed
691
    IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
weinig's avatar
weinig committed
692
693
    notifyCenter->removeObserver(this, WebPreferences::webPreferencesChangedNotification(), static_cast<IWebPreferences*>(m_preferences.get()));

694
695
696
697
698
699
700
701
702
703
704
705
    if (COMPtr<WebPreferences> preferences = m_preferences) {
        BSTR identifier = 0;
        preferences->identifier(&identifier);

        m_preferences = 0;
        preferences->didRemoveFromWebView();
        // Make sure we release the reference, since WebPreferences::removeReferenceForIdentifier will check for last reference to WebPreferences
        preferences = 0;
        if (identifier) {
            WebPreferences::removeReferenceForIdentifier(identifier);
            SysFreeString(identifier);
        }
706
    }
aroben's avatar
aroben committed
707
708

    deleteBackingStore();
mitz@apple.com's avatar
mitz@apple.com committed
709
    return S_OK;
aroben's avatar
aroben committed
710
711
}

hyatt@apple.com's avatar
hyatt@apple.com committed
712
void WebView::repaint(const WebCore::IntRect& windowRect, bool contentChanged, bool immediate, bool repaintContentOnly)
713
{
714
715
716
717
718
#if USE(ACCELERATED_COMPOSITING)
    if (isAcceleratedCompositing())
        setRootLayerNeedsDisplay();
#endif

hyatt@apple.com's avatar
hyatt@apple.com committed
719
720
721
722
    if (!repaintContentOnly) {
        RECT rect = windowRect;
        ::InvalidateRect(m_viewWindow, &rect, false);
    }
723
724
    if (contentChanged)
        addToDirtyRegion(windowRect);
hyatt@apple.com's avatar
hyatt@apple.com committed
725
726
    if (immediate) {
        if (repaintContentOnly)
hyatt@apple.com's avatar
hyatt@apple.com committed
727
            updateBackingStore(core(topLevelFrame())->view());
hyatt@apple.com's avatar
hyatt@apple.com committed
728
729
730
        else
            ::UpdateWindow(m_viewWindow);
    }
731
732
}

aroben's avatar
aroben committed
733
734
void WebView::deleteBackingStore()
{
735
736
    pendingDeleteBackingStoreSet.remove(this);

737
738
739
740
    if (m_deleteBackingStoreTimerActive) {
        KillTimer(m_viewWindow, DeleteBackingStoreTimer);
        m_deleteBackingStoreTimerActive = false;
    }
darin's avatar
darin committed
741
742
    m_backingStoreBitmap.clear();
    m_backingStoreDirtyRegion.clear();
743
#if USE(ACCELERATED_COMPOSITING)
744
745
    if (m_layerRenderer)
        m_layerRenderer->setBackingStoreDirty(false);
746
#endif
aroben's avatar
aroben committed
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761

    m_backingStoreSize.cx = m_backingStoreSize.cy = 0;
}

bool WebView::ensureBackingStore()
{
    RECT windowRect;
    ::GetClientRect(m_viewWindow, &windowRect);
    LONG width = windowRect.right - windowRect.left;
    LONG height = windowRect.bottom - windowRect.top;
    if (width > 0 && height > 0 && (width != m_backingStoreSize.cx || height != m_backingStoreSize.cy)) {
        deleteBackingStore();

        m_backingStoreSize.cx = width;
        m_backingStoreSize.cy = height;
bfulgham@webkit.org's avatar
bfulgham@webkit.org committed
762
        BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(IntSize(m_backingStoreSize));
aroben's avatar
aroben committed
763
764

        void* pixels = NULL;
765
        m_backingStoreBitmap = RefCountedHBITMAP::create(::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0));
aroben's avatar
aroben committed
766
767
768
769
770
771
772
773
        return true;
    }

    return false;
}

void WebView::addToDirtyRegion(const IntRect& dirtyRect)
{
774
775
776
777
    // FIXME: We want an assert here saying that the dirtyRect is inside the clienRect,
    // but it was being hit during our layout tests, and is being investigated in
    // http://webkit.org/b/29350.

aroben's avatar
aroben committed
778
779
780
781
782
783
784
785
786
787
788
    HRGN newRegion = ::CreateRectRgn(dirtyRect.x(), dirtyRect.y(),
                                     dirtyRect.right(), dirtyRect.bottom());
    addToDirtyRegion(newRegion);
}

void WebView::addToDirtyRegion(HRGN newRegion)
{
    LOCAL_GDI_COUNTER(0, __FUNCTION__);

    if (m_backingStoreDirtyRegion) {
        HRGN combinedRegion = ::CreateRectRgn(0,0,0,0);
789
        ::CombineRgn(combinedRegion, m_backingStoreDirtyRegion->handle(), newRegion, RGN_OR);
aroben's avatar
aroben committed
790
        ::DeleteObject(newRegion);
791
        m_backingStoreDirtyRegion = RefCountedHRGN::create(combinedRegion);
aroben's avatar
aroben committed
792
    } else
793
        m_backingStoreDirtyRegion = RefCountedHRGN::create(newRegion);
794

795
#if USE(ACCELERATED_COMPOSITING)
796
797
    if (m_layerRenderer)
        m_layerRenderer->setBackingStoreDirty(true);
798
#endif
799

sfalken@apple.com's avatar
sfalken@apple.com committed
800
801
    if (m_uiDelegatePrivate)
        m_uiDelegatePrivate->webViewDidInvalidate(this);
aroben's avatar
aroben committed
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
}

void WebView::scrollBackingStore(FrameView* frameView, int dx, int dy, const IntRect& scrollViewRect, const IntRect& clipRect)
{
    LOCAL_GDI_COUNTER(0, __FUNCTION__);

    // If there's no backing store we don't need to update it
    if (!m_backingStoreBitmap) {
        if (m_uiDelegatePrivate)
            m_uiDelegatePrivate->webViewScrolled(this);

        return;
    }

    // Make a region to hold the invalidated scroll area.
    HRGN updateRegion = ::CreateRectRgn(0, 0, 0, 0);

    // Collect our device context info and select the bitmap to scroll.
    HDC windowDC = ::GetDC(m_viewWindow);
    HDC bitmapDC = ::CreateCompatibleDC(windowDC);
822
    ::SelectObject(bitmapDC, m_backingStoreBitmap->handle());
aroben's avatar
aroben committed
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
    
    // Scroll the bitmap.
    RECT scrollRectWin(scrollViewRect);
    RECT clipRectWin(clipRect);
    ::ScrollDC(bitmapDC, dx, dy, &scrollRectWin, &clipRectWin, updateRegion, 0);
    RECT regionBox;
    ::GetRgnBox(updateRegion, &regionBox);

    // Flush.
    GdiFlush();

    // Add the dirty region to the backing store's dirty region.
    addToDirtyRegion(updateRegion);

    if (m_uiDelegatePrivate)
        m_uiDelegatePrivate->webViewScrolled(this);

    // Update the backing store.
    updateBackingStore(frameView, bitmapDC, false);

    // Clean up.
    ::DeleteDC(bitmapDC);
    ::ReleaseDC(m_viewWindow, windowDC);
}

848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
// This emulates the Mac smarts for painting rects intelligently.  This is very
// important for us, since we double buffer based off dirty rects.
static void getUpdateRects(HRGN region, const IntRect& dirtyRect, Vector<IntRect>& rects)
{
    ASSERT_ARG(region, region);

    const int cRectThreshold = 10;
    const float cWastedSpaceThreshold = 0.75f;

    rects.clear();

    DWORD regionDataSize = GetRegionData(region, sizeof(RGNDATA), NULL);
    if (!regionDataSize) {
        rects.append(dirtyRect);
        return;
    }

865
866
    Vector<unsigned char> buffer(regionDataSize);
    RGNDATA* regionData = reinterpret_cast<RGNDATA*>(buffer.data());
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
    GetRegionData(region, regionDataSize, regionData);
    if (regionData->rdh.nCount > cRectThreshold) {
        rects.append(dirtyRect);
        return;
    }

    double singlePixels = 0.0;
    unsigned i;
    RECT* rect;
    for (i = 0, rect = reinterpret_cast<RECT*>(regionData->Buffer); i < regionData->rdh.nCount; i++, rect++)
        singlePixels += (rect->right - rect->left) * (rect->bottom - rect->top);

    double unionPixels = dirtyRect.width() * dirtyRect.height();
    double wastedSpace = 1.0 - (singlePixels / unionPixels);
    if (wastedSpace <= cWastedSpaceThreshold) {
        rects.append(dirtyRect);
        return;
    }

    for (i = 0, rect = reinterpret_cast<RECT*>(regionData->Buffer); i < regionData->rdh.nCount; i++, rect++)
        rects.append(*rect);
}

890
void WebView::updateBackingStore(FrameView* frameView, HDC dc, bool backingStoreCompletelyDirty, WindowsToPaint windowsToPaint)
aroben's avatar
aroben committed
891
892
893
894
895
896
897
898
{
    LOCAL_GDI_COUNTER(0, __FUNCTION__);

    HDC windowDC = 0;
    HDC bitmapDC = dc;
    if (!dc) {
        windowDC = ::GetDC(m_viewWindow);
        bitmapDC = ::CreateCompatibleDC(windowDC);
899
        ::SelectObject(bitmapDC, m_backingStoreBitmap->handle());
aroben's avatar
aroben committed
900
901
902
903
    }

    if (m_backingStoreBitmap && (m_backingStoreDirtyRegion || backingStoreCompletelyDirty)) {
        // Do a layout first so that everything we render to the backing store is always current.
904
905
906
        if (Frame* coreFrame = core(m_mainFrame))
            if (FrameView* view = coreFrame->view())
                view->layoutIfNeededRecursive();
aroben's avatar
aroben committed
907

908
        Vector<IntRect> paintRects;
909
        if (!backingStoreCompletelyDirty && m_backingStoreDirtyRegion) {
910
            RECT regionBox;
911
912
            ::GetRgnBox(m_backingStoreDirtyRegion->handle(), &regionBox);
            getUpdateRects(m_backingStoreDirtyRegion->handle(), regionBox, paintRects);
913
914
915
916
917
        } else {
            RECT clientRect;
            ::GetClientRect(m_viewWindow, &clientRect);
            paintRects.append(clientRect);
        }
aroben's avatar
aroben committed
918

919
        for (unsigned i = 0; i < paintRects.size(); ++i)
920
            paintIntoBackingStore(frameView, bitmapDC, paintRects[i], windowsToPaint);
aroben's avatar
aroben committed
921

sfalken@apple.com's avatar
sfalken@apple.com committed
922
923
        if (m_uiDelegatePrivate)
            m_uiDelegatePrivate->webViewPainted(this);
924

darin's avatar
darin committed
925
        m_backingStoreDirtyRegion.clear();
926
#if USE(ACCELERATED_COMPOSITING)
927
928
        if (m_layerRenderer)
            m_layerRenderer->setBackingStoreDirty(false);
929
#endif
aroben's avatar
aroben committed
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
    }

    if (!dc) {
        ::DeleteDC(bitmapDC);
        ::ReleaseDC(m_viewWindow, windowDC);
    }

    GdiFlush();
}

void WebView::paint(HDC dc, LPARAM options)
{
    LOCAL_GDI_COUNTER(0, __FUNCTION__);

    Frame* coreFrame = core(m_mainFrame);
    if (!coreFrame)
        return;
    FrameView* frameView = coreFrame->view();

    RECT rcPaint;
    HDC hdc;
darin's avatar
darin committed
951
    OwnPtr<HRGN> region;
aroben's avatar
aroben committed
952
953
    int regionType = NULLREGION;
    PAINTSTRUCT ps;
954
    WindowsToPaint windowsToPaint;
aroben's avatar
aroben committed
955
    if (!dc) {
darin's avatar
darin committed
956
957
        region.set(CreateRectRgn(0,0,0,0));
        regionType = GetUpdateRgn(m_viewWindow, region.get(), false);
aroben's avatar
aroben committed
958
959
        hdc = BeginPaint(m_viewWindow, &ps);
        rcPaint = ps.rcPaint;
960
961
962
        // We're painting to the screen, and our child windows can handle
        // painting themselves to the screen.
        windowsToPaint = PaintWebViewOnly;
aroben's avatar
aroben committed
963
964
965
966
967
    } else {
        hdc = dc;
        ::GetClientRect(m_viewWindow, &rcPaint);
        if (options & PRF_ERASEBKGND)
            ::FillRect(hdc, &rcPaint, (HBRUSH)GetStockObject(WHITE_BRUSH));
968
969
970
        // Since we aren't painting to the screen, we want to paint all our
        // children into the HDC.
        windowsToPaint = PaintWebViewAndChildren;
aroben's avatar
aroben committed
971
972
    }

973
974
975
976
977
978
979
980
    if (::IsRectEmpty(&rcPaint)) {
        if (!dc)
            EndPaint(m_viewWindow, &ps);
        return;
    }

    m_paintCount++;

aroben's avatar
aroben committed
981
982
    HDC bitmapDC = ::CreateCompatibleDC(hdc);
    bool backingStoreCompletelyDirty = ensureBackingStore();
983
    ::SelectObject(bitmapDC, m_backingStoreBitmap->handle());
aroben's avatar
aroben committed
984
985

    // Update our backing store if needed.
986
    updateBackingStore(frameView, bitmapDC, backingStoreCompletelyDirty, windowsToPaint);
aroben's avatar
aroben committed
987

988
989
990
991
992
993
994
995
996
997
998
999
#if USE(ACCELERATED_COMPOSITING)
    if (!isAcceleratedCompositing()) {
#endif
        // Now we blit the updated backing store
        IntRect windowDirtyRect = rcPaint;
        
        // Apply the same heuristic for this update region too.
        Vector<IntRect> blitRects;
        if (region && regionType == COMPLEXREGION)
            getUpdateRects(region.get(), windowDirtyRect, blitRects);
        else
            blitRects.append(windowDirtyRect);
aroben's avatar
aroben committed
1000