Reviewed by Adam.
[WebKit-https.git] / WebKit / win / WebView.cpp
1 /*
2  * Copyright (C) 2006, 2007 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 COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "WebKitDLL.h"
28 #include "WebView.h"
29
30 #include "DOMCoreClasses.h"
31 #include "IWebNotification.h"
32 #include "WebDebugProgram.h"
33 #include "WebDocumentLoader.h"
34 #include "WebEditorClient.h"
35 #include "WebElementPropertyBag.h"
36 #include "WebFrame.h"
37 #include "WebBackForwardList.h"
38 #include "WebChromeClient.h"
39 #include "WebContextMenuClient.h"
40 #include "WebDragClient.h"
41 #include "WebInspectorClient.h"
42 #include "WebKit.h"
43 #include "WebKitStatisticsPrivate.h"
44 #include "WebMutableURLRequest.h"
45 #include "WebNotificationCenter.h"
46 #include "WebPreferences.h"
47 #pragma warning( push, 0 )
48 #include <CoreGraphics/CGContext.h>
49 #include <CFNetwork/CFHTTPCookiesPriv.h>
50 #include <WebCore/BString.h>
51 #include <WebCore/Cache.h>
52 #include <WebCore/CommandByName.h>
53 #include <WebCore/ContextMenu.h>
54 #include <WebCore/ContextMenuController.h>
55 #include <WebCore/CString.h>
56 #include <WebCore/Cursor.h>
57 #include <WebCore/Document.h>
58 #include <WebCore/DragController.h>
59 #include <WebCore/DragData.h>
60 #include <WebCore/Editor.h>
61 #include <WebCore/EventHandler.h>
62 #include <WebCore/FocusController.h>
63 #include <WebCore/FrameLoader.h>
64 #include <WebCore/FrameTree.h>
65 #include <WebCore/FrameView.h>
66 #include <WebCore/FrameWin.h>
67 #include <WebCore/GDIObjectCounter.h>
68 #include <WebCore/GraphicsContext.h>
69 #include <WebCore/HistoryItem.h>
70 #include <WebCore/HitTestResult.h>
71 #include <WebCore/IntRect.h>
72 #include <WebCore/KeyboardEvent.h>
73 #include <WebCore/MIMETypeRegistry.h>
74 #include <WebCore/NotImplemented.h>
75 #include <WebCore/Page.h>
76 #include <WebCore/PageCache.h>
77 #include <WebCore/PlatformKeyboardEvent.h>
78 #include <WebCore/PlatformMouseEvent.h>
79 #include <WebCore/PlatformWheelEvent.h>
80 #include <WebCore/PluginDatabaseWin.h>
81 #include <WebCore/PlugInInfoStore.h>
82 #include <WebCore/ProgressTracker.h>
83 #include <WebCore/ResourceHandle.h>
84 #include <WebCore/ResourceHandleClient.h>
85 #include <WebCore/SelectionController.h>
86 #include <WebCore/Settings.h>
87 #include <WebCore/TypingCommand.h>
88 #pragma warning(pop)
89 #include <JavaScriptCore/collector.h>
90 #include <JavaScriptCore/value.h>
91 #include <CFNetwork/CFURLProtocolPriv.h>
92 #include <tchar.h>
93 #include <dimm.h>
94 #include <windowsx.h>
95 #include <ShlObj.h>
96
97 using namespace WebCore;
98 using KJS::JSLock;
99 using std::min;
100
101 const LPCWSTR kWebViewWindowClassName = L"WebViewWindowClass";
102
103 const int WM_XP_THEMECHANGED = 0x031A;
104 const int WM_VISTA_MOUSEHWHEEL = 0x020E;
105
106 static const int maxToolTipWidth = 250;
107
108 static ATOM registerWebView();
109 static LRESULT CALLBACK WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
110
111 HRESULT createMatchEnumerator(Vector<IntRect>* rects, IEnumTextMatches** matches);
112
113 static bool continuousSpellCheckingEnabled;
114 static bool grammarCheckingEnabled;
115
116 // WebView ----------------------------------------------------------------
117
118 bool WebView::s_allowSiteSpecificHacks = false;
119
120 WebView::WebView()
121 : m_refCount(0)
122 , m_hostWindow(0)
123 , m_viewWindow(0)
124 , m_mainFrame(0)
125 , m_page(0)
126 , m_backingStoreBitmap(0)
127 , m_backingStoreDirtyRegion(0)
128 , m_useBackForwardList(true)
129 , m_userAgentOverridden(false)
130 , m_textSizeMultiplier(1)
131 , m_mouseActivated(false)
132 , m_dragData(0)
133 , m_currentCharacterCode(0)
134 , m_isBeingDestroyed(false)
135 , m_paintCount(0)
136 , m_hasSpellCheckerDocumentTag(false)
137 , m_smartInsertDeleteEnabled(false)
138 , m_didClose(false)
139 , m_inIMEComposition(0)
140 , m_toolTipHwnd(0)
141 , m_closeWindowTimer(this, &WebView::closeWindowTimerFired)
142 {
143     KJS::Collector::registerAsMainThread();
144
145     m_backingStoreSize.cx = m_backingStoreSize.cy = 0;
146
147     CoCreateInstance(CLSID_DragDropHelper, 0, CLSCTX_INPROC_SERVER, IID_IDropTargetHelper,(void**)&m_dropTargetHelper);
148
149     COMPtr<IWebPreferences> prefs;
150     if (SUCCEEDED(preferences(&prefs))) {
151         BOOL enabled;
152         if (SUCCEEDED(prefs->continuousSpellCheckingEnabled(&enabled)))
153             continuousSpellCheckingEnabled = !!enabled;
154         if (SUCCEEDED(prefs->grammarCheckingEnabled(&enabled)))
155             grammarCheckingEnabled = !!enabled;
156     }
157
158     WebDebugProgram::viewAdded(this);
159     WebViewCount++;
160     gClassCount++;
161 }
162
163 WebView::~WebView()
164 {
165     deleteBackingStore();
166
167     // <rdar://4958382> m_viewWindow will be destroyed when m_hostWindow is destroyed, but if
168     // setHostWindow was never called we will leak our HWND. If we still have a valid HWND at
169     // this point, we should just destroy it ourselves.
170     if (::IsWindow(m_viewWindow))
171         ::DestroyWindow(m_viewWindow);
172
173     delete m_page;
174
175     WebDebugProgram::viewRemoved(this);
176     WebViewCount--;
177     gClassCount--;
178 }
179
180 WebView* WebView::createInstance()
181 {
182     WebView* instance = new WebView();
183     instance->AddRef();
184     return instance;
185 }
186
187 void WebView::close()
188 {
189     if (m_didClose)
190         return;
191
192     m_didClose = true;
193
194     IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
195     COMPtr<IWebPreferences> prefs;
196     if (SUCCEEDED(preferences(&prefs)))
197         notifyCenter->removeObserver(this, WebPreferences::webPreferencesChangedNotification(), prefs.get());
198     prefs = 0;  // make sure we release the reference, since WebPreferences::removeReferenceForIdentifier will check for last reference to WebPreferences
199     if (m_preferences) {
200         BSTR identifier = 0;
201         if (SUCCEEDED(m_preferences->identifier(&identifier)))
202             WebPreferences::removeReferenceForIdentifier(identifier);
203         if (identifier)
204             SysFreeString(identifier);
205         m_preferences = 0;
206     }
207
208     setHostWindow(0);
209     setFrameLoadDelegate(0);
210     setFrameLoadDelegatePrivate(0);
211     setUIDelegate(0);
212     setFormDelegate(0);
213     setPolicyDelegate(0);
214
215     Frame* frame = NULL;
216     frame = m_page->mainFrame();
217     if (frame)
218         frame->loader()->detachFromParent();
219
220     delete m_page;
221     m_page = 0;
222
223     deleteBackingStore();
224 }
225
226 void WebView::deleteBackingStore()
227 {
228     if (m_backingStoreBitmap) {
229         ::DeleteObject(m_backingStoreBitmap);
230         m_backingStoreBitmap = 0;
231     }
232
233     if (m_backingStoreDirtyRegion) {
234         ::DeleteObject(m_backingStoreDirtyRegion);
235         m_backingStoreDirtyRegion = 0;
236     }
237
238     m_backingStoreSize.cx = m_backingStoreSize.cy = 0;
239 }
240
241 bool WebView::ensureBackingStore()
242 {
243     RECT windowRect;
244     ::GetClientRect(m_viewWindow, &windowRect);
245     LONG width = windowRect.right - windowRect.left;
246     LONG height = windowRect.bottom - windowRect.top;
247     if (width > 0 && height > 0 && (width != m_backingStoreSize.cx || height != m_backingStoreSize.cy)) {
248         deleteBackingStore();
249
250         m_backingStoreSize.cx = width;
251         m_backingStoreSize.cy = height;
252         BITMAPINFO bitmapInfo;
253         bitmapInfo.bmiHeader.biSize          = sizeof(BITMAPINFOHEADER);
254         bitmapInfo.bmiHeader.biWidth         = width; 
255         bitmapInfo.bmiHeader.biHeight        = -height;
256         bitmapInfo.bmiHeader.biPlanes        = 1;
257         bitmapInfo.bmiHeader.biBitCount      = 32;
258         bitmapInfo.bmiHeader.biCompression   = BI_RGB;
259         bitmapInfo.bmiHeader.biSizeImage     = 0;
260         bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
261         bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
262         bitmapInfo.bmiHeader.biClrUsed       = 0;
263         bitmapInfo.bmiHeader.biClrImportant  = 0;
264
265         void* pixels = NULL;
266         m_backingStoreBitmap = ::CreateDIBSection(NULL, &bitmapInfo, DIB_RGB_COLORS, &pixels, NULL, 0);
267         return true;
268     }
269
270     return false;
271 }
272
273 void WebView::addToDirtyRegion(const IntRect& dirtyRect)
274 {
275     HRGN newRegion = ::CreateRectRgn(dirtyRect.x(), dirtyRect.y(),
276                                      dirtyRect.right(), dirtyRect.bottom());
277     addToDirtyRegion(newRegion);
278 }
279
280 void WebView::addToDirtyRegion(HRGN newRegion)
281 {
282     LOCAL_GDI_COUNTER(0, __FUNCTION__);
283
284     if (m_backingStoreDirtyRegion) {
285         HRGN combinedRegion = ::CreateRectRgn(0,0,0,0);
286         ::CombineRgn(combinedRegion, m_backingStoreDirtyRegion, newRegion, RGN_OR);
287         ::DeleteObject(m_backingStoreDirtyRegion);
288         ::DeleteObject(newRegion);
289         m_backingStoreDirtyRegion = combinedRegion;
290     } else
291         m_backingStoreDirtyRegion = newRegion;
292 }
293
294 void WebView::scrollBackingStore(FrameView* frameView, int dx, int dy, const IntRect& scrollViewRect, const IntRect& clipRect)
295 {
296     LOCAL_GDI_COUNTER(0, __FUNCTION__);
297
298     // If there's no backing store we don't need to update it
299     if (!m_backingStoreBitmap) {
300         if (m_uiDelegatePrivate)
301             m_uiDelegatePrivate->webViewScrolled(this);
302
303         return;
304     }
305
306     // Make a region to hold the invalidated scroll area.
307     HRGN updateRegion = ::CreateRectRgn(0, 0, 0, 0);
308
309     // Collect our device context info and select the bitmap to scroll.
310     HDC windowDC = ::GetDC(m_viewWindow);
311     HDC bitmapDC = ::CreateCompatibleDC(windowDC);
312     ::SelectObject(bitmapDC, m_backingStoreBitmap);
313     
314     // Scroll the bitmap.
315     RECT scrollRectWin(scrollViewRect);
316     RECT clipRectWin(clipRect);
317     ::ScrollDC(bitmapDC, dx, dy, &scrollRectWin, &clipRectWin, updateRegion, 0);
318     RECT regionBox;
319     ::GetRgnBox(updateRegion, &regionBox);
320
321     // Flush.
322     GdiFlush();
323
324     // Add the dirty region to the backing store's dirty region.
325     addToDirtyRegion(updateRegion);
326
327     if (m_uiDelegatePrivate)
328         m_uiDelegatePrivate->webViewScrolled(this);
329
330     // Update the backing store.
331     updateBackingStore(frameView, bitmapDC, false);
332
333     // Clean up.
334     ::DeleteDC(bitmapDC);
335     ::ReleaseDC(m_viewWindow, windowDC);
336
337 }
338
339 void WebView::updateBackingStore(FrameView* frameView, HDC dc, bool backingStoreCompletelyDirty)
340 {
341     LOCAL_GDI_COUNTER(0, __FUNCTION__);
342
343     HDC windowDC = 0;
344     HDC bitmapDC = dc;
345     if (!dc) {
346         windowDC = ::GetDC(m_viewWindow);
347         bitmapDC = ::CreateCompatibleDC(windowDC);
348         ::SelectObject(bitmapDC, m_backingStoreBitmap);
349     }
350
351     if (m_backingStoreBitmap && (m_backingStoreDirtyRegion || backingStoreCompletelyDirty)) {
352         // Do a layout first so that everything we render to the backing store is always current.
353         m_mainFrame->layoutIfNeededRecursive(0);
354
355         // This emulates the Mac smarts for painting rects intelligently.  This is
356         // very important for us, since we double buffer based off dirty rects.
357         bool useRegionBox = true;
358         const int cRectThreshold = 10;
359         const float cWastedSpaceThreshold = 0.75f;
360         RECT regionBox;
361         if (!backingStoreCompletelyDirty) {
362             ::GetRgnBox(m_backingStoreDirtyRegion, &regionBox);
363             DWORD regionDataSize = GetRegionData(m_backingStoreDirtyRegion, sizeof(RGNDATA), NULL);
364             if (regionDataSize) {
365                 RGNDATA* regionData = (RGNDATA*)malloc(regionDataSize);
366                 GetRegionData(m_backingStoreDirtyRegion, regionDataSize, regionData);
367                 if (regionData->rdh.nCount <= cRectThreshold) {
368                     double unionPixels = (regionBox.right - regionBox.left) * (regionBox.bottom - regionBox.top);
369                     double singlePixels = 0;
370                     
371                     unsigned i;
372                     RECT* rect;
373                     for (i = 0, rect = (RECT*)regionData->Buffer; i < regionData->rdh.nCount; i++, rect++)
374                         singlePixels += (rect->right - rect->left) * (rect->bottom - rect->top);
375                     double wastedSpace = 1.0 - (singlePixels / unionPixels);
376                     if (wastedSpace > cWastedSpaceThreshold) {
377                         // Paint individual rects.
378                         useRegionBox = false;
379                         for (i = 0, rect = (RECT*)regionData->Buffer; i < regionData->rdh.nCount; i++, rect++)
380                             paintIntoBackingStore(frameView, bitmapDC, rect);
381                     }
382                 }
383                 free(regionData);
384             }
385         } else
386             ::GetClientRect(m_viewWindow, &regionBox);
387
388         if (useRegionBox)
389             paintIntoBackingStore(frameView, bitmapDC, &regionBox);
390
391         if (m_backingStoreDirtyRegion) {
392             ::DeleteObject(m_backingStoreDirtyRegion);
393             m_backingStoreDirtyRegion = 0;
394         }
395     }
396
397     if (!dc) {
398         ::DeleteDC(bitmapDC);
399         ::ReleaseDC(m_viewWindow, windowDC);
400     }
401
402     GdiFlush();
403 }
404
405 void WebView::paint(HDC dc, LPARAM options)
406 {
407     LOCAL_GDI_COUNTER(0, __FUNCTION__);
408
409     Frame* coreFrame = core(m_mainFrame);
410     if (!coreFrame)
411         return;
412     FrameView* frameView = coreFrame->view();
413
414     m_paintCount++;
415
416     RECT rcPaint;
417     HDC hdc;
418     HRGN region = 0;
419     int regionType = NULLREGION;
420     PAINTSTRUCT ps;
421     if (!dc) {
422         region = CreateRectRgn(0,0,0,0);
423         regionType = GetUpdateRgn(m_viewWindow, region, false);
424         hdc = BeginPaint(m_viewWindow, &ps);
425         rcPaint = ps.rcPaint;
426     } else {
427         hdc = dc;
428         ::GetClientRect(m_viewWindow, &rcPaint);
429         if (options & PRF_ERASEBKGND)
430             ::FillRect(hdc, &rcPaint, (HBRUSH)GetStockObject(WHITE_BRUSH));
431     }
432
433     HDC bitmapDC = ::CreateCompatibleDC(hdc);
434     bool backingStoreCompletelyDirty = ensureBackingStore();
435     ::SelectObject(bitmapDC, m_backingStoreBitmap);
436
437     // Update our backing store if needed.
438     updateBackingStore(frameView, bitmapDC, backingStoreCompletelyDirty);
439
440     // Now we blit the updated backing store
441     IntRect windowDirtyRect = rcPaint;
442     
443     // Apply the same heuristic for this update region too.
444     bool useWindowDirtyRect = true;
445     if (region && regionType == COMPLEXREGION) {
446         LOCAL_GDI_COUNTER(1, __FUNCTION__" (COMPLEXREGION)");
447
448         const int cRectThreshold = 10;
449         const float cWastedSpaceThreshold = 0.75f;
450         DWORD regionDataSize = GetRegionData(region, sizeof(RGNDATA), NULL);
451         if (regionDataSize) {
452             RGNDATA* regionData = (RGNDATA*)malloc(regionDataSize);
453             GetRegionData(region, regionDataSize, regionData);
454             if (regionData->rdh.nCount <= cRectThreshold) {
455                 double unionPixels = windowDirtyRect.width() * windowDirtyRect.height();
456                 double singlePixels = 0;
457                 
458                 unsigned i;
459                 RECT* rect;
460                 for (i = 0, rect = (RECT*)regionData->Buffer; i < regionData->rdh.nCount; i++, rect++)
461                     singlePixels += (rect->right - rect->left) * (rect->bottom - rect->top);
462                 double wastedSpace = 1.0 - (singlePixels / unionPixels);
463                 if (wastedSpace > cWastedSpaceThreshold) {
464                     // Paint individual rects.
465                     useWindowDirtyRect = false;
466                     for (i = 0, rect = (RECT*)regionData->Buffer; i < regionData->rdh.nCount; i++, rect++)
467                         paintIntoWindow(bitmapDC, hdc, rect);
468                 }
469             }
470             free(regionData);
471         }
472     }
473     
474     ::DeleteObject(region);
475
476     if (useWindowDirtyRect)
477         paintIntoWindow(bitmapDC, hdc, &rcPaint);
478
479     ::DeleteDC(bitmapDC);
480
481     // Paint the gripper.
482     COMPtr<IWebUIDelegate> ui;
483     if (SUCCEEDED(uiDelegate(&ui))) {
484         COMPtr<IWebUIDelegatePrivate> uiPrivate;
485         if (SUCCEEDED(ui->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&uiPrivate))) {
486             RECT r;
487             if (SUCCEEDED(uiPrivate->webViewResizerRect(this, &r))) {
488                 LOCAL_GDI_COUNTER(2, __FUNCTION__" webViewDrawResizer delegate call");
489                 uiPrivate->webViewDrawResizer(this, hdc, (frameView->resizerOverlapsContent() ? true : false), &r);
490             }
491         }
492     }
493
494     if (!dc)
495         EndPaint(m_viewWindow, &ps);
496
497     m_paintCount--;
498 }
499
500 void WebView::paintIntoBackingStore(FrameView* frameView, HDC bitmapDC, LPRECT dirtyRect)
501 {
502     LOCAL_GDI_COUNTER(0, __FUNCTION__);
503
504 #if FLASH_BACKING_STORE_REDRAW
505     HDC dc = ::GetDC(m_viewWindow);
506     HBRUSH yellowBrush = CreateSolidBrush(RGB(255, 255, 0));
507     FillRect(dc, dirtyRect, yellowBrush);
508     DeleteObject(yellowBrush);
509     GdiFlush();
510     Sleep(50);
511     paintIntoWindow(bitmapDC, dc, dirtyRect);
512     ::ReleaseDC(m_viewWindow, dc);
513 #endif
514
515     FillRect(bitmapDC, dirtyRect, (HBRUSH)GetStockObject(WHITE_BRUSH));
516     if (frameView && frameView->frame() && frameView->frame()->renderer()) {
517         GraphicsContext gc(bitmapDC);
518         gc.save();
519         gc.clip(IntRect(*dirtyRect));
520         frameView->paint(&gc, IntRect(*dirtyRect));
521         gc.restore();
522     }
523 }
524
525 void WebView::paintIntoWindow(HDC bitmapDC, HDC windowDC, LPRECT dirtyRect)
526 {
527     LOCAL_GDI_COUNTER(0, __FUNCTION__);
528 #if FLASH_WINDOW_REDRAW
529     HBRUSH greenBrush = CreateSolidBrush(RGB(0, 255, 0));
530     FillRect(windowDC, dirtyRect, greenBrush);
531     DeleteObject(greenBrush);
532     GdiFlush();
533     Sleep(50);
534 #endif
535
536     // Blit the dirty rect from the backing store into the same position
537     // in the destination DC.
538     BitBlt(windowDC, dirtyRect->left, dirtyRect->top, dirtyRect->right - dirtyRect->left, dirtyRect->bottom - dirtyRect->top, bitmapDC,
539            dirtyRect->left, dirtyRect->top, SRCCOPY);
540 }
541
542 void WebView::frameRect(RECT* rect)
543 {
544     ::GetWindowRect(m_viewWindow, rect);
545 }
546
547 void WebView::closeWindowSoon()
548 {
549     m_closeWindowTimer.startOneShot(0);
550     AddRef();
551 }
552
553 void WebView::closeWindowTimerFired(WebCore::Timer<WebView>*)
554 {
555     closeWindow();
556     Release();
557 }
558
559 void WebView::closeWindow()
560 {
561     if (m_hasSpellCheckerDocumentTag) {
562         if (m_editingDelegate)
563             m_editingDelegate->closeSpellDocument(this);
564         m_hasSpellCheckerDocumentTag = false;
565     }
566
567     COMPtr<IWebUIDelegate> ui;
568     if (SUCCEEDED(uiDelegate(&ui)))
569         ui->webViewClose(this);
570 }
571
572 bool WebView::canHandleRequest(const WebCore::ResourceRequest& request)
573 {
574     // On the mac there's an about url protocol implementation but CFNetwork doesn't have that.
575     if (equalIgnoringCase(String(request.url().protocol()), "about"))
576         return true;
577
578     if (CFURLProtocolCanHandleRequest(request.cfURLRequest()))
579         return true;
580
581     // FIXME: Mac WebKit calls _representationExistsForURLScheme here
582     return false;
583 }
584
585 Page* WebView::page()
586 {
587     return m_page;
588 }
589
590 bool WebView::handleContextMenuEvent(WPARAM wParam, LPARAM lParam)
591 {
592     static const int contextMenuMargin = 1;
593
594     // Translate the screen coordinates into window coordinates
595     POINT coords = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
596     if (coords.x == -1 || coords.y == -1) {
597         FrameView* view = m_page->mainFrame()->view();
598         if (!view)
599             return false;
600
601         int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
602         IntPoint location;
603
604         // The context menu event was generated from the keyboard, so show the context menu by the current selection.
605         Position start = m_page->mainFrame()->selectionController()->selection().start();
606         Position end = m_page->mainFrame()->selectionController()->selection().end();
607
608         if (!start.node() || !end.node())
609             location = IntPoint(rightAligned ? view->contentsWidth() - contextMenuMargin : contextMenuMargin, contextMenuMargin);
610         else {
611             RenderObject* renderer = start.node()->renderer();
612             if (!renderer)
613                 return false;
614
615             // Calculate the rect of the first line of the selection (cribbed from -[WebCoreFrameBridge firstRectForDOMRange:]).
616             int extraWidthToEndOfLine = 0;
617             IntRect startCaretRect = renderer->caretRect(start.offset(), DOWNSTREAM, &extraWidthToEndOfLine);
618             IntRect endCaretRect = renderer->caretRect(end.offset(), UPSTREAM);
619
620             IntRect firstRect;
621             if (startCaretRect.y() == endCaretRect.y())
622                 firstRect = IntRect(min(startCaretRect.x(), endCaretRect.x()), startCaretRect.y(), abs(endCaretRect.x() - startCaretRect.x()), max(startCaretRect.height(), endCaretRect.height()));
623             else
624                 firstRect = IntRect(startCaretRect.x(), startCaretRect.y(), startCaretRect.width() + extraWidthToEndOfLine, startCaretRect.height());
625
626             location = IntPoint(rightAligned ? firstRect.right() : firstRect.x(), firstRect.bottom());
627         }
628
629         location = view->contentsToWindow(location);
630         // FIXME: The IntSize(0, -1) is a hack to get the hit-testing to result in the selected element.
631         // Ideally we'd have the position of a context menu event be separate from its target node.
632         coords = location + IntSize(0, -1);
633     } else {
634         if (!::ScreenToClient(m_viewWindow, &coords))
635             return false;
636     }
637
638     lParam = MAKELPARAM(coords.x, coords.y);
639
640     // The contextMenuController() holds onto the last context menu that was popped up on the
641     // page until a new one is created. We need to clear this menu before propagating the event
642     // through the DOM so that we can detect if we create a new menu for this event, since we
643     // won't create a new menu if the DOM swallows the event and the defaultEventHandler does
644     // not run.
645     m_page->contextMenuController()->clearContextMenu();
646
647     Frame* focusedFrame = m_page->focusController()->focusedOrMainFrame();
648     focusedFrame->view()->setCursor(pointerCursor());
649     PlatformMouseEvent mouseEvent(m_viewWindow, WM_RBUTTONUP, wParam, lParam);
650     bool handledEvent = focusedFrame->eventHandler()->sendContextMenuEvent(mouseEvent);
651     if (!handledEvent)
652         return false;
653
654     // Show the menu
655     ContextMenu* coreMenu = m_page->contextMenuController()->contextMenu();
656     if (!coreMenu)
657         return false;
658
659     Node* node = coreMenu->hitTestResult().innerNonSharedNode();
660     if (!node)
661         return false;
662
663     Frame* frame = node->document()->frame();
664     if (!frame)
665         return false;
666
667     FrameView* view = frame->view();
668     if (!view)
669         return false;
670
671     POINT point(view->contentsToWindow(coreMenu->hitTestResult().point()));
672
673     // Translate the point to screen coordinates
674     if (!::ClientToScreen(view->containingWindow(), &point))
675         return false;
676
677     BOOL hasCustomMenus = false;
678     if (m_uiDelegate)
679         m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
680
681     if (hasCustomMenus)
682         m_uiDelegate->trackCustomPopupMenu((IWebView*)this, (OLE_HANDLE)(ULONG64)coreMenu->platformDescription(), &point);
683     else {
684         // Surprisingly, TPM_RIGHTBUTTON means that items are selectable with either the right OR left mouse button
685         UINT flags = TPM_RIGHTBUTTON | TPM_TOPALIGN | TPM_VERPOSANIMATION | TPM_HORIZONTAL
686             | TPM_LEFTALIGN | TPM_HORPOSANIMATION;
687         ::TrackPopupMenuEx(coreMenu->platformDescription(), flags, point.x, point.y, view->containingWindow(), 0);
688     }
689
690     return true;
691 }
692
693 bool WebView::onMeasureItem(WPARAM /*wParam*/, LPARAM lParam)
694 {
695     if (!m_uiDelegate)
696         return false;
697
698     BOOL hasCustomMenus = false;
699     m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
700     if (!hasCustomMenus)
701         return false;
702
703     m_uiDelegate->measureCustomMenuItem((IWebView*)this, (void*)lParam);
704     return true;
705 }
706
707 bool WebView::onDrawItem(WPARAM /*wParam*/, LPARAM lParam)
708 {
709     if (!m_uiDelegate)
710         return false;
711
712     BOOL hasCustomMenus = false;
713     m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
714     if (!hasCustomMenus)
715         return false;
716
717     m_uiDelegate->drawCustomMenuItem((IWebView*)this, (void*)lParam);
718     return true;
719 }
720
721 bool WebView::onInitMenuPopup(WPARAM wParam, LPARAM /*lParam*/)
722 {
723     if (!m_uiDelegate)
724         return false;
725
726     HMENU menu = (HMENU)wParam;
727     if (!menu)
728         return false;
729
730     BOOL hasCustomMenus = false;
731     m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
732     if (!hasCustomMenus)
733         return false;
734
735     m_uiDelegate->addCustomMenuDrawingData((IWebView*)this, (OLE_HANDLE)(ULONG64)menu);
736     return true;
737 }
738
739 bool WebView::onUninitMenuPopup(WPARAM wParam, LPARAM /*lParam*/)
740 {
741     if (!m_uiDelegate)
742         return false;
743
744     HMENU menu = (HMENU)wParam;
745     if (!menu)
746         return false;
747
748     BOOL hasCustomMenus = false;
749     m_uiDelegate->hasCustomMenuImplementation(&hasCustomMenus);
750     if (!hasCustomMenus)
751         return false;
752
753     m_uiDelegate->cleanUpCustomMenuDrawingData((IWebView*)this, (OLE_HANDLE)(ULONG64)menu);
754     return true;
755 }
756
757 void WebView::performContextMenuAction(WPARAM wParam, LPARAM /*lParam*/)
758 {
759     ContextMenu* menu = m_page->contextMenuController()->contextMenu();
760     ASSERT(menu);
761
762     ContextMenuItem* item = menu->itemWithAction((ContextMenuAction)wParam);
763     m_page->contextMenuController()->contextMenuItemSelected(item);
764     delete item;
765 }
766
767 bool WebView::handleMouseEvent(UINT message, WPARAM wParam, LPARAM lParam)
768 {
769     static LONG globalClickCount;
770     static IntPoint globalPrevPoint;
771     static MouseButton globalPrevButton;
772     static LONG globalPrevMouseDownTime;
773
774     // Create our event.
775     PlatformMouseEvent mouseEvent(m_viewWindow, message, wParam, lParam, m_mouseActivated);
776    
777     bool insideThreshold = abs(globalPrevPoint.x() - mouseEvent.pos().x()) < ::GetSystemMetrics(SM_CXDOUBLECLK) &&
778                            abs(globalPrevPoint.y() - mouseEvent.pos().y()) < ::GetSystemMetrics(SM_CYDOUBLECLK);
779     LONG messageTime = ::GetMessageTime();
780     
781     bool handled = false;
782     if (message == WM_LBUTTONDOWN || message == WM_MBUTTONDOWN || message == WM_RBUTTONDOWN) {
783         // FIXME: I'm not sure if this is the "right" way to do this
784         // but without this call, we never become focused since we don't allow
785         // the default handling of mouse events.
786         SetFocus(m_viewWindow);
787
788         // Always start capturing events when the mouse goes down in our HWND.
789         ::SetCapture(m_viewWindow);
790
791         if (((messageTime - globalPrevMouseDownTime) < (LONG)::GetDoubleClickTime()) && 
792             insideThreshold &&
793             mouseEvent.button() == globalPrevButton)
794             globalClickCount++;
795         else
796             // Reset the click count.
797             globalClickCount = 1;
798         globalPrevMouseDownTime = messageTime;
799         globalPrevButton = mouseEvent.button();
800         globalPrevPoint = mouseEvent.pos();
801         
802         mouseEvent.setClickCount(globalClickCount);
803         handled = m_page->mainFrame()->eventHandler()->handleMousePressEvent(mouseEvent);
804     } else if (message == WM_LBUTTONDBLCLK || message == WM_MBUTTONDBLCLK || message == WM_RBUTTONDBLCLK) {
805         globalClickCount++;
806         mouseEvent.setClickCount(globalClickCount);
807         handled = m_page->mainFrame()->eventHandler()->handleMousePressEvent(mouseEvent);
808     } else if (message == WM_LBUTTONUP || message == WM_MBUTTONUP || message == WM_RBUTTONUP) {
809         // Record the global position and the button of the up.
810         globalPrevButton = mouseEvent.button();
811         globalPrevPoint = mouseEvent.pos();
812         mouseEvent.setClickCount(globalClickCount);
813         m_page->mainFrame()->eventHandler()->handleMouseReleaseEvent(mouseEvent);
814         ::ReleaseCapture();
815     } else if (message == WM_MOUSEMOVE) {
816         if (!insideThreshold)
817             globalClickCount = 0;
818         mouseEvent.setClickCount(globalClickCount);
819         handled = m_page->mainFrame()->eventHandler()->mouseMoved(mouseEvent);
820     }
821     setMouseActivated(false);
822     return handled;
823 }
824
825 bool WebView::mouseWheel(WPARAM wParam, LPARAM lParam, bool isHorizontal)
826 {
827     // Ctrl+Mouse wheel doesn't ever go into WebCore.  It is used to
828     // zoom instead (Mac zooms the whole Desktop, but Windows browsers trigger their
829     // own local zoom modes for Ctrl+wheel).
830     if (wParam & MK_CONTROL) {
831         short delta = short(HIWORD(wParam));
832         if (delta < 0)
833             makeTextLarger(0);
834         else
835             makeTextSmaller(0);
836         return true;
837     }
838
839     PlatformWheelEvent wheelEvent(m_viewWindow, wParam, lParam, isHorizontal);
840     Frame* coreFrame = core(m_mainFrame);
841     if (!coreFrame)
842         return false;
843
844     return coreFrame->eventHandler()->handleWheelEvent(wheelEvent);
845 }
846
847 bool WebView::execCommand(WPARAM wParam, LPARAM /*lParam*/)
848 {
849     Frame* frame = m_page->focusController()->focusedOrMainFrame();
850     bool handled = false;
851     switch (LOWORD(wParam)) {
852     case SelectAll:
853         handled = frame->editor()->execCommand("SelectAll");
854         break;
855     case Undo:
856         handled = frame->editor()->execCommand("Undo");
857         break;
858     case Redo:
859         handled = frame->editor()->execCommand("Redo");
860         break;
861     default:
862         break;
863     }
864     return handled;
865 }
866
867 bool WebView::keyUp(WPARAM virtualKeyCode, LPARAM keyData)
868 {
869     // Don't send key events for shift, ctrl, and capslock keys when they're by themselves
870     if (virtualKeyCode == VK_SHIFT || virtualKeyCode == VK_CONTROL || virtualKeyCode == VK_CAPITAL) {
871         return false;
872     }
873
874     // Don't process keyDown events during IME composition
875     if (m_inIMEComposition)
876         return false;
877
878     PlatformKeyboardEvent keyEvent(m_viewWindow, virtualKeyCode, keyData, m_currentCharacterCode);
879     Frame* frame = m_page->focusController()->focusedOrMainFrame();
880     m_currentCharacterCode = 0;
881
882     return frame->eventHandler()->keyEvent(keyEvent);
883 }
884
885 static const unsigned CtrlKey = 1 << 0;
886 static const unsigned AltKey = 1 << 1;
887 static const unsigned ShiftKey = 1 << 2;
888
889
890 struct KeyEntry {
891     unsigned virtualKey;
892     unsigned modifiers;
893     const char* name;
894 };
895
896 static const KeyEntry keyEntries[] = {
897     { VK_LEFT,   0,                  "MoveLeft"                                    },
898     { VK_LEFT,   ShiftKey,           "MoveLeftAndModifySelection"                  },
899     { VK_LEFT,   CtrlKey,            "MoveWordLeft"                                },
900     { VK_LEFT,   CtrlKey | ShiftKey, "MoveWordLeftAndModifySelection"              },
901     { VK_RIGHT,  0,                  "MoveRight"                                   },
902     { VK_RIGHT,  ShiftKey,           "MoveRightAndModifySelection"                 },
903     { VK_RIGHT,  CtrlKey,            "MoveWordRight"                               },
904     { VK_RIGHT,  CtrlKey | ShiftKey, "MoveWordRightAndModifySelection"             },
905     { VK_UP,     0,                  "MoveUp"                                      },
906     { VK_UP,     ShiftKey,           "MoveUpAndModifySelection"                    },
907     { VK_PRIOR,  ShiftKey,           "MoveUpAndModifySelection"                    },
908     { VK_DOWN,   0,                  "MoveDown"                                    },
909     { VK_DOWN,   ShiftKey,           "MoveDownAndModifySelection"                  },
910     { VK_NEXT,   ShiftKey,           "MoveDownAndModifySelection"                  },
911     { VK_PRIOR,  0,                  "MoveUpByPageAndModifyCaret"                  },
912     { VK_NEXT,   0,                  "MoveDownByPageAndModifyCaret"                },
913     { VK_HOME,   0,                  "MoveToBeginningOfLine"                       },
914     { VK_HOME,   ShiftKey,           "MoveToBeginningOfLineAndModifySelection"     },
915     { VK_HOME,   CtrlKey,            "MoveToBeginningOfDocument"                   },
916     { VK_HOME,   CtrlKey | ShiftKey, "MoveToBeginningOfDocumentAndModifySelection" },
917
918     { VK_END,    0,                  "MoveToEndOfLine"                             },
919     { VK_END,    ShiftKey,           "MoveToEndOfLineAndModifySelection"           },
920     { VK_END,    CtrlKey,            "MoveToEndOfDocument"                         },
921     { VK_END,    CtrlKey | ShiftKey, "MoveToEndOfDocumentAndModifySelection"       },
922
923     { VK_BACK,   0,                  "BackwardDelete"                              },
924     { VK_BACK,   ShiftKey,           "BackwardDelete"                              },
925     { VK_DELETE, 0,                  "ForwardDelete"                               },
926     { VK_DELETE, ShiftKey,           "ForwardDelete"                               },
927     { VK_BACK,   CtrlKey,            "DeleteWordBackward"                          },
928     { VK_DELETE, CtrlKey,            "DeleteWordForward"                           },
929     
930     { 'B',       CtrlKey,            "ToggleBold"                                  },
931     { 'I',       CtrlKey,            "ToggleItalic"                                },
932
933     { VK_ESCAPE, 0,                  "Cancel"                                      },
934     { VK_OEM_PERIOD, CtrlKey,        "Cancel"                                      },
935     { VK_TAB,    0,                  "InsertTab"                                   },
936     { VK_TAB,    ShiftKey,           "InsertBacktab"                               },
937     { VK_RETURN, 0,                  "InsertNewline"                               },
938     { VK_RETURN, CtrlKey,            "InsertNewline"                               },
939     { VK_RETURN, AltKey,             "InsertNewline"                               },
940     { VK_RETURN, AltKey | ShiftKey,  "InsertNewline"                               },
941
942     { 'C',       CtrlKey,            "Copy"                                        },
943     { 'V',       CtrlKey,            "Paste"                                       },
944     { 'X',       CtrlKey,            "Cut"                                         },
945 };
946
947 const char* WebView::interpretKeyEvent(const KeyboardEvent* evt)
948 {
949     const PlatformKeyboardEvent* keyEvent = evt->keyEvent();
950     if (!keyEvent)
951         return "";
952
953     static HashMap<int, const char*>* commandsMap = 0;
954
955     if (!commandsMap) {
956         commandsMap = new HashMap<int, const char*>;
957
958         for (unsigned i = 0; i < _countof(keyEntries); i++)
959             commandsMap->set(keyEntries[i].modifiers << 16 | keyEntries[i].virtualKey, keyEntries[i].name);
960     }
961
962     unsigned modifiers = 0;
963     if (keyEvent->shiftKey())
964         modifiers |= ShiftKey;
965     if (keyEvent->altKey())
966         modifiers |= AltKey;
967     if (keyEvent->ctrlKey())
968         modifiers |= CtrlKey;
969
970     return commandsMap->get(modifiers << 16 | keyEvent->WindowsKeyCode());
971 }
972
973 bool WebView::handleEditingKeyboardEvent(KeyboardEvent* evt)
974 {
975     String command(interpretKeyEvent(evt));
976
977     Node* node = evt->target()->toNode();
978     ASSERT(node);
979     Frame* frame = node->document()->frame();
980     ASSERT(frame);
981
982     if (!command.isEmpty())
983         if (frame->editor()->execCommand(command, evt))
984             return true;
985
986     if (evt->keyEvent())
987         if (frame->editor()->insertText(evt->keyEvent()->text(), evt))
988             return true;
989
990     return false;
991 }
992
993 bool WebView::keyDown(WPARAM virtualKeyCode, LPARAM keyData)
994 {
995     MSG msg;
996     // If the next message is a WM_CHAR message, then take it out of the queue, and use
997     // the message parameters to get the character code to construct the PlatformKeyboardEvent.
998     if (::PeekMessage(&msg, m_viewWindow, WM_CHAR, WM_CHAR, PM_REMOVE)) 
999         m_currentCharacterCode = (UChar)msg.wParam;
1000
1001     // FIXME: We need to check WM_UNICHAR to support supplementary characters.
1002     // FIXME: We may need to handle other messages for international text.
1003
1004     // Don't send key events for shift, ctrl, and capslock keys when they're by themselves
1005     if (virtualKeyCode == VK_SHIFT || virtualKeyCode == VK_CONTROL || virtualKeyCode == VK_CAPITAL)
1006         return false;
1007
1008     // Don't process keyDown events during IME composition
1009     if (m_inIMEComposition)
1010         return false;
1011
1012     PlatformKeyboardEvent keyEvent(m_viewWindow, virtualKeyCode, keyData, m_currentCharacterCode);
1013     Frame* frame = m_page->focusController()->focusedOrMainFrame();
1014
1015     if (frame->eventHandler()->keyEvent(keyEvent))
1016         return true;
1017
1018     // We need to handle back/forward using either Backspace(+Shift) or Ctrl+Left/Right Arrow keys.
1019     int windowsKeyCode = keyEvent.WindowsKeyCode();
1020     if ((windowsKeyCode == VK_BACK && keyEvent.shiftKey()) || (windowsKeyCode == VK_RIGHT && keyEvent.ctrlKey()))
1021         m_page->goForward();
1022     else if (windowsKeyCode == VK_BACK || (windowsKeyCode == VK_LEFT && keyEvent.ctrlKey()))
1023         m_page->goBack();
1024     
1025     // Need to scroll the page if the arrow keys, space(shift), pgup/dn, or home/end are hit.
1026     ScrollDirection direction;
1027     ScrollGranularity granularity;
1028     switch (windowsKeyCode) {
1029         case VK_LEFT:
1030             granularity = ScrollByLine;
1031             direction = ScrollLeft;
1032             break;
1033         case VK_RIGHT:
1034             granularity = ScrollByLine;
1035             direction = ScrollRight;
1036             break;
1037         case VK_UP:
1038             granularity = ScrollByLine;
1039             direction = ScrollUp;
1040             break;
1041         case VK_DOWN:
1042             granularity = ScrollByLine;
1043             direction = ScrollDown;
1044             break;
1045         case VK_HOME:
1046             granularity = ScrollByDocument;
1047             direction = ScrollUp;
1048             break;
1049         case VK_END:
1050             granularity = ScrollByDocument;
1051             direction = ScrollDown;
1052             break;
1053         case VK_SPACE:
1054             granularity = ScrollByPage;
1055             direction = (GetKeyState(VK_SHIFT) & 0x8000) ? ScrollUp : ScrollDown;
1056             break;
1057         case VK_PRIOR:
1058             granularity = ScrollByPage;
1059             direction = ScrollUp;
1060             break;
1061         case VK_NEXT:
1062             granularity = ScrollByPage;
1063             direction = ScrollDown;
1064             break;
1065         default:
1066             // We return true here so the WM_CHAR handler won't pick up unhandled messages.
1067             return true;
1068     }
1069
1070     frame->view()->scroll(direction, granularity);
1071
1072     return true;
1073 }
1074
1075 bool WebView::inResizer(LPARAM lParam)
1076 {
1077     if (!m_uiDelegatePrivate)
1078         return false;
1079
1080     RECT r;
1081     if (FAILED(m_uiDelegatePrivate->webViewResizerRect(this, &r)))
1082         return false;
1083
1084     POINT pt;
1085     pt.x = LOWORD(lParam);
1086     pt.y = HIWORD(lParam);
1087     return !!PtInRect(&r, pt);
1088 }
1089
1090 void WebView::initializeCacheSizesIfNecessary()
1091 {
1092     static bool didInitialize;
1093     if (didInitialize)
1094         return;
1095
1096     COMPtr<IWebPreferences> prefs;
1097     if (FAILED(preferences(&prefs)))
1098         return;
1099
1100    UINT pageCacheSize;
1101    if (SUCCEEDED(prefs->pageCacheSize(&pageCacheSize)))
1102         pageCache()->setCapacity(pageCacheSize);
1103
1104    UINT objectCacheSize;
1105    if (SUCCEEDED(prefs->objectCacheSize(&objectCacheSize)))
1106         cache()->setMaximumSize(objectCacheSize);
1107
1108     didInitialize = true;
1109 }
1110
1111 static ATOM registerWebViewWindowClass()
1112 {
1113     static bool haveRegisteredWindowClass = false;
1114     if (haveRegisteredWindowClass)
1115         return true;
1116
1117     WNDCLASSEX wcex;
1118
1119     wcex.cbSize = sizeof(WNDCLASSEX);
1120
1121     wcex.style          = CS_DBLCLKS;
1122     wcex.lpfnWndProc    = WebViewWndProc;
1123     wcex.cbClsExtra     = 0;
1124     wcex.cbWndExtra     = 4; // 4 bytes for the IWebView pointer
1125     wcex.hInstance      = gInstance;
1126     wcex.hIcon          = 0;
1127     wcex.hCursor        = ::LoadCursor(0, IDC_ARROW);
1128     wcex.hbrBackground  = 0;
1129     wcex.lpszMenuName   = 0;
1130     wcex.lpszClassName  = kWebViewWindowClassName;
1131     wcex.hIconSm        = 0;
1132
1133     return RegisterClassEx(&wcex);
1134 }
1135
1136 namespace WebCore {
1137     extern HCURSOR lastSetCursor;
1138 }
1139
1140 static LRESULT CALLBACK WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1141 {
1142     LRESULT lResult = 0;
1143     LONG_PTR longPtr = GetWindowLongPtr(hWnd, 0);
1144     WebView* webView = reinterpret_cast<WebView*>(longPtr);
1145     WebFrame* mainFrameImpl = webView ? webView->topLevelFrame() : 0;
1146     if (!mainFrameImpl)
1147         return DefWindowProc(hWnd, message, wParam, lParam);
1148
1149     ASSERT(webView);
1150
1151     bool handled = true;
1152
1153     switch (message) {
1154         case WM_PAINT: {
1155             COMPtr<IWebDataSource> dataSource;
1156             mainFrameImpl->dataSource(&dataSource);
1157             Frame* coreFrame = core(mainFrameImpl);
1158             if (!webView->isPainting() && (!dataSource || coreFrame && coreFrame->view()->didFirstLayout()))
1159                 webView->paint(0, 0);
1160             else
1161                 ValidateRect(hWnd, 0);
1162             break;
1163         }
1164         case WM_PRINTCLIENT:
1165             webView->paint((HDC)wParam, lParam);
1166             break;
1167         case WM_DESTROY:
1168             webView->close();
1169             webView->setIsBeingDestroyed();
1170             webView->revokeDragDrop();
1171             break;
1172         case WM_MOUSEMOVE:
1173             if (webView->inResizer(lParam))
1174                 SetCursor(LoadCursor(0, IDC_SIZENWSE));
1175             // fall through
1176         case WM_LBUTTONDOWN:
1177         case WM_MBUTTONDOWN:
1178         case WM_RBUTTONDOWN:
1179         case WM_LBUTTONDBLCLK:
1180         case WM_MBUTTONDBLCLK:
1181         case WM_RBUTTONDBLCLK:
1182         case WM_LBUTTONUP:
1183         case WM_MBUTTONUP:
1184         case WM_RBUTTONUP:
1185             if (Frame* coreFrame = core(mainFrameImpl))
1186                 if (coreFrame->view()->didFirstLayout())
1187                     handled = webView->handleMouseEvent(message, wParam, lParam);
1188             break;
1189         case WM_MOUSEWHEEL:
1190         case WM_VISTA_MOUSEHWHEEL:
1191             if (Frame* coreFrame = core(mainFrameImpl))
1192                 if (coreFrame->view()->didFirstLayout())
1193                     handled = webView->mouseWheel(wParam, lParam, (wParam & MK_SHIFT) || message == WM_VISTA_MOUSEHWHEEL);
1194             break;
1195         case WM_KEYDOWN:
1196             handled = webView->keyDown(wParam, lParam);
1197             break;
1198         case WM_KEYUP:
1199             handled = webView->keyUp(wParam, lParam);
1200             break;
1201         case WM_SIZE:
1202             if (webView->isBeingDestroyed())
1203                 // If someone has sent us this message while we're being destroyed, we should bail out so we don't crash.
1204                 break;
1205
1206             if (lParam != 0) {
1207                 webView->deleteBackingStore();
1208                 if (Frame* coreFrame = core(mainFrameImpl)) {
1209                     coreFrame->view()->resize(LOWORD(lParam), HIWORD(lParam));
1210
1211                     if (!coreFrame->loader()->isLoading())
1212                         coreFrame->sendResizeEvent();
1213                 }
1214             }
1215             break;
1216         case WM_SHOWWINDOW:
1217             lResult = DefWindowProc(hWnd, message, wParam, lParam);
1218             if (wParam == 0)
1219                 // The window is being hidden (e.g., because we switched tabs.
1220                 // Null out our backing store.
1221                 webView->deleteBackingStore();
1222             break;
1223         case WM_SETFOCUS: {
1224             COMPtr<IWebUIDelegate> uiDelegate;
1225             COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate;
1226             if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate &&
1227                 SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate)
1228                 uiDelegatePrivate->webViewReceivedFocus(webView);
1229             // FIXME: Merge this logic with updateActiveState, and switch this over to use updateActiveState
1230
1231             // It's ok to just always do setWindowHasFocus, since we won't fire the focus event on the DOM
1232             // window unless the value changes.  It's also ok to do setIsActive inside focus,
1233             // because Windows has no concept of having to update control tints (e.g., graphite vs. aqua)
1234             // and therefore only needs to update the selection (which is limited to the focused frame).
1235             FocusController* focusController = webView->page()->focusController();
1236             if (Frame* frame = focusController->focusedFrame()) {
1237                 frame->setIsActive(true);
1238
1239                 // If the previously focused window is a child of ours (for example a plugin), don't send any
1240                 // focus events.
1241                 if (!IsChild(hWnd, reinterpret_cast<HWND>(wParam)))
1242                     frame->setWindowHasFocus(true);
1243             } else
1244                 focusController->setFocusedFrame(webView->page()->mainFrame());
1245             break;
1246         }
1247         case WM_KILLFOCUS: {
1248             COMPtr<IWebUIDelegate> uiDelegate;
1249             COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate;
1250             if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate &&
1251                 SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate)
1252                 uiDelegatePrivate->webViewLostFocus(webView, (OLE_HANDLE)(ULONG64)wParam);
1253             // FIXME: Merge this logic with updateActiveState, and switch this over to use updateActiveState
1254
1255             // However here we have to be careful.  If we are losing focus because of a deactivate,
1256             // then we need to remember our focused target for restoration later.  
1257             // If we are losing focus to another part of our window, then we are no longer focused for real
1258             // and we need to clear out the focused target.
1259             FocusController* focusController = webView->page()->focusController();
1260             webView->resetIME(focusController->focusedOrMainFrame());
1261             if (GetAncestor(hWnd, GA_ROOT) != GetFocus()) {
1262                 if (Frame* frame = focusController->focusedFrame()) {
1263                     frame->setIsActive(false);
1264
1265                     // If we're losing focus to a child of ours, don't send blur events.
1266                     if (!IsChild(hWnd, reinterpret_cast<HWND>(wParam)))
1267                         frame->setWindowHasFocus(false);
1268                 }
1269             } else
1270                 focusController->setFocusedFrame(0);
1271             break;
1272         }
1273         case WM_CUT:
1274             webView->cut(0);
1275             break;
1276         case WM_COPY:
1277             webView->copy(0);
1278             break;
1279         case WM_PASTE:
1280             webView->paste(0);
1281             break;
1282         case WM_CLEAR:
1283             webView->delete_(0);
1284             break;
1285         case WM_COMMAND:
1286             if (HIWORD(wParam))
1287                 handled = webView->execCommand(wParam, lParam);
1288             else // If the high word of wParam is 0, the message is from a menu
1289                 webView->performContextMenuAction(wParam, lParam);
1290             break;
1291         case WM_CONTEXTMENU:
1292             handled = webView->handleContextMenuEvent(wParam, lParam);
1293             break;
1294         case WM_INITMENUPOPUP:
1295             handled = webView->onInitMenuPopup(wParam, lParam);
1296             break;
1297         case WM_MEASUREITEM:
1298             handled = webView->onMeasureItem(wParam, lParam);
1299             break;
1300         case WM_DRAWITEM:
1301             handled = webView->onDrawItem(wParam, lParam);
1302             break;
1303         case WM_UNINITMENUPOPUP:
1304             handled = webView->onUninitMenuPopup(wParam, lParam);
1305             break;
1306         case WM_XP_THEMECHANGED:
1307             if (Frame* coreFrame = core(mainFrameImpl)) {
1308                 webView->deleteBackingStore();
1309                 coreFrame->view()->themeChanged();
1310             }
1311             break;
1312         case WM_MOUSEACTIVATE:
1313             webView->setMouseActivated(true);
1314             break;
1315         case WM_GETDLGCODE: {
1316             COMPtr<IWebUIDelegate> uiDelegate;
1317             COMPtr<IWebUIDelegatePrivate> uiDelegatePrivate;
1318             LONG_PTR dlgCode = 0;
1319             UINT keyCode = 0;
1320             if (lParam) {
1321                 LPMSG lpMsg = (LPMSG)lParam;
1322                 if (lpMsg->message == WM_KEYDOWN)
1323                     keyCode = (UINT) lpMsg->wParam;
1324             }
1325             if (SUCCEEDED(webView->uiDelegate(&uiDelegate)) && uiDelegate &&
1326                 SUCCEEDED(uiDelegate->QueryInterface(IID_IWebUIDelegatePrivate, (void**) &uiDelegatePrivate)) && uiDelegatePrivate &&
1327                 SUCCEEDED(uiDelegatePrivate->webViewGetDlgCode(webView, keyCode, &dlgCode)))
1328                 return dlgCode;
1329             handled = false;
1330             break;
1331         }
1332
1333         case WM_IME_STARTCOMPOSITION:
1334             handled = webView->onIMEStartComposition();
1335             break;
1336         case WM_IME_REQUEST:
1337             webView->onIMERequest(wParam, lParam, &lResult);
1338             break;
1339         case WM_IME_COMPOSITION:
1340             handled = webView->onIMEComposition(lParam);
1341             break;
1342         case WM_IME_ENDCOMPOSITION:
1343             handled = webView->onIMEEndComposition();
1344             break;
1345         case WM_IME_CHAR:
1346             handled = webView->onIMEChar(wParam, lParam);
1347             break;
1348         case WM_IME_NOTIFY:
1349             handled = webView->onIMENotify(wParam, lParam, &lResult);
1350             break;
1351         case WM_IME_SELECT:
1352             handled = webView->onIMESelect(wParam, lParam);
1353             break;
1354         case WM_IME_SETCONTEXT:
1355             handled = webView->onIMESetContext(wParam, lParam);
1356             break;
1357         case WM_SETCURSOR:
1358             if (lastSetCursor) {
1359                 SetCursor(lastSetCursor);
1360                 break;
1361             }
1362             __fallthrough;
1363         default:
1364             handled = false;
1365             break;
1366     }
1367
1368     if (!handled)
1369         lResult = DefWindowProc(hWnd, message, wParam, lParam);
1370     
1371     return lResult;
1372 }
1373
1374 HRESULT WebView::updateWebCoreSettingsFromPreferences(IWebPreferences* preferences)
1375 {
1376     HRESULT hr;
1377     BSTR str;
1378     int size;
1379     BOOL enabled;
1380     
1381     Settings* settings = m_page->settings();
1382
1383     hr = preferences->cursiveFontFamily(&str);
1384     if (FAILED(hr))
1385         return hr;
1386     settings->setCursiveFontFamily(AtomicString(str, SysStringLen(str)));
1387     SysFreeString(str);
1388
1389     hr = preferences->defaultFixedFontSize(&size);
1390     if (FAILED(hr))
1391         return hr;
1392     settings->setDefaultFixedFontSize(size);
1393
1394     hr = preferences->defaultFontSize(&size);
1395     if (FAILED(hr))
1396         return hr;
1397     settings->setDefaultFontSize(size);
1398     
1399     hr = preferences->defaultTextEncodingName(&str);
1400     if (FAILED(hr))
1401         return hr;
1402     settings->setDefaultTextEncodingName(String(str, SysStringLen(str)));
1403     SysFreeString(str);
1404
1405     hr = preferences->fantasyFontFamily(&str);
1406     if (FAILED(hr))
1407         return hr;
1408     settings->setFantasyFontFamily(AtomicString(str, SysStringLen(str)));
1409     SysFreeString(str);
1410
1411     hr = preferences->fixedFontFamily(&str);
1412     if (FAILED(hr))
1413         return hr;
1414     settings->setFixedFontFamily(AtomicString(str, SysStringLen(str)));
1415     SysFreeString(str);
1416
1417     hr = preferences->isJavaEnabled(&enabled);
1418     if (FAILED(hr))
1419         return hr;
1420     settings->setJavaEnabled(!!enabled);
1421
1422     hr = preferences->isJavaScriptEnabled(&enabled);
1423     if (FAILED(hr))
1424         return hr;
1425     settings->setJavaScriptEnabled(!!enabled);
1426
1427     hr = preferences->javaScriptCanOpenWindowsAutomatically(&enabled);
1428     if (FAILED(hr))
1429         return hr;
1430     settings->setJavaScriptCanOpenWindowsAutomatically(!!enabled);
1431
1432     hr = preferences->minimumFontSize(&size);
1433     if (FAILED(hr))
1434         return hr;
1435     settings->setMinimumFontSize(size);
1436
1437     hr = preferences->minimumLogicalFontSize(&size);
1438     if (FAILED(hr))
1439         return hr;
1440     settings->setMinimumLogicalFontSize(size);
1441
1442     hr = preferences->arePlugInsEnabled(&enabled);
1443     if (FAILED(hr))
1444         return hr;
1445     settings->setPluginsEnabled(!!enabled);
1446
1447     hr = preferences->privateBrowsingEnabled(&enabled);
1448     if (FAILED(hr))
1449         return hr;
1450     settings->setPrivateBrowsingEnabled(!!enabled);
1451
1452     hr = preferences->sansSerifFontFamily(&str);
1453     if (FAILED(hr))
1454         return hr;
1455     settings->setSansSerifFontFamily(AtomicString(str, SysStringLen(str)));
1456     SysFreeString(str);
1457
1458     hr = preferences->serifFontFamily(&str);
1459     if (FAILED(hr))
1460         return hr;
1461     settings->setSerifFontFamily(AtomicString(str, SysStringLen(str)));
1462     SysFreeString(str);
1463
1464     hr = preferences->standardFontFamily(&str);
1465     if (FAILED(hr))
1466         return hr;
1467     settings->setStandardFontFamily(AtomicString(str, SysStringLen(str)));
1468     SysFreeString(str);
1469
1470     hr = preferences->loadsImagesAutomatically(&enabled);
1471     if (FAILED(hr))
1472         return hr;
1473     settings->setLoadsImagesAutomatically(!!enabled);
1474
1475     hr = preferences->userStyleSheetEnabled(&enabled);
1476     if (FAILED(hr))
1477         return hr;
1478     if (enabled) {
1479         hr = preferences->userStyleSheetLocation(&str);
1480         if (FAILED(hr))
1481             return hr;
1482         settings->setUserStyleSheetLocation(KURL(DeprecatedString((DeprecatedChar*)str, SysStringLen(str))));
1483         SysFreeString(str);
1484     } else {
1485         settings->setUserStyleSheetLocation(KURL(DeprecatedString("")));
1486     }
1487
1488     hr = preferences->shouldPrintBackgrounds(&enabled);
1489     if (FAILED(hr))
1490         return hr;
1491     settings->setShouldPrintBackgrounds(!!enabled);
1492
1493     hr = preferences->textAreasAreResizable(&enabled);
1494     if (FAILED(hr))
1495         return hr;
1496     settings->setTextAreasAreResizable(!!enabled);
1497
1498     WebKitEditableLinkBehavior behavior;
1499     hr = preferences->editableLinkBehavior(&behavior);
1500     if (FAILED(hr))
1501         return hr;
1502     settings->setEditableLinkBehavior((EditableLinkBehavior)behavior);
1503
1504     WebKitCookieStorageAcceptPolicy acceptPolicy;
1505     hr = preferences->cookieStorageAcceptPolicy(&acceptPolicy);
1506     if (FAILED(hr))
1507         return hr;
1508
1509     hr = preferences->usesPageCache(&enabled);
1510     if (FAILED(hr))
1511         return hr;
1512     settings->setUsesPageCache(!!enabled);
1513
1514     hr = preferences->isDOMPasteAllowed(&enabled);
1515     if (FAILED(hr))
1516         return hr;
1517     settings->setDOMPasteAllowed(!!enabled);
1518
1519     ResourceHandle::setCookieStorageAcceptPolicy(acceptPolicy);
1520
1521     settings->setShowsURLsInToolTips(false);
1522
1523     settings->setForceFTPDirectoryListings(true);
1524
1525     // FIXME: make this read a preference like the Mac's WebKitDeveloperExtras
1526     // or when Safari's IncludeDebugMenu is set
1527     settings->setDeveloperExtrasEnabled(true);
1528
1529     m_mainFrame->invalidate(); // FIXME
1530
1531     return S_OK;
1532 }
1533
1534 static String osVersion()
1535 {
1536     String osVersion;
1537     OSVERSIONINFO versionInfo = {0};
1538     versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
1539     GetVersionEx(&versionInfo);
1540
1541     if (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1542         if (versionInfo.dwMajorVersion == 4) {
1543             if (versionInfo.dwMinorVersion == 0)
1544                 osVersion = "Windows 95";
1545             else if (versionInfo.dwMinorVersion == 10)
1546                 osVersion = "Windows 98";
1547             else if (versionInfo.dwMinorVersion == 90)
1548                 osVersion = "Windows 98; Win 9x 4.90";
1549         }
1550     } else if (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
1551         osVersion = String::format("Windows NT %d.%d", versionInfo.dwMajorVersion, versionInfo.dwMinorVersion);
1552
1553     if (!osVersion.length())
1554         osVersion = String::format("Windows %d.%d", versionInfo.dwMajorVersion, versionInfo.dwMinorVersion);
1555
1556     return osVersion;
1557 }
1558
1559 static String language()
1560 {
1561     TCHAR languageName[256];
1562     if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, languageName, ARRAYSIZE(languageName)))
1563         return "en";
1564     else
1565         return String(languageName, (unsigned int)_tcslen(languageName));
1566 }
1567
1568 static String webKitVersion()
1569 {
1570     String versionStr = "420+";
1571     void* data = 0;
1572
1573     struct LANGANDCODEPAGE {
1574         WORD wLanguage;
1575         WORD wCodePage;
1576     } *lpTranslate;
1577
1578     TCHAR path[MAX_PATH];
1579     GetModuleFileName(gInstance, path, ARRAYSIZE(path));
1580     DWORD handle;
1581     DWORD versionSize = GetFileVersionInfoSize(path, &handle);
1582     if (!versionSize)
1583         goto exit;
1584     data = malloc(versionSize);
1585     if (!data)
1586         goto exit;
1587     if (!GetFileVersionInfo(path, 0, versionSize, data))
1588         goto exit;
1589     UINT cbTranslate;
1590     if (!VerQueryValue(data, TEXT("\\VarFileInfo\\Translation"), (LPVOID*)&lpTranslate, &cbTranslate))
1591         goto exit;
1592     TCHAR key[256];
1593     _stprintf_s(key, ARRAYSIZE(key), TEXT("\\StringFileInfo\\%04x%04x\\ProductVersion"), lpTranslate[0].wLanguage, lpTranslate[0].wCodePage);
1594     LPCTSTR productVersion;
1595     UINT productVersionLength;
1596     if (!VerQueryValue(data, (LPTSTR)(LPCTSTR)key, (void**)&productVersion, &productVersionLength))
1597         goto exit;
1598     versionStr = String(productVersion, productVersionLength);
1599
1600 exit:
1601     if (data)
1602         free(data);
1603     return versionStr;
1604 }
1605
1606 const String& WebView::userAgentForKURL(const KURL& url)
1607 {
1608     if (m_userAgentOverridden)
1609         return m_userAgentCustom;
1610
1611     static const DeprecatedString uaCustomHosts[] = {
1612         "flickr.com",                       // <rdar://problem/5081617> flickr does not recognize post-2.0.4 versions of Safari
1613         "volvocars.us",                     // <rdar://problem/5246665> Drop down lists are not drawn on volvocars.us
1614         "investing.schwab.com"              // <rdar://problem/5213266> schwab.com menu is ridiculously big.
1615     };
1616     static const DeprecatedString uaCustomURLs[] = {
1617         "http://www.adobe.com/shockwave/download/"  // <rdar://problem/5243655> Flash download page doesn't recognize Boomer
1618     };
1619     static const String uaCustomValuesForHosts[] = {
1620         "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/418.9.1 (KHTML, like Gecko) Safari/419.3",
1621         "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/522.7 (KHTML, like Gecko) Version/3.0 Safari/522.7",
1622         "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3",
1623     };
1624     static const String uaCustomValuesForURLs[] = {
1625         "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3",
1626     };
1627
1628     if (allowSiteSpecificHacks()) {
1629         for (int i = 0; i < ARRAYSIZE(uaCustomHosts); i++) {
1630             if (url.host().endsWith(uaCustomHosts[i]))
1631                 return uaCustomValuesForHosts[i];
1632         }
1633         for (int i = 0; i < ARRAYSIZE(uaCustomURLs); i++) {
1634             if (url.url().startsWith(uaCustomURLs[i]))
1635                 return uaCustomValuesForURLs[i];
1636         }
1637     }
1638
1639     if (!m_userAgentStandard.length())
1640         m_userAgentStandard = String::format("Mozilla/5.0 (Windows; U; %s; %s) AppleWebKit/%s (KHTML, like Gecko)%s%s", osVersion().latin1().data(), language().latin1().data(), webKitVersion().latin1().data(), (m_applicationName.length() ? " " : ""), m_applicationName.latin1().data());
1641     return m_userAgentStandard;
1642 }
1643
1644 // IUnknown -------------------------------------------------------------------
1645
1646 HRESULT STDMETHODCALLTYPE WebView::QueryInterface(REFIID riid, void** ppvObject)
1647 {
1648     *ppvObject = 0;
1649     if (IsEqualGUID(riid, CLSID_WebView))
1650         *ppvObject = this;
1651     else if (IsEqualGUID(riid, IID_IUnknown))
1652         *ppvObject = static_cast<IWebView*>(this);
1653     else if (IsEqualGUID(riid, IID_IWebView))
1654         *ppvObject = static_cast<IWebView*>(this);
1655     else if (IsEqualGUID(riid, IID_IWebViewPrivate))
1656         *ppvObject = static_cast<IWebViewPrivate*>(this);
1657     else if (IsEqualGUID(riid, IID_IWebIBActions))
1658         *ppvObject = static_cast<IWebIBActions*>(this);
1659     else if (IsEqualGUID(riid, IID_IWebViewCSS))
1660         *ppvObject = static_cast<IWebViewCSS*>(this);
1661     else if (IsEqualGUID(riid, IID_IWebViewEditing))
1662         *ppvObject = static_cast<IWebViewEditing*>(this);
1663     else if (IsEqualGUID(riid, IID_IWebViewUndoableEditing))
1664         *ppvObject = static_cast<IWebViewUndoableEditing*>(this);
1665     else if (IsEqualGUID(riid, IID_IWebViewEditingActions))
1666         *ppvObject = static_cast<IWebViewEditingActions*>(this);
1667     else if (IsEqualGUID(riid, IID_IWebNotificationObserver))
1668         *ppvObject = static_cast<IWebNotificationObserver*>(this);
1669     else if (IsEqualGUID(riid, IID_IDropTarget))
1670         *ppvObject = static_cast<IDropTarget*>(this);
1671     else
1672         return E_NOINTERFACE;
1673
1674     AddRef();
1675     return S_OK;
1676 }
1677
1678 ULONG STDMETHODCALLTYPE WebView::AddRef(void)
1679 {
1680     return ++m_refCount;
1681 }
1682
1683 ULONG STDMETHODCALLTYPE WebView::Release(void)
1684 {
1685     ULONG newRef = --m_refCount;
1686     if (!newRef)
1687         delete(this);
1688
1689     return newRef;
1690 }
1691
1692 // IWebView --------------------------------------------------------------------
1693
1694 HRESULT STDMETHODCALLTYPE WebView::canShowMIMEType( 
1695     /* [in] */ BSTR mimeType,
1696     /* [retval][out] */ BOOL* canShow)
1697 {
1698     String mimeTypeStr(mimeType, SysStringLen(mimeType));
1699
1700     if (!canShow)
1701         return E_POINTER;
1702
1703     *canShow = MIMETypeRegistry::isSupportedImageMIMEType(mimeTypeStr) ||
1704         MIMETypeRegistry::isSupportedNonImageMIMEType(mimeTypeStr) ||
1705         PlugInInfoStore::supportsMIMEType(mimeTypeStr);
1706     
1707     return S_OK;
1708 }
1709
1710 HRESULT STDMETHODCALLTYPE WebView::canShowMIMETypeAsHTML( 
1711     /* [in] */ BSTR /*mimeType*/,
1712     /* [retval][out] */ BOOL* canShow)
1713 {
1714     // FIXME
1715     *canShow = TRUE;
1716     return S_OK;
1717 }
1718
1719 HRESULT STDMETHODCALLTYPE WebView::MIMETypesShownAsHTML( 
1720     /* [retval][out] */ IEnumVARIANT** /*enumVariant*/)
1721 {
1722     ASSERT_NOT_REACHED();
1723     return E_NOTIMPL;
1724 }
1725
1726 HRESULT STDMETHODCALLTYPE WebView::setMIMETypesShownAsHTML( 
1727         /* [size_is][in] */ BSTR* /*mimeTypes*/,
1728         /* [in] */ int /*cMimeTypes*/)
1729 {
1730     ASSERT_NOT_REACHED();
1731     return E_NOTIMPL;
1732 }
1733
1734 HRESULT STDMETHODCALLTYPE WebView::URLFromPasteboard( 
1735     /* [in] */ IDataObject* /*pasteboard*/,
1736     /* [retval][out] */ BSTR* /*url*/)
1737 {
1738     ASSERT_NOT_REACHED();
1739     return E_NOTIMPL;
1740 }
1741
1742 HRESULT STDMETHODCALLTYPE WebView::URLTitleFromPasteboard( 
1743     /* [in] */ IDataObject* /*pasteboard*/,
1744     /* [retval][out] */ BSTR* /*urlTitle*/)
1745 {
1746     ASSERT_NOT_REACHED();
1747     return E_NOTIMPL;
1748 }
1749
1750 HRESULT STDMETHODCALLTYPE WebView::initWithFrame( 
1751     /* [in] */ RECT frame,
1752     /* [in] */ BSTR frameName,
1753     /* [in] */ BSTR groupName)
1754 {
1755     HRESULT hr = S_OK;
1756
1757     if (m_viewWindow)
1758         return E_FAIL;
1759
1760     registerWebViewWindowClass();
1761
1762     if (!::IsWindow(m_hostWindow)) {
1763         ASSERT_NOT_REACHED();
1764         return E_FAIL;
1765     }
1766
1767     m_viewWindow = CreateWindowEx(0, kWebViewWindowClassName, 0, WS_CHILD | WS_CLIPCHILDREN,
1768         frame.left, frame.top, frame.right - frame.left, frame.bottom - frame.top, m_hostWindow, 0, gInstance, 0);
1769     ASSERT(::IsWindow(m_viewWindow));
1770
1771     hr = registerDragDrop();
1772     if (FAILED(hr))
1773         return hr;
1774
1775     m_groupName = String(groupName, SysStringLen(groupName));
1776
1777     m_page = new Page(new WebChromeClient(this), new WebContextMenuClient(this), new WebEditorClient(this), new WebDragClient(this), new WebInspectorClient(this));
1778     // FIXME: 4931464 - When we do cache pages on Windows this needs to be removed so the "should I cache this page?" check
1779     // in FrameLoader::provisionalLoadStarted() doesn't always fail
1780     m_page->settings()->setUsesPageCache(false);
1781
1782     // Try to set the FTP Directory template path in WebCore when the first WebView is initialized
1783     static bool setFTPDirectoryTemplatePathOnce = false;
1784
1785     if (!setFTPDirectoryTemplatePathOnce && m_uiDelegate) {
1786         COMPtr<IWebUIDelegate2> uiDelegate2;
1787         if (SUCCEEDED(m_uiDelegate->QueryInterface(IID_IWebUIDelegate2, (void**)&uiDelegate2))) {
1788             BSTR path;
1789             if (SUCCEEDED(uiDelegate2->ftpDirectoryTemplatePath(this, &path))) {
1790                 m_page->settings()->setFTPDirectoryTemplatePath(String(path, SysStringLen(path)));
1791                 SysFreeString(path);
1792                 setFTPDirectoryTemplatePathOnce = true;
1793             }
1794         }
1795     }
1796
1797     WebFrame* webFrame = WebFrame::createInstance();
1798     webFrame->initWithWebFrameView(0 /*FIXME*/, this, m_page, 0);
1799     m_mainFrame = webFrame;
1800     webFrame->Release(); // The WebFrame is owned by the Frame, so release our reference to it.
1801
1802
1803     m_page->mainFrame()->tree()->setName(String(frameName, SysStringLen(frameName)));
1804     m_page->mainFrame()->init();
1805     m_page->setGroupName(m_groupName);
1806
1807     #pragma warning(suppress: 4244)
1808     SetWindowLongPtr(m_viewWindow, 0, (LONG_PTR)this);
1809     ShowWindow(m_viewWindow, SW_SHOW);
1810
1811     initializeCacheSizesIfNecessary();
1812     initializeToolTipWindow();
1813
1814     // Update WebCore with preferences.  These values will either come from an archived WebPreferences,
1815     // or from the standard preferences, depending on whether this method was called from initWithCoder:
1816     // or initWithFrame, respectively.
1817     //[self _updateWebCoreSettingsFromPreferences: [self preferences]];
1818     COMPtr<IWebPreferences> prefs;
1819     if (FAILED(preferences(&prefs)))
1820         return hr;
1821     hr = updateWebCoreSettingsFromPreferences(prefs.get());
1822     if (FAILED(hr))
1823         return hr;
1824
1825     // Use default cookie storage
1826     RetainPtr<CFHTTPCookieStorageRef> cookies(AdoptCF, CFHTTPCookieStorageCreateFromFile(kCFAllocatorDefault, 0, 0));
1827     ResourceHandle::setCookieStorage(cookies.get());
1828
1829     // Register to receive notifications whenever preference values change.
1830     //[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_preferencesChangedNotification:)
1831     //                                             name:WebPreferencesChangedNotification object:[self preferences]];
1832     IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal();
1833     if (!WebPreferences::webPreferencesChangedNotification())
1834         return E_OUTOFMEMORY;
1835     notifyCenter->addObserver(this, WebPreferences::webPreferencesChangedNotification(), prefs.get());
1836
1837     setSmartInsertDeleteEnabled(TRUE);
1838     return hr;
1839 }
1840
1841 static bool initCommonControls()
1842 {
1843     static bool haveInitialized = false;
1844     if (haveInitialized)
1845         return true;
1846
1847     INITCOMMONCONTROLSEX init;
1848     init.dwSize = sizeof(init);
1849     init.dwICC = ICC_TREEVIEW_CLASSES;
1850     haveInitialized = !!::InitCommonControlsEx(&init);
1851     return haveInitialized;
1852 }
1853
1854 void WebView::initializeToolTipWindow()
1855 {
1856     if (!initCommonControls())
1857         return;
1858
1859     m_toolTipHwnd = CreateWindowEx(0, TOOLTIPS_CLASS, 0, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
1860                                    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1861                                    m_viewWindow, 0, 0, 0);
1862     if (!m_toolTipHwnd)
1863         return;
1864
1865     TOOLINFO info = {0};
1866     info.cbSize = sizeof(info);
1867     info.uFlags = TTF_IDISHWND | TTF_SUBCLASS ;
1868     info.uId = reinterpret_cast<UINT_PTR>(m_viewWindow);
1869
1870     ::SendMessage(m_toolTipHwnd, TTM_ADDTOOL, 0, reinterpret_cast<LPARAM>(&info));
1871     ::SendMessage(m_toolTipHwnd, TTM_SETMAXTIPWIDTH, 0, maxToolTipWidth);
1872
1873     ::SetWindowPos(m_toolTipHwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
1874 }
1875
1876 void WebView::setToolTip(const String& toolTip)
1877 {
1878     if (!m_toolTipHwnd)
1879         return;
1880
1881     if (toolTip == m_toolTip)
1882         return;
1883
1884     m_toolTip = toolTip;
1885
1886     if (!m_toolTip.isEmpty()) {
1887         TOOLINFO info = {0};
1888         info.cbSize = sizeof(info);
1889         info.uFlags = TTF_IDISHWND;
1890         info.uId = reinterpret_cast<UINT_PTR>(m_viewWindow);
1891         info.lpszText = const_cast<UChar*>(m_toolTip.charactersWithNullTermination());
1892         ::SendMessage(m_toolTipHwnd, TTM_UPDATETIPTEXT, 0, reinterpret_cast<LPARAM>(&info));
1893     }
1894
1895     ::SendMessage(m_toolTipHwnd, TTM_ACTIVATE, !m_toolTip.isEmpty(), 0);
1896 }
1897
1898 HRESULT STDMETHODCALLTYPE WebView::setUIDelegate( 
1899     /* [in] */ IWebUIDelegate* d)
1900 {
1901     m_uiDelegate = d;
1902
1903     if (m_uiDelegatePrivate)
1904         m_uiDelegatePrivate = 0;
1905
1906     if (d) {
1907         if (FAILED(d->QueryInterface(IID_IWebUIDelegatePrivate, (void**)&m_uiDelegatePrivate)))
1908             m_uiDelegatePrivate = 0;
1909     }
1910
1911     return S_OK;
1912 }
1913
1914 HRESULT STDMETHODCALLTYPE WebView::uiDelegate( 
1915     /* [out][retval] */ IWebUIDelegate** d)
1916 {
1917     if (!m_uiDelegate)
1918         return E_FAIL;
1919
1920     return m_uiDelegate.copyRefTo(d);
1921 }
1922
1923 HRESULT STDMETHODCALLTYPE WebView::setResourceLoadDelegate( 
1924     /* [in] */ IWebResourceLoadDelegate* d)
1925 {
1926     m_resourceLoadDelegate = d;
1927     return S_OK;
1928 }
1929
1930 HRESULT STDMETHODCALLTYPE WebView::resourceLoadDelegate( 
1931     /* [out][retval] */ IWebResourceLoadDelegate** d)
1932 {
1933     if (!m_resourceLoadDelegate)
1934         return E_FAIL;
1935
1936     return m_resourceLoadDelegate.copyRefTo(d);
1937 }
1938
1939 HRESULT STDMETHODCALLTYPE WebView::setDownloadDelegate( 
1940     /* [in] */ IWebDownloadDelegate* d)
1941 {
1942     m_downloadDelegate = d;
1943     return S_OK;
1944 }
1945
1946 HRESULT STDMETHODCALLTYPE WebView::downloadDelegate( 
1947     /* [out][retval] */ IWebDownloadDelegate** d)
1948 {
1949     if (!m_downloadDelegate)
1950         return E_FAIL;
1951
1952     return m_downloadDelegate.copyRefTo(d);
1953 }
1954
1955 HRESULT STDMETHODCALLTYPE WebView::setFrameLoadDelegate( 
1956     /* [in] */ IWebFrameLoadDelegate* d)
1957 {
1958     m_frameLoadDelegate = d;
1959     return S_OK;
1960 }
1961
1962 HRESULT STDMETHODCALLTYPE WebView::frameLoadDelegate( 
1963     /* [out][retval] */ IWebFrameLoadDelegate** d)
1964 {
1965     if (!m_frameLoadDelegate)
1966         return E_FAIL;
1967
1968     return m_frameLoadDelegate.copyRefTo(d);
1969 }
1970
1971 HRESULT STDMETHODCALLTYPE WebView::setPolicyDelegate( 
1972     /* [in] */ IWebPolicyDelegate* d)
1973 {
1974     m_policyDelegate = d;
1975     return S_OK;
1976 }
1977
1978 HRESULT STDMETHODCALLTYPE WebView::policyDelegate( 
1979     /* [out][retval] */ IWebPolicyDelegate** d)
1980 {
1981     if (!m_policyDelegate)
1982         return E_FAIL;
1983     return m_policyDelegate.copyRefTo(d);
1984 }
1985
1986 HRESULT STDMETHODCALLTYPE WebView::mainFrame( 
1987     /* [out][retval] */ IWebFrame** frame)
1988 {
1989     if (!frame) {
1990         ASSERT_NOT_REACHED();
1991         return E_POINTER;
1992     }
1993
1994     *frame = m_mainFrame;
1995     if (!m_mainFrame)
1996         return E_FAIL;
1997
1998     m_mainFrame->AddRef();
1999     return S_OK;
2000 }
2001
2002 HRESULT STDMETHODCALLTYPE WebView::focusedFrame( 
2003     /* [out][retval] */ IWebFrame** frame)
2004 {
2005     if (!frame) {
2006         ASSERT_NOT_REACHED();
2007         return E_POINTER;
2008     }
2009
2010     *frame = 0;
2011     Frame* f = m_page->focusController()->focusedFrame();
2012     if (!f)
2013         return E_FAIL;
2014
2015     WebFrame* webFrame = kit(f);
2016     if (!webFrame)
2017         return E_FAIL;
2018
2019     return webFrame->QueryInterface(IID_IWebFrame, (void**) frame);
2020 }
2021 HRESULT STDMETHODCALLTYPE WebView::backForwardList( 
2022     /* [out][retval] */ IWebBackForwardList** list)
2023 {
2024     if (!m_useBackForwardList)
2025         return E_FAIL;
2026  
2027     *list = WebBackForwardList::createInstance(m_page->backForwardList());
2028
2029     return S_OK;
2030 }
2031
2032 HRESULT STDMETHODCALLTYPE WebView::setMaintainsBackForwardList( 
2033     /* [in] */ BOOL flag)
2034 {
2035     m_useBackForwardList = !!flag;
2036     return S_OK;
2037 }
2038
2039 HRESULT STDMETHODCALLTYPE WebView::goBack( 
2040     /* [retval][out] */ BOOL* succeeded)
2041 {
2042     *succeeded = m_page->goBack();
2043     return S_OK;
2044 }
2045
2046 HRESULT STDMETHODCALLTYPE WebView::goForward( 
2047     /* [retval][out] */ BOOL* succeeded)
2048 {
2049     *succeeded = m_page->goForward();
2050     return S_OK;
2051 }
2052
2053 HRESULT STDMETHODCALLTYPE WebView::goToBackForwardItem( 
2054     /* [in] */ IWebHistoryItem* item,
2055     /* [retval][out] */ BOOL* succeeded)
2056 {
2057     *succeeded = FALSE;
2058
2059     COMPtr<WebHistoryItem> webHistoryItem;
2060     HRESULT hr = item->QueryInterface(CLSID_WebHistoryItem, (void**)&webHistoryItem);
2061     if (FAILED(hr))
2062         return hr;
2063
2064     m_page->goToItem(webHistoryItem->historyItem(), FrameLoadTypeIndexedBackForward);
2065     *succeeded = TRUE;
2066
2067     return S_OK;
2068 }
2069
2070 HRESULT STDMETHODCALLTYPE WebView::setTextSizeMultiplier( 
2071     /* [in] */ float multiplier)
2072 {
2073     if (m_textSizeMultiplier != multiplier)
2074         m_textSizeMultiplier = multiplier;
2075     
2076     if (!m_mainFrame)
2077         return E_FAIL;
2078
2079     m_mainFrame->setTextSizeMultiplier(multiplier);
2080     return S_OK;
2081 }
2082
2083 HRESULT STDMETHODCALLTYPE WebView::textSizeMultiplier( 
2084     /* [retval][out] */ float* multiplier)
2085 {
2086     *multiplier = m_textSizeMultiplier;
2087     return S_OK;
2088 }
2089
2090 HRESULT STDMETHODCALLTYPE WebView::setApplicationNameForUserAgent( 
2091     /* [in] */ BSTR applicationName)
2092 {
2093     m_applicationName = String(applicationName, SysStringLen(applicationName));
2094     m_userAgentStandard = String();
2095     return S_OK;
2096 }
2097
2098 HRESULT STDMETHODCALLTYPE WebView::applicationNameForUserAgent( 
2099     /* [retval][out] */ BSTR* applicationName)
2100 {
2101     *applicationName = SysAllocStringLen(m_applicationName.characters(), m_applicationName.length());
2102     if (!*applicationName && m_applicationName.length())
2103         return E_OUTOFMEMORY;
2104     return S_OK;
2105 }
2106
2107 HRESULT STDMETHODCALLTYPE WebView::setCustomUserAgent( 
2108     /* [in] */ BSTR userAgentString)
2109 {
2110     m_userAgentOverridden = true;
2111     m_userAgentCustom = String(userAgentString, SysStringLen(userAgentString));
2112     return S_OK;
2113 }
2114
2115 HRESULT STDMETHODCALLTYPE WebView::customUserAgent( 
2116     /* [retval][out] */ BSTR* userAgentString)
2117 {
2118     *userAgentString = 0;
2119     if (!m_userAgentOverridden)
2120         return S_OK;
2121     *userAgentString = SysAllocStringLen(m_userAgentCustom.characters(), m_userAgentCustom.length());
2122     if (!*userAgentString && m_userAgentCustom.length())
2123         return E_OUTOFMEMORY;
2124     return S_OK;
2125 }
2126
2127 HRESULT STDMETHODCALLTYPE WebView::userAgentForURL( 
2128     /* [in] */ BSTR url,
2129     /* [retval][out] */ BSTR* userAgent)
2130 {
2131     DeprecatedString urlStr((DeprecatedChar*)url, SysStringLen(url));
2132     String userAgentString = this->userAgentForKURL(KURL(urlStr));
2133     *userAgent = SysAllocStringLen(userAgentString.characters(), userAgentString.length());
2134     if (!*userAgent && userAgentString.length())
2135         return E_OUTOFMEMORY;
2136     return S_OK;
2137 }
2138
2139 HRESULT STDMETHODCALLTYPE WebView::supportsTextEncoding( 
2140     /* [retval][out] */ BOOL* supports)
2141 {
2142     *supports = TRUE;
2143     return S_OK;
2144 }
2145
2146 HRESULT STDMETHODCALLTYPE WebView::setCustomTextEncodingName( 
2147     /* [in] */ BSTR encodingName)
2148 {
2149     if (!m_mainFrame)
2150         return E_FAIL;
2151
2152     HRESULT hr;
2153     BSTR oldEncoding;
2154     hr = customTextEncodingName(&oldEncoding);
2155     if (FAILED(hr))
2156         return hr;
2157
2158     if (oldEncoding != encodingName && (!oldEncoding || !encodingName || _tcscmp(oldEncoding, encodingName))) {
2159         if (Frame* coreFrame = core(m_mainFrame))
2160             coreFrame->loader()->reloadAllowingStaleData(String(encodingName, SysStringLen(encodingName)));
2161     }
2162
2163     return S_OK;
2164 }
2165
2166 HRESULT STDMETHODCALLTYPE WebView::customTextEncodingName( 
2167     /* [retval][out] */ BSTR* encodingName)
2168 {
2169     HRESULT hr = S_OK;
2170     COMPtr<IWebDataSource> dataSource;
2171     COMPtr<WebDataSource> dataSourceImpl;
2172     *encodingName = 0;
2173
2174     if (!m_mainFrame)
2175         return E_FAIL;
2176
2177     if (FAILED(m_mainFrame->provisionalDataSource(&dataSource)) || !dataSource) {
2178         hr = m_mainFrame->dataSource(&dataSource);
2179         if (FAILED(hr) || !dataSource)
2180             return hr;
2181     }
2182
2183     hr = dataSource->QueryInterface(IID_WebDataSource, (void**)&dataSourceImpl);
2184     if (FAILED(hr))
2185         return hr;
2186
2187     BString str = dataSourceImpl->documentLoader()->overrideEncoding();
2188     if (FAILED(hr))
2189         return hr;
2190
2191     if (!*encodingName)
2192         *encodingName = SysAllocStringLen(m_overrideEncoding.characters(), m_overrideEncoding.length());
2193
2194     if (!*encodingName && m_overrideEncoding.length())
2195         return E_OUTOFMEMORY;
2196
2197     return S_OK;
2198 }
2199
2200 HRESULT STDMETHODCALLTYPE WebView::setMediaStyle( 
2201     /* [in] */ BSTR /*media*/)
2202 {
2203     ASSERT_NOT_REACHED();
2204     return E_NOTIMPL;
2205 }
2206
2207 HRESULT STDMETHODCALLTYPE WebView::mediaStyle( 
2208     /* [retval][out] */ BSTR* /*media*/)
2209 {
2210     ASSERT_NOT_REACHED();
2211     return E_NOTIMPL;
2212 }
2213
2214 HRESULT STDMETHODCALLTYPE WebView::stringByEvaluatingJavaScriptFromString( 
2215     /* [in] */ BSTR script, // assumes input does not have "JavaScript" at the begining.
2216     /* [retval][out] */ BSTR* result)
2217 {
2218     if (!result) {
2219         ASSERT_NOT_REACHED();
2220         return E_POINTER;
2221     }
2222
2223     *result = 0;
2224
2225     Frame* coreFrame = core(m_mainFrame);
2226     if (!coreFrame)
2227         return E_FAIL;
2228
2229     KJS::JSValue* scriptExecutionResult = coreFrame->loader()->executeScript(WebCore::String(script), true);
2230     if(!scriptExecutionResult)
2231         return E_FAIL;
2232     else if (scriptExecutionResult->isString()) {
2233         JSLock lock;
2234         *result = BString(String(scriptExecutionResult->getString()));
2235     }
2236
2237     return S_OK;
2238 }
2239
2240 HRESULT STDMETHODCALLTYPE WebView::windowScriptObject( 
2241     /* [retval][out] */ IWebScriptObject** /*webScriptObject*/)
2242 {
2243     ASSERT_NOT_REACHED();
2244     return E_NOTIMPL;
2245 }
2246
2247 HRESULT STDMETHODCALLTYPE WebView::setPreferences( 
2248     /* [in] */ IWebPreferences* prefs)
2249 {
2250     if (m_preferences == prefs)
2251         return S_OK;
2252
2253     IWebNotificationCenter* nc = WebNotificationCenter::defaultCenterInternal();
2254     COMPtr<IWebPreferences> oldPrefs;
2255     if (SUCCEEDED(preferences(&oldPrefs)) && oldPrefs) {
2256         nc->removeObserver(this, WebPreferences::webPreferencesChangedNotification(), oldPrefs.get());
2257         BSTR identifier = 0;
2258         HRESULT hr = oldPrefs->identifier(&identifier);
2259         oldPrefs = 0;   // make sure we release the reference, since WebPreferences::removeReferenceForIdentifier will check for last reference to WebPreferences
2260         if (SUCCEEDED(hr))
2261             WebPreferences::removeReferenceForIdentifier(identifier);
2262         if (identifier)
2263             SysFreeString(identifier);
2264     }
2265     m_preferences = prefs;
2266     COMPtr<IWebPreferences> newPrefs;
2267     if (SUCCEEDED(preferences(&newPrefs)))
2268         nc->addObserver(this, WebPreferences::webPreferencesChangedNotification(), newPrefs.get());
2269     HRESULT hr = nc->postNotificationName(WebPreferences::webPreferencesChangedNotification(), newPrefs.get(), 0);
2270     if (FAILED(hr))
2271         return hr;
2272
2273     return S_OK;
2274 }
2275
2276 HRESULT STDMETHODCALLTYPE WebView::preferences( 
2277     /* [retval][out] */ IWebPreferences** prefs)
2278 {
2279     HRESULT hr = S_OK;
2280
2281     if (!m_preferences) {
2282         WebPreferences* instance = WebPreferences::createInstance();
2283         if (!instance)
2284             return E_FAIL;
2285         hr = instance->standardPreferences(&m_preferences);
2286         instance->Release();
2287     }
2288
2289     m_preferences.copyRefTo(prefs);
2290     return hr;
2291 }
2292
2293 HRESULT STDMETHODCALLTYPE WebView::setPreferencesIdentifier( 
2294     /* [in] */ BSTR /*anIdentifier*/)
2295 {
2296     ASSERT_NOT_REACHED();
2297     return E_NOTIMPL;
2298 }
2299
2300 HRESULT STDMETHODCALLTYPE WebView::preferencesIdentifier( 
2301     /* [retval][out] */ BSTR* /*anIdentifier*/)
2302 {
2303     ASSERT_NOT_REACHED();
2304     return E_NOTIMPL;
2305 }
2306
2307 HRESULT STDMETHODCALLTYPE WebView::setHostWindow( 
2308     /* [in] */ OLE_HANDLE oleWindow)
2309 {
2310     HWND window = (HWND)(ULONG64)oleWindow;
2311     if (m_viewWindow && window)
2312         SetParent(m_viewWindow, window);
2313
2314     m_hostWindow = window;
2315
2316     return S_OK;
2317 }
2318
2319 HRESULT STDMETHODCALLTYPE WebView::hostWindow( 
2320     /* [retval][out] */ OLE_HANDLE* window)
2321 {
2322     *window = (OLE_HANDLE)(ULONG64)m_hostWindow;
2323     return S_OK;
2324 }
2325
2326
2327 static Frame *incrementFrame(Frame *curr, bool forward, bool wrapFlag)
2328 {
2329     return forward
2330         ? curr->tree()->traverseNextWithWrap(wrapFlag)
2331         : curr->tree()->traversePreviousWithWrap(wrapFlag);
2332 }
2333
2334 HRESULT STDMETHODCALLTYPE WebView::searchFor( 
2335     /* [in] */ BSTR str,
2336     /* [in] */ BOOL forward,
2337     /* [in] */ BOOL caseFlag,
2338     /* [in] */ BOOL wrapFlag,
2339     /* [retval][out] */ BOOL* found)
2340 {
2341     if (!found)
2342         return E_INVALIDARG;
2343     
2344     if (!m_page || !m_page->mainFrame())
2345         return E_UNEXPECTED;
2346
2347     if (!str || !SysStringLen(str))
2348         return E_INVALIDARG;
2349
2350     String search(str, SysStringLen(str));
2351
2352
2353     WebCore::Frame* frame = m_page->focusController()->focusedOrMainFrame();
2354     WebCore::Frame* startFrame = frame;
2355     do {
2356         *found = frame->findString(search, !!forward, !!caseFlag, false, true);
2357         if (*found) {
2358             if (frame != startFrame)
2359                 startFrame->selectionController()->clear();
2360             m_page->focusController()->setFocusedFrame(frame);
2361             return S_OK;
2362         }
2363         frame = incrementFrame(frame, !!forward, !!wrapFlag);
2364     } while (frame && frame != startFrame);
2365
2366     // Search contents of startFrame, on the other side of the selection that we did earlier.
2367     // We cheat a bit and just research with wrap on
2368     if (wrapFlag && !startFrame->selectionController()->isNone()) {
2369         *found = startFrame->findString(search, !!forward, !!caseFlag, true, true);
2370         m_page->focusController()->setFocusedFrame(frame);
2371     }
2372
2373     return S_OK;
2374 }
2375
2376 HRESULT STDMETHODCALLTYPE WebView::updateActiveState()
2377 {
2378     Frame* frame = m_page->mainFrame();
2379
2380     HWND window = ::GetAncestor(m_viewWindow, GA_ROOT);
2381     HWND activeWindow = ::GetActiveWindow();
2382     bool windowIsKey = window == activeWindow;
2383     activeWindow = ::GetAncestor(activeWindow, GA_ROOTOWNER);
2384
2385     bool windowOrSheetIsKey = windowIsKey || (window == activeWindow);
2386
2387     frame->setIsActive(windowIsKey);            
2388
2389     Frame* focusedFrame = m_page->focusController()->focusedOrMainFrame();
2390     frame->setWindowHasFocus(frame == focusedFrame && windowOrSheetIsKey);
2391
2392     return S_OK;
2393 }
2394
2395 HRESULT STDMETHODCALLTYPE WebView::markAllMatchesForText(
2396     BSTR str, BOOL caseSensitive, BOOL highlight, UINT limit, UINT* matches)
2397 {
2398     if (!matches)
2399         return E_INVALIDARG;
2400
2401     if (!m_page || !m_page->mainFrame())
2402         return E_UNEXPECTED;
2403
2404     if (!str || !SysStringLen(str))
2405         return E_INVALIDARG;
2406
2407     String search(str, SysStringLen(str));
2408     *matches = 0;
2409
2410     WebCore::Frame* frame = m_page->mainFrame();
2411     do {
2412         frame->setMarkedTextMatchesAreHighlighted(!!highlight);
2413         *matches += frame->markAllMatchesForText(search, !!caseSensitive, (limit == 0)? 0 : (limit - *matches));
2414         frame = incrementFrame(frame, true, false);
2415     } while (frame);
2416
2417     return S_OK;
2418
2419 }
2420
2421 HRESULT STDMETHODCALLTYPE WebView::unmarkAllTextMatches()
2422 {
2423     if (!m_page || !m_page->mainFrame())
2424         return E_UNEXPECTED;
2425
2426     WebCore::Frame* frame = m_page->mainFrame();
2427     do {
2428         if (Document* document = frame->document())
2429             document->removeMarkers(DocumentMarker::TextMatch);
2430         frame = incrementFrame(frame, true, false);
2431     } while (frame);
2432
2433
2434     return S_OK;
2435 }
2436
2437 HRESULT STDMETHODCALLTYPE WebView::rectsForTextMatches(
2438     IEnumTextMatches** pmatches)
2439 {
2440     Vector<IntRect> allRects;
2441     WebCore::Frame* frame = m_page->mainFrame();
2442     do {
2443         if (Document* document = frame->document()) {
2444             Vector<IntRect> frameRects = document->renderedRectsForMarkers(DocumentMarker::TextMatch);
2445             IntPoint frameOffset(-frame->view()->scrollOffset().width(), -frame->view()->scrollOffset().height());
2446             frameOffset = frame->view()->convertToContainingWindow(frameOffset);
2447
2448             Vector<IntRect>::iterator end = frameRects.end();
2449             for (Vector<IntRect>::iterator it = frameRects.begin(); it < end; it++) {
2450                 it->move(frameOffset.x(), frameOffset.y());
2451                 allRects.append(*it);
2452             }
2453         }
2454         frame = incrementFrame(frame, true, false);
2455     } while (frame);
2456
2457     return createMatchEnumerator(&allRects, pmatches);
2458 }
2459
2460 HRESULT STDMETHODCALLTYPE WebView::generateSelectionImage(BOOL forceWhiteText, OLE_HANDLE* hBitmap)
2461 {
2462     *hBitmap = 0;
2463
2464     WebCore::Frame* frame = m_page->focusController()->focusedOrMainFrame();
2465
2466     if (frame) {
2467         HBITMAP bitmap = imageFromSelection(frame, forceWhiteText ? TRUE : FALSE);
2468         *hBitmap = (OLE_HANDLE)(ULONG64)bitmap;
2469     }
2470
2471     return S_OK;
2472 }
2473
2474 HRESULT STDMETHODCALLTYPE WebView::selectionImageRect(RECT* rc)
2475 {
2476     WebCore::Frame* frame = m_page->focusController()->focusedOrMainFrame();
2477
2478     if (frame) {
2479         IntRect ir = enclosingIntRect(frame->selectionRect());
2480         ir = frame->view()->convertToContainingWindow(ir);
2481         ir.move(-frame->view()->scrollOffset().width(), -frame->view()->scrollOffset().height());
2482         rc->left = ir.x();
2483         rc->top = ir.y();
2484         rc->bottom = rc->top + ir.height();
2485         rc->right = rc->left + ir.width();
2486     }
2487
2488     return S_OK;
2489 }
2490
2491 HRESULT STDMETHODCALLTYPE WebView::registerViewClass( 
2492     /* [in] */ IWebDocumentView* /*view*/,
2493     /* [in] */ IWebDocumentRepresentation* /*representation*/,
2494     /* [in] */ BSTR /*forMIMEType*/)
2495 {
2496     ASSERT_NOT_REACHED();
2497     return E_NOTIMPL;
2498 }
2499
2500 HRESULT STDMETHODCALLTYPE WebView::setGroupName( 
2501         /* [in] */ BSTR groupName)
2502 {
2503     m_groupName = String(groupName, SysStringLen(groupName));
2504     return S_OK;
2505 }
2506     
2507 HRESULT STDMETHODCALLTYPE WebView::groupName( 
2508         /* [retval][out] */ BSTR* groupName)
2509 {
2510     *groupName = SysAllocStringLen(m_groupName.characters(), m_groupName.length());
2511     if (!*groupName && m_groupName.length())
2512         return E_OUTOFMEMORY;
2513     return S_OK;
2514 }
2515     
2516 HRESULT STDMETHODCALLTYPE WebView::estimatedProgress( 
2517         /* [retval][out] */ double* estimatedProgress)
2518 {
2519     *estimatedProgress = m_page->progress()->estimatedProgress();
2520     return S_OK;
2521 }
2522     
2523 HRESULT STDMETHODCALLTYPE WebView::isLoading( 
2524         /* [retval][out] */ BOOL* isLoading)
2525 {
2526     COMPtr<IWebDataSource> dataSource;
2527     COMPtr<IWebDataSource> provisionalDataSource;
2528
2529     if (!isLoading)
2530         return E_POINTER;
2531
2532     *isLoading = FALSE;
2533
2534     if (SUCCEEDED(m_mainFrame->dataSource(&dataSource)))
2535         dataSource->isLoading(isLoading);
2536
2537     if (*isLoading)
2538         return S_OK;
2539
2540     if (SUCCEEDED(m_mainFrame->provisionalDataSource(&provisionalDataSource)))
2541         provisionalDataSource->isLoading(isLoading);
2542     return S_OK;
2543 }
2544     
2545 HRESULT STDMETHODCALLTYPE WebView::elementAtPoint( 
2546         /* [in] */ LPPOINT point,
2547         /* [retval][out] */ IPropertyBag** elementDictionary)
2548 {
2549     if (!elementDictionary) {
2550         ASSERT_NOT_REACHED();
2551         return E_POINTER;
2552     }
2553
2554     *elementDictionary = 0;
2555
2556     Frame* frame = core(m_mainFrame);
2557     if (!frame)
2558         return E_FAIL;
2559
2560     IntPoint webCorePoint = IntPoint(point->x, point->y);
2561     HitTestResult result = HitTestResult(webCorePoint);
2562     if (frame->renderer())
2563         result = frame->eventHandler()->hitTestResultAtPoint(webCorePoint, false);
2564     *elementDictionary = WebElementPropertyBag::createInstance(result);
2565     return S_OK;
2566 }
2567     
2568 HRESULT STDMETHODCALLTYPE WebView::pasteboardTypesForSelection( 
2569     /* [retval][out] */ IEnumVARIANT** /*enumVariant*/)
2570 {
2571     ASSERT_NOT_REACHED();
2572     return E_NOTIMPL;
2573 }
2574     
2575 HRESULT STDMETHODCALLTYPE WebView::writeSelectionWithPasteboardTypes( 
2576         /* [size_is][in] */ BSTR* /*types*/,
2577         /* [in] */ int /*cTypes*/,
2578         /* [in] */ IDataObject* /*pasteboard*/)
2579 {
2580     ASSERT_NOT_REACHED();
2581     return E_NOTIMPL;
2582 }
2583     
2584 HRESULT STDMETHODCALLTYPE WebView::pasteboardTypesForElement( 
2585     /* [in] */ IPropertyBag* /*elementDictionary*/,
2586     /* [retval][out] */ IEnumVARIANT** /*enumVariant*/)
2587 {
2588     ASSERT_NOT_REACHED();
2589     return E_NOTIMPL;
2590 }
2591     
2592 HRESULT STDMETHODCALLTYPE WebView::writeElement( 
2593         /* [in] */ IPropertyBag* /*elementDictionary*/,
2594         /* [size_is][in] */ BSTR* /*withPasteboardTypes*/,
2595         /* [in] */ int /*cWithPasteboardTypes*/,
2596         /* [in] */ IDataObject* /*pasteboard*/)
2597 {
2598     ASSERT_NOT_REACHED();
2599     return E_NOTIMPL;
2600 }
2601     
2602 HRESULT STDMETHODCALLTYPE WebView::selectedText(
2603         /* [out, retval] */ BSTR* text)
2604 {
2605     if (!text) {
2606         ASSERT_NOT_REACHED();
2607         return E_POINTER;
2608     }
2609
2610     *text = 0;
2611
2612     Frame* focusedFrame = (m_page && m_page->focusController()) ? m_page->focusController()->focusedOrMainFrame() : 0;
2613     if (!focusedFrame)
2614         return E_FAIL;
2615
2616     String frameSelectedText = focusedFrame->selectedText();
2617     *text = SysAllocStringLen(frameSelectedText.characters(), frameSelectedText.length());
2618     if (!*text && frameSelectedText.length())
2619         return E_OUTOFMEMORY;
2620     return S_OK;
2621 }
2622
2623 HRESULT STDMETHODCALLTYPE WebView::centerSelectionInVisibleArea(
2624         /* [in] */ IUnknown* /* sender */)
2625 {
2626     Frame* coreFrame = core(m_mainFrame);
2627     if (!coreFrame)
2628         return E_FAIL;
2629
2630     coreFrame->revealSelection(RenderLayer::gAlignCenterAlways);
2631     return S_OK;
2632 }
2633
2634
2635 HRESULT STDMETHODCALLTYPE WebView::moveDragCaretToPoint( 
2636         /* [in] */ LPPOINT /*point*/)
2637 {
2638     ASSERT_NOT_REACHED();
2639     return E_NOTIMPL;
2640 }
2641     
2642 HRESULT STDMETHODCALLTYPE WebView::removeDragCaret( void)
2643 {
2644     ASSERT_NOT_REACHED();
2645     return E_NOTIMPL;
2646 }
2647     
2648 HRESULT STDMETHODCALLTYPE WebView::setDrawsBackground( 
2649         /* [in] */ BOOL /*drawsBackground*/)
2650 {
2651     ASSERT_NOT_REACHED();
2652     return E_NOTIMPL;
2653 }
2654     
2655 HRESULT STDMETHODCALLTYPE WebView::drawsBackground( 
2656         /* [retval][out] */ BOOL* /*drawsBackground*/)
2657 {
2658     ASSERT_NOT_REACHED();
2659     return E_NOTIMPL;
2660 }
2661     
2662 HRESULT STDMETHODCALLTYPE WebView::setMainFrameURL( 
2663         /* [in] */ BSTR /*urlString*/)
2664 {
2665     ASSERT_NOT_REACHED();
2666     return E_NOTIMPL;
2667 }
2668     
2669 HRESULT STDMETHODCALLTYPE WebView::mainFrameURL( 
2670         /* [retval][out] */ BSTR* /*urlString*/)
2671 {
2672     ASSERT_NOT_REACHED();
2673     return E_NOTIMPL;
2674 }
2675     
2676 HRESULT STDMETHODCALLTYPE WebView::mainFrameDocument( 
2677         /* [retval][out] */ IDOMDocument** document)
2678 {
2679     if (document)
2680         *document = 0;
2681     if (!m_mainFrame)
2682         return E_FAIL;
2683     return m_mainFrame->DOMDocument(document);
2684 }
2685     
2686 HRESULT STDMETHODCALLTYPE WebView::mainFrameTitle( 
2687         /* [retval][out] */ BSTR* /*title*/)
2688 {
2689     ASSERT_NOT_REACHED();
2690     return E_NOTIMPL;
2691 }
2692     
2693 HRESULT STDMETHODCALLTYPE WebView::mainFrameIcon( 
2694         /* [retval][out] */ OLE_HANDLE* /*hBitmap*/)
2695 {
2696     ASSERT_NOT_REACHED();
2697     return E_NOTIMPL;
2698 }
2699
2700 // IWebIBActions ---------------------------------------------------------------
2701
2702 HRESULT STDMETHODCALLTYPE WebView::takeStringURLFrom( 
2703         /* [in] */ IUnknown* /*sender*/)
2704 {
2705     ASSERT_NOT_REACHED();
2706     return E_NOTIMPL;
2707 }
2708     
2709 HRESULT STDMETHODCALLTYPE WebView::stopLoading( 
2710         /* [in] */ IUnknown* /*sender*/)
2711 {
2712     if (!m_mainFrame)
2713         return E_FAIL;
2714
2715     return m_mainFrame->stopLoading();
2716 }
2717     
2718 HRESULT STDMETHODCALLTYPE WebView::reload( 
2719         /* [in] */ IUnknown* /*sender*/)
2720 {
2721     if (!m_mainFrame)
2722         return E_FAIL;
2723
2724     return m_mainFrame->reload();
2725 }
2726     
2727 HRESULT STDMETHODCALLTYPE WebView::canGoBack( 
2728         /* [in] */ IUnknown* /*sender*/,
2729         /* [retval][out] */ BOOL* result)
2730 {
2731     *result = !!m_page->backForwardList()->backItem();
2732     return S_OK;
2733 }
2734     
2735 HRESULT STDMETHODCALLTYPE WebView::goBack( 
2736         /* [in] */ IUnknown* /*sender*/)
2737 {
2738     ASSERT_NOT_REACHED();
2739     return E_NOTIMPL;
2740 }
2741     
2742 HRESULT STDMETHODCALLTYPE WebView::canGoForward( 
2743         /* [in] */ IUnknown* /*sender*/,
2744         /* [retval][out] */ BOOL* result)
2745 {
2746     *result = !!m_page->backForwardList()->forwardItem();
2747     return S_OK;
2748 }
2749     
2750 HRESULT STDMETHODCALLTYPE WebView::goForward( 
2751         /* [in] */ IUnknown* /*sender*/)
2752 {
2753     ASSERT_NOT_REACHED();
2754     return E_NOTIMPL;
2755 }
2756
2757 #define MinimumTextSizeMultiplier   0.5f
2758 #define MaximumTextSizeMultiplier   3.0f
2759 #define TextSizeMultiplierRatio     1.2f
2760
2761 HRESULT STDMETHODCALLTYPE WebView::canMakeTextLarger( 
2762         /* [in] */ IUnknown* /*sender*/,
2763         /* [retval][out] */ BOOL* result)
2764 {
2765     bool canGrowMore = m_textSizeMultiplier*TextSizeMultiplierRatio < MaximumTextSizeMultiplier;
2766     *result = canGrowMore ? TRUE : FALSE;
2767     return S_OK;
2768 }
2769     
2770 HRESULT STDMETHODCALLTYPE WebView::makeTextLarger( 
2771         /* [in] */ IUnknown* /*sender*/)
2772 {
2773     float newScale = m_textSizeMultiplier*TextSizeMultiplierRatio;
2774     bool canGrowMore = newScale < MaximumTextSizeMultiplier;
2775     if (!canGrowMore)
2776         return E_FAIL;
2777     return setTextSizeMultiplier(newScale);
2778
2779 }
2780     
2781 HRESULT STDMETHODCALLTYPE WebView::canMakeTextSmaller( 
2782         /* [in] */ IUnknown* /*sender*/,
2783         /* [retval][out] */ BOOL* result)
2784 {
2785     bool canShrinkMore = m_textSizeMultiplier/TextSizeMultiplierRatio > MinimumTextSizeMultiplier;
2786     *result = canShrinkMore ? TRUE : FALSE;
2787     return S_OK;
2788 }
2789
2790 HRESULT STDMETHODCALLTYPE WebView::makeTextSmaller( 
2791         /* [in] */ IUnknown* /*sender*/)
2792 {
2793     float newScale = m_textSizeMultiplier/TextSizeMultiplierRatio;
2794     bool canShrinkMore = newScale > MinimumTextSizeMultiplier;
2795     if (!canShrinkMore)
2796         return E_FAIL;
2797     return setTextSizeMultiplier(newScale);
2798 }
2799
2800 HRESULT STDMETHODCALLTYPE WebView::canMakeTextStandardSize( 
2801     /* [in] */ IUnknown* /*sender*/,
2802     /* [retval][out] */ BOOL* result)
2803 {
2804     bool notAlreadyStandard = m_textSizeMultiplier != 1.0f;
2805     *result = notAlreadyStandard ? TRUE : FALSE;
2806     return S_OK;
2807 }
2808
2809 HRESULT STDMETHODCALLTYPE WebView::makeTextStandardSize( 
2810     /* [in] */ IUnknown* /*sender*/)
2811 {
2812     bool notAlreadyStandard = m_textSizeMultiplier != 1.0f;
2813     if (notAlreadyStandard)
2814         return setTextSizeMultiplier(1.0f);
2815     return S_OK;
2816 }
2817
2818 HRESULT STDMETHODCALLTYPE WebView::toggleContinuousSpellChecking( 
2819     /* [in] */ IUnknown* /*sender*/)
2820 {
2821     HRESULT hr;
2822     BOOL enabled;
2823     if (FAILED(hr = isContinuousSpellCheckingEnabled(&enabled)))
2824         return hr;
2825     return setContinuousSpellCheckingEnabled(enabled ? FALSE : TRUE);
2826 }
2827
2828 HRESULT STDMETHODCALLTYPE WebView::toggleSmartInsertDelete( 
2829     /* [in] */ IUnknown* /*sender*/)
2830 {
2831     BOOL enabled = FALSE;
2832     HRESULT hr = smartInsertDeleteEnabled(&enabled);
2833     if (FAILED(hr))
2834         return hr;
2835
2836     return setSmartInsertDeleteEnabled(enabled ? FALSE : TRUE);
2837 }
2838
2839 HRESULT STDMETHODCALLTYPE WebView::toggleGrammarChecking( 
2840     /* [in] */ IUnknown* /*sender*/)
2841 {
2842     BOOL enabled;
2843     HRESULT hr = isGrammarCheckingEnabled(&enabled);
2844     if (FAILED(hr))
2845         return hr;
2846
2847     return setGrammarCheckingEnabled(enabled ? FALSE : TRUE);
2848 }
2849
2850 // IWebViewCSS -----------------------------------------------------------------
2851
2852 HRESULT STDMETHODCALLTYPE WebView::computedStyleForElement( 
2853         /* [in] */ IDOMElement* /*element*/,
2854         /* [in] */ BSTR /*pseudoElement*/,
2855         /* [retval][out] */ IDOMCSSStyleDeclaration** /*style*/)
2856 {
2857     ASSERT_NOT_REACHED();
2858     return E_NOTIMPL;
2859 }
2860
2861 // IWebViewEditing -------------------------------------------------------------
2862
2863 HRESULT STDMETHODCALLTYPE WebView::editableDOMRangeForPoint( 
2864         /* [in] */ LPPOINT /*point*/,
2865         /* [retval][out] */ IDOMRange** /*range*/)
2866 {
2867     ASSERT_NOT_REACHED();
2868     return E_NOTIMPL;
2869 }
2870     
2871 HRESULT STDMETHODCALLTYPE WebView::setSelectedDOMRange( 
2872         /* [in] */ IDOMRange* /*range*/,
2873         /* [in] */ WebSelectionAffinity /*affinity*/)
2874 {
2875     ASSERT_NOT_REACHED();
2876     return E_NOTIMPL;
2877 }
2878     
2879 HRESULT STDMETHODCALLTYPE WebView::selectedDOMRange( 
2880         /* [retval][out] */ IDOMRange** /*range*/)
2881 {
2882     ASSERT_NOT_REACHED();
2883     return E_NOTIMPL;
2884 }
2885     
2886 HRESULT STDMETHODCALLTYPE WebView::selectionAffinity( 
2887         /* [retval][out][retval][out] */ WebSelectionAffinity* /*affinity*/)
2888 {
2889     ASSERT_NOT_REACHED();
2890     return E_NOTIMPL;
2891 }
2892     
2893 HRESULT STDMETHODCALLTYPE WebView::setEditable( 
2894         /* [in] */ BOOL /*flag*/)
2895 {
2896     ASSERT_NOT_REACHED();
2897     return E_NOTIMPL;
2898 }
2899     
2900 HRESULT STDMETHODCALLTYPE WebView::isEditable( 
2901         /* [retval][out] */ BOOL* /*isEditable*/)
2902 {
2903     ASSERT_NOT_REACHED();
2904     return E_NOTIMPL;
2905 }
2906     
2907 HRESULT STDMETHODCALLTYPE WebView::setTypingStyle( 
2908         /* [in] */ IDOMCSSStyleDeclaration* /*style*/)
2909 {
2910     ASSERT_NOT_REACHED();
2911     return E_NOTIMPL;
2912 }
2913     
2914 HRESULT STDMETHODCALLTYPE WebView::typingStyle( 
2915         /* [retval][out] */ IDOMCSSStyleDeclaration** /*style*/)
2916 {
2917     ASSERT_NOT_REACHED();
2918     return E_NOTIMPL;
2919 }
2920     
2921 HRESULT STDMETHODCALLTYPE WebView::setSmartInsertDeleteEnabled( 
2922         /* [in] */ BOOL flag)
2923 {
2924     m_smartInsertDeleteEnabled = !!flag;
2925     return S_OK;
2926 }
2927     
2928 HRESULT STDMETHODCALLTYPE WebView::smartInsertDeleteEnabled( 
2929         /* [retval][out] */ BOOL* enabled)
2930 {
2931     *enabled = m_smartInsertDeleteEnabled ? TRUE : FALSE;
2932     return S_OK;
2933 }
2934     
2935 HRESULT STDMETHODCALLTYPE WebView::setContinuousSpellCheckingEnabled( 
2936         /* [in] */ BOOL flag)
2937 {
2938     if (continuousSpellCheckingEnabled != !!flag) {
2939         continuousSpellCheckingEnabled = !!flag;
2940         COMPtr<IWebPreferences> prefs;
2941         if (SUCCEEDED(preferences(&prefs)))
2942             prefs->setContinuousSpellCheckingEnabled(flag);
2943     }
2944     
2945     BOOL spellCheckingEnabled;
2946     if (SUCCEEDED(isContinuousSpellCheckingEnabled(&spellCheckingEnabled)) && spellCheckingEnabled)
2947         preflightSpellChecker();
2948     else
2949         m_mainFrame->unmarkAllMisspellings();
2950
2951     return S_OK;
2952 }
2953     
2954 HRESULT STDMETHODCALLTYPE WebView::isContinuousSpellCheckingEnabled( 
2955         /* [retval][out] */ BOOL* enabled)
2956 {
2957     *enabled = (continuousSpellCheckingEnabled && continuousCheckingAllowed()) ? TRUE : FALSE;
2958     return S_OK;
2959 }
2960     
2961 HRESULT STDMETHODCALLTYPE WebView::spellCheckerDocumentTag( 
2962         /* [retval][out] */ int* tag)
2963 {
2964     // we just use this as a flag to indicate that we've spell checked the document
2965     // and need to close the spell checker out when the view closes.
2966     *tag = 0;
2967     m_hasSpellCheckerDocumentTag = true;
2968     return S_OK;
2969 }
2970
2971 static COMPtr<IWebEditingDelegate> spellingDelegateForTimer;
2972
2973 static void preflightSpellCheckerNow()
2974 {
2975     spellingDelegateForTimer->preflightChosenSpellServer();
2976     spellingDelegateForTimer = 0;
2977 }
2978
2979 static void CALLBACK preflightSpellCheckerTimerCallback(HWND, UINT, UINT_PTR id, DWORD)
2980 {
2981     ::KillTimer(0, id);
2982     preflightSpellCheckerNow();
2983 }
2984
2985 void WebView::preflightSpellChecker()
2986 {
2987     // As AppKit does, we wish to delay tickling the shared spellchecker into existence on application launch.
2988     if (!m_editingDelegate)
2989         return;
2990
2991     BOOL exists;
2992     spellingDelegateForTimer = m_editingDelegate;
2993     if (SUCCEEDED(m_editingDelegate->sharedSpellCheckerExists(&exists)) && exists)
2994         preflightSpellCheckerNow();
2995     else
2996         ::SetTimer(0, 0, 2000, preflightSpellCheckerTimerCallback);
2997 }
2998
2999 bool WebView::continuousCheckingAllowed()
3000 {
3001     static bool allowContinuousSpellChecking = true;
3002     static bool readAllowContinuousSpellCheckingDefault = false;
3003     if (!readAllowContinuousSpellCheckingDefault) {
3004         COMPtr<IWebPreferences> prefs;
3005         if (SUCCEEDED(preferences(&prefs))) {
3006             BOOL allowed;
3007             prefs->allowContinuousSpellChecking(&allowed);
3008             allowContinuousSpellChecking = !!allowed;
3009         }
3010         readAllowContinuousSpellCheckingDefault = true;
3011     }
3012     return allowContinuousSpellChecking;
3013 }
3014
3015 HRESULT STDMETHODCALLTYPE WebView::undoManager( 
3016         /* [retval][out] */ IWebUndoManager** /*manager*/)
3017 {
3018     ASSERT_NOT_REACHED();
3019     return E_NOTIMPL;
3020 }
3021     
3022 HRESULT STDMETHODCALLTYPE WebView::setEditingDelegate( 
3023         /* [in] */ IWebEditingDelegate* d)
3024 {
3025     m_editingDelegate = d;
3026     return S_OK;
3027 }
3028     
3029 HRESULT STDMETHODCALLTYPE WebView::editingDelegate( 
3030         /* [retval][out] */ IWebEditingDelegate** d)
3031 {
3032     if (!d) {
3033         ASSERT_NOT_REACHED();
3034         return E_POINTER;
3035     }
3036
3037     *d = m_editingDelegate.get();
3038     if (!*d)
3039         return E_FAIL;
3040
3041     (*d)->AddRef();
3042     return S_OK;
3043 }
3044     
3045 HRESULT STDMETHODCALLTYPE WebView::styleDeclarationWithText( 
3046         /* [in] */ BSTR /*text*/,
3047         /* [retval][out] */ IDOMCSSStyleDeclaration** /*style*/)
3048 {
3049     ASSERT_NOT_REACHED();
3050     return E_NOTIMPL;
3051 }
3052     
3053 HRESULT STDMETHODCALLTYPE WebView::hasSelectedRange( 
3054         /* [retval][out] */ BOOL* hasSelectedRange)
3055 {
3056     *hasSelectedRange = m_page->mainFrame()->selectionController()->isRange();
3057     return S_OK;
3058 }
3059     
3060 HRESULT STDMETHODCALLTYPE WebView::cutEnabled( 
3061         /* [retval][out] */ BOOL* enabled)
3062 {
3063     Editor* editor = m_page->focusController()->focusedOrMainFrame()->editor();
3064     *enabled = editor->canCut() || editor->canDHTMLCut();
3065     return S_OK;
3066 }
3067     
3068 HRESULT STDMETHODCALLTYPE WebView::copyEnabled( 
3069         /* [retval][out] */ BOOL* enabled)
3070 {
3071     Editor* editor = m_page->focusController()->focusedOrMainFrame()->editor();
3072     *enabled = editor->canCopy() || editor->canDHTMLCopy();
3073     return S_OK;
3074 }
3075     
3076 HRESULT STDMETHODCALLTYPE WebView::pasteEnabled( 
3077         /* [retval][out] */ BOOL* enabled)
3078 {
3079     Editor* editor = m_page->focusController()->focusedOrMainFrame()->editor();
3080     *enabled = editor->canPaste() || editor->canDHTMLPaste();
3081     return S_OK;
3082 }
3083     
3084 HRESULT STDMETHODCALLTYPE WebView::deleteEnabled( 
3085         /* [retval][out] */ BOOL* enabled)
3086 {
3087     *enabled = m_page->focusController()->focusedOrMainFrame()->editor()->canDelete();
3088     return S_OK;
3089 }
3090     
3091 HRESULT STDMETHODCALLTYPE WebView::editingEnabled( 
3092         /* [retval][out] */ BOOL* enabled)
3093 {
3094     *enabled = m_page->focusController()->focusedOrMainFrame()->editor()->canEdit();
3095     return S_OK;
3096 }
3097
3098 HRESULT STDMETHODCALLTYPE WebView::isGrammarCheckingEnabled( 
3099     /* [retval][out] */ BOOL* enabled)
3100 {
3101     *enabled = grammarCheckingEnabled ? TRUE : FALSE;
3102     return S_OK;
3103 }
3104
3105 HRESULT STDMETHODCALLTYPE WebView::setGrammarCheckingEnabled( 
3106     BOOL enabled)
3107 {
3108     if (grammarCheckingEnabled == !!enabled)
3109         return S_OK;
3110     
3111     grammarCheckingEnabled = !!enabled;
3112     COMPtr<IWebPreferences> prefs;
3113     if (SUCCEEDED(preferences(&prefs)))
3114         prefs->setGrammarCheckingEnabled(enabled);
3115     
3116     m_editingDelegate->updateGrammar();
3117
3118     // We call _preflightSpellChecker when turning continuous spell checking on, but we don't need to do that here
3119     // because grammar checking only occurs on code paths that already preflight spell checking appropriately.
3120     
3121     BOOL grammarEnabled;
3122     if (SUCCEEDED(isGrammarCheckingEnabled(&grammarEnabled)) && !grammarEnabled)
3123         m_mainFrame->unmarkAllBadGrammar();
3124
3125     return S_OK;
3126 }
3127
3128 // IWebViewUndoableEditing -----------------------------------------------------
3129
3130 HRESULT STDMETHODCALLTYPE WebView::replaceSelectionWithNode( 
3131         /* [in] */ IDOMNode* /*node*/)
3132 {
3133     ASSERT_NOT_REACHED();
3134     return E_NOTIMPL;
3135 }
3136     
3137 HRESULT STDMETHODCALLTYPE WebView::replaceSelectionWithText( 
3138         /* [in] */ BSTR text)
3139 {
3140     String textString(text, ::SysStringLen(text));
3141     Position start = m_page->mainFrame()->selectionController()->selection().start();
3142     m_page->focusController()->focusedOrMainFrame()->editor()->insertText(textString, 0);
3143     m_page->mainFrame()->selectionController()->setBase(start);
3144     return S_OK;
3145 }
3146     
3147 HRESULT STDMETHODCALLTYPE WebView::replaceSelectionWithMarkupString( 
3148         /* [in] */ BSTR /*markupString*/)
3149 {
3150     ASSERT_NOT_REACHED();
3151     return E_NOTIMPL;
3152 }
3153     
3154 HRESULT STDMETHODCALLTYPE WebView::replaceSelectionWithArchive( 
3155         /* [in] */ IWebArchive* /*archive*/)
3156 {
3157     ASSERT_NOT_REACHED();
3158     return E_NOTIMPL;
3159 }
3160     
3161 HRESULT STDMETHODCALLTYPE WebView::deleteSelection( void)
3162 {
3163     m_page->focusController()->focusedOrMainFrame()->editor()->deleteSelectionWithSmartDelete();
3164     return S_OK;
3165 }
3166
3167 HRESULT STDMETHODCALLTYPE WebView::clearSelection( void)
3168 {
3169     m_page->focusController()->focusedOrMainFrame()->selectionController()->clear();
3170     return S_OK;
3171 }
3172     
3173 HRESULT STDMETHODCALLTYPE WebView::applyStyle( 
3174         /* [in] */ IDOMCSSStyleDeclaration* /*style*/)
3175 {
3176     ASSERT_NOT_REACHED();
3177     return E_NOTIMPL;
3178 }
3179
3180 // IWebViewEditingActions ------------------------------------------------------
3181
3182 HRESULT STDMETHODCALLTYPE WebView::copy( 
3183         /* [in] */ IUnknown* /*sender*/)
3184 {
3185     m_page->focusController()->focusedOrMainFrame()->editor()->execCommand("Copy");
3186     return S_OK;
3187 }
3188
3189 HRESULT STDMETHODCALLTYPE WebView::cut( 
3190         /* [in] */ IUnknown* /*sender*/)
3191 {
3192     m_page->focusController()->focusedOrMainFrame()->editor()->execCommand("Cut");
3193     return S_OK;
3194 }
3195
3196 HRESULT STDMETHODCALLTYPE WebView::paste( 
3197         /* [in] */ IUnknown* /*sender*/)
3198 {
3199     m_page->focusController()->focusedOrMainFrame()->editor()->execCommand("Paste");
3200     return S_OK;
3201 }
3202
3203 HRESULT STDMETHODCALLTYPE WebView::copyURL( 
3204         /* [in] */ BSTR url)
3205 {
3206     String temp(url, SysStringLen(url));
3207     m_page->focusController()->focusedOrMainFrame()->editor()->copyURL(KURL(temp.deprecatedString()), "");
3208     return S_OK;
3209 }
3210
3211
3212 HRESULT STDMETHODCALLTYPE WebView::copyFont( 
3213         /* [in] */ IUnknown* /*sender*/)
3214 {
3215     ASSERT_NOT_REACHED();
3216     return E_NOTIMPL;
3217 }
3218     
3219 HRESULT STDMETHODCALLTYPE WebView::pasteFont( 
3220         /* [in] */ IUnknown* /*sender*/)
3221 {
3222     ASSERT_NOT_REACHED();
3223     return E_NOTIMPL;
3224 }
3225     
3226 HRESULT STDMETHODCALLTYPE WebView::delete_( 
3227         /* [in] */ IUnknown* /*sender*/)
3228 {
3229     m_page->focusController()->focusedOrMainFrame()->editor()->execCommand("Delete");
3230     return S_OK;
3231 }
3232     
3233 HRESULT STDMETHODCALLTYPE WebView::pasteAsPlainText( 
3234         /* [in] */ IUnknown* /*sender*/)
3235 {
3236     ASSERT_NOT_REACHED();
3237     return E_NOTIMPL;
3238 }
3239     
3240 HRESULT STDMETHODCALLTYPE WebView::pasteAsRichText( 
3241         /* [in] */ IUnknown* /*sender*/)
3242 {
3243     ASSERT_NOT_REACHED();
3244     return E_NOTIMPL;
3245 }
3246     
3247 HRESULT STDMETHODCALLTYPE WebView::changeFont( 
3248         /* [in] */ IUnknown* /*sender*/)
3249 {
3250     ASSERT_NOT_REACHED();
3251     return E_NOTIMPL;
3252 }
3253     
3254 HRESULT STDMETHODCALLTYPE WebView::changeAttributes( 
3255         /* [in] */ IUnknown* /*sender*/)
3256 {
3257     ASSERT_NOT_REACHED();
3258     return E_NOTIMPL;
3259 }
3260     
3261 HRESULT STDMETHODCALLTYPE WebView::changeDocumentBackgroundColor( 
3262         /* [in] */ IUnknown* /*sender*/)
3263 {
3264     ASSERT_NOT_REACHED();
3265     return E_NOTIMPL;
3266 }
3267     
3268 HRESULT STDMETHODCALLTYPE WebView::changeColor( 
3269         /* [in] */ IUnknown* /*sender*/)
3270 {
3271     ASSERT_NOT_REACHED();
3272     return E_NOTIMPL;
3273 }
3274     
3275 HRESULT STDMETHODCALLTYPE WebView::alignCenter( 
3276         /* [in] */ IUnknown* /*sender*/)
3277 {
3278     ASSERT_NOT_REACHED();
3279     return E_NOTIMPL;
3280 }
3281     
3282 HRESULT STDMETHODCALLTYPE WebView::alignJustified( 
3283         /* [in] */ IUnknown* /*sender*/)
3284 {
3285     ASSERT_NOT_REACHED();
3286     return E_NOTIMPL;
3287 }
3288     
3289 HRESULT STDMETHODCALLTYPE WebView::alignLeft( 
3290         /* [in] */ IUnknown* /*sender*/)
3291 {
3292     ASSERT_NOT_REACHED();
3293     return E_NOTIMPL;
3294 }
3295     
3296 HRESULT STDMETHODCALLTYPE WebView::alignRight( 
3297         /* [in] */ IUnknown* /*sender*/)
3298 {
3299     ASSERT_NOT_REACHED();
3300     return E_NOTIMPL;
3301 }
3302     
3303 HRESULT STDMETHODCALLTYPE WebView::checkSpelling( 
3304         /* [in] */ IUnknown* /*sender*/)
3305 {
3306     if (!m_editingDelegate) {
3307         LOG_ERROR("No NSSpellChecker");
3308         return E_FAIL;
3309     }
3310     
3311     core(m_mainFrame)->editor()->advanceToNextMisspelling();
3312     return S_OK;
3313 }
3314     
3315 HRESULT STDMETHODCALLTYPE WebView::showGuessPanel( 
3316         /* [in] */ IUnknown* /*sender*/)
3317 {
3318     if (!m_editingDelegate) {
3319         LOG_ERROR("No NSSpellChecker");
3320         return E_FAIL;
3321     }
3322     
3323     // Post-Tiger, this menu item is a show/hide toggle, to match AppKit. Leave Tiger behavior alone
3324     // to match rest of OS X.
3325     BOOL showing;
3326     if (SUCCEEDED(m_editingDelegate->spellingUIIsShowing(&showing)) && showing) {
3327         m_editingDelegate->showSpellingUI(FALSE);
3328     }
3329     
3330     core(m_mainFrame)->editor()->advanceToNextMisspelling(true);
3331     m_editingDelegate->showSpellingUI(TRUE);
3332     return S_OK;
3333 }
3334     
3335 HRESULT STDMETHODCALLTYPE WebView::performFindPanelAction( 
3336         /* [in] */ IUnknown* /*sender*/)
3337 {
3338     ASSERT_NOT_REACHED();
3339     return E_NOTIMPL;
3340 }
3341     
3342 HRESULT STDMETHODCALLTYPE WebView::startSpeaking( 
3343         /* [in] */ IUnknown* /*sender*/)
3344 {
3345     ASSERT_NOT_REACHED();
3346     return E_NOTIMPL;
3347 }
3348     
3349 HRESULT STDMETHODCALLTYPE WebView::stopSpeaking( 
3350         /* [in] */ IUnknown* /*sender*/)
3351 {
3352     ASSERT_NOT_REACHED();
3353     return E_NOTIMPL;
3354 }
3355
3356 // IWebNotificationObserver -----------------------------------------------------------------
3357
3358 HRESULT STDMETHODCALLTYPE WebView::onNotify( 
3359     /* [in] */ IWebNotification* notification)
3360 {
3361     COMPtr<IUnknown> unkPrefs;
3362     HRESULT hr = notification->getObject(&unkPrefs);
3363     if (FAILED(hr))
3364         return hr;
3365
3366     COMPtr<IWebPreferences> preferences;
3367     hr = unkPrefs->QueryInterface(IID_IWebPreferences, (void**)&preferences);
3368     if (FAILED(hr))
3369         return hr;
3370
3371     hr = updateWebCoreSettingsFromPreferences(preferences.get());
3372
3373     return hr;
3374 }
3375
3376 // IWebViewPrivate ------------------------------------------------------------
3377
3378 HRESULT STDMETHODCALLTYPE WebView::setInViewSourceMode( 
3379         /* [in] */ BOOL flag)
3380 {
3381     if (!m_mainFrame)
3382         return E_FAIL;
3383
3384     return m_mainFrame->setInViewSourceMode(flag);
3385 }
3386     
3387 HRESULT STDMETHODCALLTYPE WebView::inViewSourceMode( 
3388         /* [retval][out] */ BOOL* flag)
3389 {
3390     if (!m_mainFrame)
3391         return E_FAIL;
3392
3393     return m_mainFrame->inViewSourceMode(flag);
3394 }
3395
3396 HRESULT STDMETHODCALLTYPE WebView::viewWindow( 
3397         /* [retval][out] */ OLE_HANDLE *window)
3398 {
3399     *window = (OLE_HANDLE)(ULONG64)m_viewWindow;
3400     return S_OK;
3401 }
3402
3403 HRESULT STDMETHODCALLTYPE WebView::setFormDelegate( 
3404     /* [in] */ IWebFormDelegate *formDelegate)
3405 {
3406     m_formDelegate = formDelegate;
3407     return S_OK;
3408 }
3409
3410 HRESULT STDMETHODCALLTYPE WebView::formDelegate( 
3411     /* [retval][out] */ IWebFormDelegate **formDelegate)
3412 {
3413     if (!m_formDelegate)
3414         return E_FAIL;
3415
3416     return m_formDelegate.copyRefTo(formDelegate);
3417 }
3418
3419 HRESULT STDMETHODCALLTYPE WebView::setFrameLoadDelegatePrivate( 
3420     /* [in] */ IWebFrameLoadDelegatePrivate* d)
3421 {
3422     m_frameLoadDelegatePrivate = d;
3423     return S_OK;
3424 }
3425
3426 HRESULT STDMETHODCALLTYPE WebView::frameLoadDelegatePrivate( 
3427     /* [out][retval] */ IWebFrameLoadDelegatePrivate** d)
3428 {
3429     if (!m_frameLoadDelegatePrivate)
3430         return E_FAIL;
3431         
3432     return m_frameLoadDelegatePrivate.copyRefTo(d);
3433 }
3434
3435 HRESULT STDMETHODCALLTYPE WebView::scrollOffset( 
3436     /* [retval][out] */ LPPOINT offset)
3437 {
3438     if (!offset)
3439         return E_POINTER;
3440     IntSize offsetIntSize = m_page->mainFrame()->view()->scrollOffset();
3441     offset->x = offsetIntSize.width();
3442     offset->y = offsetIntSize.height();
3443     return S_OK;
3444 }
3445
3446 HRESULT STDMETHODCALLTYPE WebView::scrollBy( 
3447     /* [in] */ LPPOINT offset)
3448 {
3449     if (!offset)
3450         return E_POINTER;
3451     m_page->mainFrame()->view()->scrollBy(offset->x, offset->y);
3452     return S_OK;
3453 }
3454
3455 HRESULT STDMETHODCALLTYPE WebView::visibleContentRect( 
3456     /* [retval][out] */ LPRECT rect)
3457 {
3458     if (!rect)
3459         return E_POINTER;
3460     FloatRect visibleContent = m_page->mainFrame()->view()->visibleContentRect();
3461     rect->left = (LONG) visibleContent.x();
3462     rect->top = (LONG) visibleContent.y();
3463     rect->right = (LONG) visibleContent.right();
3464     rect->bottom = (LONG) visibleContent.bottom();
3465     return S_OK;
3466 }
3467
3468 static DWORD dragOperationToDragCursor(DragOperation op) {
3469     DWORD res = DROPEFFECT_NONE;
3470     if (op & DragOperationCopy) 
3471         res = DROPEFFECT_COPY;
3472     else if (op & DragOperationLink) 
3473         res = DROPEFFECT_LINK;
3474     else if (op & DragOperationMove) 
3475         res = DROPEFFECT_MOVE;
3476     else if (op & DragOperationGeneric) 
3477         res = DROPEFFECT_MOVE; //This appears to be the Firefox behaviour
3478     return res;
3479 }
3480
3481 static DragOperation keyStateToDragOperation(DWORD) {
3482     //FIXME: This is currently very simple, it may need to actually
3483     //work out an appropriate DragOperation in future -- however this
3484     //behaviour appears to match FireFox
3485     return (DragOperation)(DragOperationCopy | DragOperationLink);
3486 }
3487
3488 HRESULT STDMETHODCALLTYPE WebView::DragEnter(
3489         IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
3490 {
3491     m_dragData = 0;
3492
3493     if (m_dropTargetHelper)
3494         m_dropTargetHelper->DragEnter(m_viewWindow, pDataObject, (POINT*)&pt, *pdwEffect);
3495
3496     POINTL localpt = pt;
3497     ::ScreenToClient(m_viewWindow, (LPPOINT)&localpt);
3498     DragData data(pDataObject, IntPoint(localpt.x, localpt.y), 
3499         IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
3500     *pdwEffect = dragOperationToDragCursor(m_page->dragController()->dragEntered(&data));
3501
3502     m_dragData = pDataObject;
3503
3504     return S_OK;
3505 }
3506
3507 HRESULT STDMETHODCALLTYPE WebView::DragOver(
3508         DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
3509 {
3510     if (m_dropTargetHelper)
3511         m_dropTargetHelper->DragOver((POINT*)&pt, *pdwEffect);
3512
3513     if (m_dragData) {
3514         POINTL localpt = pt;
3515         ::ScreenToClient(m_viewWindow, (LPPOINT)&localpt);
3516         DragData data(m_dragData.get(), IntPoint(localpt.x, localpt.y), 
3517             IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
3518         *pdwEffect = dragOperationToDragCursor(m_page->dragController()->dragUpdated(&data));
3519     } else
3520         *pdwEffect = DROPEFFECT_NONE;
3521
3522     return S_OK;
3523 }
3524
3525 HRESULT STDMETHODCALLTYPE WebView::DragLeave()
3526 {
3527     if (m_dropTargetHelper)
3528         m_dropTargetHelper->DragLeave();
3529
3530     if (m_dragData) {
3531         DragData data(m_dragData.get(), IntPoint(), IntPoint(), 
3532             DragOperationNone);
3533         m_page->dragController()->dragExited(&data);
3534         m_dragData = 0;
3535     }
3536     return S_OK;
3537 }
3538
3539 HRESULT STDMETHODCALLTYPE WebView::Drop(
3540         IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
3541 {
3542     if (m_dropTargetHelper)
3543         m_dropTargetHelper->Drop(pDataObject, (POINT*)&pt, *pdwEffect);
3544
3545     m_dragData = 0;
3546     *pdwEffect = DROPEFFECT_NONE;
3547     POINTL localpt = pt;
3548     ::ScreenToClient(m_viewWindow, (LPPOINT)&localpt);
3549     DragData data(pDataObject, IntPoint(localpt.x, localpt.y), 
3550         IntPoint(pt.x, pt.y), keyStateToDragOperation(grfKeyState));
3551     m_page->dragController()->performDrag(&data);
3552     return S_OK;
3553 }
3554
3555 HRESULT STDMETHODCALLTYPE WebView::canHandleRequest( 
3556     IWebURLRequest *request,
3557     BOOL *result)
3558 {
3559     COMPtr<WebMutableURLRequest> requestImpl;
3560
3561     HRESULT hr = request->QueryInterface(CLSID_WebMutableURLRequest, (void**)&requestImpl);
3562     if (FAILED(hr))
3563         return hr;
3564
3565     *result = !!canHandleRequest(requestImpl->resourceRequest());
3566     return S_OK;
3567 }
3568
3569 HRESULT STDMETHODCALLTYPE WebView::clearFocusNode()
3570 {
3571     if (m_page && m_page->focusController())
3572         m_page->focusController()->setFocusedNode(0, 0);
3573     return S_OK;
3574 }
3575
3576 HRESULT STDMETHODCALLTYPE WebView::setTabKeyCyclesThroughElements( 
3577     /* [in] */ BOOL cycles)
3578 {
3579     if (m_page)
3580         m_page->setTabKeyCyclesThroughElements(!!cycles);
3581
3582     return S_OK;
3583 }
3584
3585 HRESULT STDMETHODCALLTYPE WebView::tabKeyCyclesThroughElements( 
3586     /* [retval][out] */ BOOL* result)
3587 {
3588     if (!result) {
3589         ASSERT_NOT_REACHED();
3590         return E_POINTER;
3591     }
3592
3593     *result = m_page && m_page->tabKeyCyclesThroughElements() ? TRUE : FALSE;
3594     return S_OK;
3595 }
3596
3597 HRESULT STDMETHODCALLTYPE WebView::setAllowSiteSpecificHacks(
3598     /* [in] */ BOOL allow)
3599 {
3600     s_allowSiteSpecificHacks = !!allow;
3601     return S_OK;
3602 }
3603
3604 HRESULT STDMETHODCALLTYPE WebView::addAdditionalPluginPath( 
3605         /* [in] */ BSTR path)
3606 {
3607     PluginDatabaseWin::installedPlugins()->addExtraPluginPath(String(path, SysStringLen(path)));
3608     return S_OK;
3609 }
3610
3611 HRESULT STDMETHODCALLTYPE WebView::loadBackForwardListFromOtherView( 
3612     /* [in] */ IWebView* otherView)
3613 {
3614     if (!m_page)
3615         return E_FAIL;
3616     
3617     // It turns out the right combination of behavior is done with the back/forward load
3618     // type.  (See behavior matrix at the top of WebFramePrivate.)  So we copy all the items
3619     // in the back forward list, and go to the current one.
3620     BackForwardList* backForwardList = m_page->backForwardList();
3621     ASSERT(!backForwardList->currentItem()); // destination list should be empty
3622
3623     COMPtr<WebView> otherWebView;
3624     if (FAILED(otherView->QueryInterface(CLSID_WebView, (void**)&otherWebView)))
3625         return E_FAIL;
3626     BackForwardList* otherBackForwardList = otherWebView->m_page->backForwardList();
3627     if (!otherBackForwardList->currentItem())
3628         return S_OK; // empty back forward list, bail
3629     
3630     HistoryItem* newItemToGoTo = 0;
3631
3632     int lastItemIndex = otherBackForwardList->forwardListCount();
3633     for (int i = -otherBackForwardList->backListCount(); i <= lastItemIndex; ++i) {
3634         if (!i) {
3635             // If this item is showing , save away its current scroll and form state,
3636             // since that might have changed since loading and it is normally not saved
3637             // until we leave that page.
3638             otherWebView->m_page->mainFrame()->loader()->saveDocumentAndScrollState();
3639         }
3640         RefPtr<HistoryItem> newItem = otherBackForwardList->itemAtIndex(i)->copy();
3641         if (!i) 
3642             newItemToGoTo = newItem.get();
3643         backForwardList->addItem(newItem.release());
3644     }
3645     
3646     ASSERT(newItemToGoTo);
3647     m_page->goToItem(newItemToGoTo, FrameLoadTypeIndexedBackForward);
3648     return S_OK;
3649 }
3650
3651 HRESULT WebView::registerDragDrop()
3652 {
3653     ASSERT(::IsWindow(m_viewWindow));
3654     return ::RegisterDragDrop(m_viewWindow, this);
3655 }
3656
3657 HRESULT WebView::revokeDragDrop()
3658 {
3659     ASSERT(::IsWindow(m_viewWindow));
3660     return ::RevokeDragDrop(m_viewWindow);
3661 }
3662
3663 void WebView::setProhibitsMainFrameScrolling(bool b)
3664 {
3665     m_page->mainFrame()->setProhibitsScrolling(b);
3666 }
3667
3668 class IMMDict {
3669     typedef HIMC (CALLBACK *getContextPtr)(HWND);
3670     typedef BOOL (CALLBACK *releaseContextPtr)(HWND, HIMC);
3671     typedef LONG (CALLBACK *getCompositionStringPtr)(HIMC, DWORD, LPVOID, DWORD);
3672     typedef BOOL (CALLBACK *setCandidateWindowPtr)(HIMC, LPCANDIDATEFORM);
3673     typedef BOOL (CALLBACK *setOpenStatusPtr)(HIMC, BOOL);
3674     typedef BOOL (CALLBACK *notifyIMEPtr)(HIMC, DWORD, DWORD, DWORD);
3675
3676 public:
3677     getContextPtr getContext;
3678     releaseContextPtr releaseContext;
3679     getCompositionStringPtr getCompositionString;
3680     setCandidateWindowPtr setCandidateWindow;
3681     setOpenStatusPtr setOpenStatus;
3682     notifyIMEPtr notifyIME;
3683     static const IMMDict& dict();
3684 private:
3685     IMMDict();
3686     HMODULE m_instance;
3687 };
3688
3689 const IMMDict& IMMDict::dict()
3690 {
3691     static IMMDict instance;
3692     return instance;
3693 }
3694
3695 IMMDict::IMMDict()
3696 {
3697     m_instance = ::LoadLibrary(TEXT("IMM32.DLL"));
3698     getContext = reinterpret_cast<getContextPtr>(::GetProcAddress(m_instance, "ImmGetContext"));
3699     ASSERT(getContext);
3700     releaseContext = reinterpret_cast<releaseContextPtr>(::GetProcAddress(m_instance, "ImmReleaseContext"));
3701     ASSERT(releaseContext);
3702     getCompositionString = reinterpret_cast<getCompositionStringPtr>(::GetProcAddress(m_instance, "ImmGetCompositionStringW"));
3703     ASSERT(getCompositionString);
3704     setCandidateWindow = reinterpret_cast<setCandidateWindowPtr>(::GetProcAddress(m_instance, "ImmSetCandidateWindow"));
3705     ASSERT(setCandidateWindow);
3706     setOpenStatus = reinterpret_cast<setOpenStatusPtr>(::GetProcAddress(m_instance, "ImmSetOpenStatus"));
3707     ASSERT(setOpenStatus);
3708     notifyIME = reinterpret_cast<notifyIMEPtr>(::GetProcAddress(m_instance, "ImmNotifyIME"));
3709     ASSERT(notifyIME);
3710 }
3711
3712 HIMC WebView::getIMMContext() 
3713 {
3714     HIMC context = IMMDict::dict().getContext(m_viewWindow);
3715     return context;
3716 }
3717
3718 void WebView::releaseIMMContext(HIMC hIMC)
3719 {
3720     if (!hIMC)
3721         return;
3722     IMMDict::dict().releaseContext(m_viewWindow, hIMC);
3723 }
3724
3725 void WebView::prepareCandidateWindow(Frame* targetFrame, HIMC hInputContext) 
3726 {
3727     IntRect caret;
3728     if (RefPtr<Range> range = targetFrame->selectionController()->selection().toRange()) {
3729         ExceptionCode ec = 0;
3730         RefPtr<Range> tempRange = range->cloneRange(ec);
3731         caret = targetFrame->firstRectForRange(tempRange.get());
3732     }
3733     caret = targetFrame->view()->contentsToWindow(caret);
3734     CANDIDATEFORM form;
3735     form.dwIndex = 0;
3736     form.dwStyle = CFS_EXCLUDE;
3737     form.ptCurrentPos.x = caret.x();
3738     form.ptCurrentPos.y = caret.y() + caret.height();
3739     form.rcArea.top = caret.y();
3740     form.rcArea.bottom = caret.bottom();
3741     form.rcArea.left = caret.x();
3742     form.rcArea.right = caret.right();
3743     IMMDict::dict().setCandidateWindow(hInputContext, &form);
3744 }
3745
3746 static bool markedTextContainsSelection(Range* markedTextRange, Range* selection)
3747 {
3748     ExceptionCode ec = 0;
3749
3750     ASSERT(markedTextRange->startContainer(ec) == markedTextRange->endContainer(ec));
3751
3752     if (selection->startContainer(ec) != markedTextRange->startContainer(ec))
3753         return false;