/* * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "WebKitDLL.h" #include "WebFrame.h" #include "CFDictionaryPropertyBag.h" #include "COMPtr.h" #include "DefaultPolicyDelegate.h" #include "DOMCoreClasses.h" #include "IWebError.h" #include "IWebErrorPrivate.h" #include "IWebHistory.h" #include "IWebHistoryItemPrivate.h" #include "IWebFrameLoadDelegatePrivate.h" #include "IWebFormDelegate.h" #include "IWebUIDelegatePrivate.h" #include "MarshallingHelpers.h" #include "WebActionPropertyBag.h" #include "WebChromeClient.h" #include "WebDocumentLoader.h" #include "WebDownload.h" #include "WebError.h" #include "WebMutableURLRequest.h" #include "WebEditorClient.h" #include "WebFramePolicyListener.h" #include "WebHistory.h" #include "WebKit.h" #include "WebKitStatisticsPrivate.h" #include "WebNotificationCenter.h" #include "WebView.h" #include "WebDataSource.h" #include "WebHistoryItem.h" #include "WebScriptDebugger.h" #include "WebScriptDebugServer.h" #include "WebURLAuthenticationChallenge.h" #include "WebURLResponse.h" #pragma warning( push, 0 ) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #pragma warning(pop) #include // CG SPI used for printing extern "C" { CGAffineTransform CGContextGetBaseCTM(CGContextRef c); void CGContextSetBaseCTM(CGContextRef c, CGAffineTransform m); } using namespace WebCore; using namespace HTMLNames; #define FLASH_REDRAW 0 // By imaging to a width a little wider than the available pixels, // thin pages will be scaled down a little, matching the way they // print in IE and Camino. This lets them use fewer sheets than they // would otherwise, which is presumably why other browsers do this. // Wide pages will be scaled down more than this. const float PrintingMinimumShrinkFactor = 1.25f; // This number determines how small we are willing to reduce the page content // in order to accommodate the widest line. If the page would have to be // reduced smaller to make the widest line fit, we just clip instead (this // behavior matches MacIE and Mozilla, at least) const float PrintingMaximumShrinkFactor = 2.0f; // {A3676398-4485-4a9d-87DC-CB5A40E6351D} const GUID IID_WebFrame = { 0xa3676398, 0x4485, 0x4a9d, { 0x87, 0xdc, 0xcb, 0x5a, 0x40, 0xe6, 0x35, 0x1d } }; //----------------------------------------------------------------------------- // Helpers to convert from WebCore to WebKit type WebFrame* kit(Frame* frame) { if (!frame) return 0; FrameLoaderClient* frameLoaderClient = frame->loader()->client(); if (frameLoaderClient) return static_cast(frameLoaderClient); // eek, is there a better way than static cast? return 0; } Frame* core(WebFrame* webFrame) { if (!webFrame) return 0; return webFrame->impl(); } // This function is not in WebFrame.h because we don't want to advertise the ability to get a non-const Frame from a const WebFrame Frame* core(const WebFrame* webFrame) { if (!webFrame) return 0; return const_cast(webFrame)->impl(); } WebView* kit(Page* page) { return page ? static_cast(page->chrome()->client())->webView() : 0; } //----------------------------------------------------------------------------- class FormValuesPropertyBag : public IPropertyBag, public IPropertyBag2 { public: FormValuesPropertyBag(HashMap* formValues) : m_formValues(formValues) {} // IUnknown virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject); virtual ULONG STDMETHODCALLTYPE AddRef(void); virtual ULONG STDMETHODCALLTYPE Release(void); // IPropertyBag virtual /* [local] */ HRESULT STDMETHODCALLTYPE Read( /* [in] */ LPCOLESTR pszPropName, /* [out][in] */ VARIANT* pVar, /* [in] */ IErrorLog* pErrorLog); virtual HRESULT STDMETHODCALLTYPE Write( /* [in] */ LPCOLESTR pszPropName, /* [in] */ VARIANT* pVar); // IPropertyBag2 virtual HRESULT STDMETHODCALLTYPE Read( /* [in] */ ULONG cProperties, /* [in] */ PROPBAG2 *pPropBag, /* [in] */ IErrorLog *pErrLog, /* [out] */ VARIANT *pvarValue, /* [out] */ HRESULT *phrError); virtual HRESULT STDMETHODCALLTYPE Write( /* [in] */ ULONG cProperties, /* [in] */ PROPBAG2 *pPropBag, /* [in] */ VARIANT *pvarValue); virtual HRESULT STDMETHODCALLTYPE CountProperties( /* [out] */ ULONG *pcProperties); virtual HRESULT STDMETHODCALLTYPE GetPropertyInfo( /* [in] */ ULONG iProperty, /* [in] */ ULONG cProperties, /* [out] */ PROPBAG2 *pPropBag, /* [out] */ ULONG *pcProperties); virtual HRESULT STDMETHODCALLTYPE LoadObject( /* [in] */ LPCOLESTR pstrName, /* [in] */ DWORD dwHint, /* [in] */ IUnknown *pUnkObject, /* [in] */ IErrorLog *pErrLog); protected: HashMap* m_formValues; }; HRESULT STDMETHODCALLTYPE FormValuesPropertyBag::QueryInterface(REFIID riid, void** ppvObject) { *ppvObject = 0; if (IsEqualGUID(riid, IID_IUnknown)) *ppvObject = this; else if (IsEqualGUID(riid, IID_IPropertyBag)) *ppvObject = static_cast(this); else if (IsEqualGUID(riid, IID_IPropertyBag2)) *ppvObject = static_cast(this); else return E_NOINTERFACE; AddRef(); return S_OK; } ULONG STDMETHODCALLTYPE FormValuesPropertyBag::AddRef(void) { return 1; } ULONG STDMETHODCALLTYPE FormValuesPropertyBag::Release(void) { return 0; } HRESULT STDMETHODCALLTYPE FormValuesPropertyBag::Read(LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog* /*pErrorLog*/) { HRESULT hr = S_OK; if (!pszPropName || !pVar) return E_POINTER; String key(pszPropName); if (!m_formValues->contains(key)) return E_INVALIDARG; String value = m_formValues->get(key); VARTYPE requestedType = V_VT(pVar); VariantClear(pVar); V_VT(pVar) = VT_BSTR; V_BSTR(pVar) = SysAllocStringLen(value.characters(), value.length()); if (value.length() && !V_BSTR(pVar)) return E_OUTOFMEMORY; if (requestedType != VT_BSTR && requestedType != VT_EMPTY) hr = VariantChangeType(pVar, pVar, VARIANT_NOUSEROVERRIDE | VARIANT_ALPHABOOL, requestedType); return hr; } HRESULT STDMETHODCALLTYPE FormValuesPropertyBag::Write(LPCOLESTR pszPropName, VARIANT* pVar) { if (!pszPropName || !pVar) return E_POINTER; VariantClear(pVar); return E_FAIL; } HRESULT STDMETHODCALLTYPE FormValuesPropertyBag::Read( /* [in] */ ULONG cProperties, /* [in] */ PROPBAG2* pPropBag, /* [in] */ IErrorLog* pErrLog, /* [out] */ VARIANT* pvarValue, /* [out] */ HRESULT* phrError) { if (cProperties > (size_t)m_formValues->size()) return E_INVALIDARG; if (!pPropBag || !pvarValue || !phrError) return E_POINTER; for (ULONG i=0; ipstrName, &pvarValue[i], pErrLog); } return S_OK; } HRESULT STDMETHODCALLTYPE FormValuesPropertyBag::Write( /* [in] */ ULONG /*cProperties*/, /* [in] */ PROPBAG2* pPropBag, /* [in] */ VARIANT* pvarValue) { if (!pPropBag || !pvarValue) return E_POINTER; return E_FAIL; } HRESULT STDMETHODCALLTYPE FormValuesPropertyBag::CountProperties( /* [out] */ ULONG* pcProperties) { *pcProperties = m_formValues->size(); return S_OK; } HRESULT STDMETHODCALLTYPE FormValuesPropertyBag::GetPropertyInfo( /* [in] */ ULONG iProperty, /* [in] */ ULONG cProperties, /* [out] */ PROPBAG2* pPropBag, /* [out] */ ULONG* pcProperties) { if (iProperty > (size_t)m_formValues->size() || iProperty+cProperties > (size_t)m_formValues->size()) return E_INVALIDARG; if (!pPropBag || !pcProperties) return E_POINTER; *pcProperties = 0; ULONG i = 0; ULONG endProperty = iProperty + cProperties; for (HashMap::iterator it = m_formValues->begin(); i= iProperty) { int storeIndex = (*pcProperties)++; pPropBag[storeIndex].dwType = PROPBAG2_TYPE_DATA; pPropBag[storeIndex].vt = VT_BSTR; pPropBag[storeIndex].cfType = CF_TEXT; pPropBag[storeIndex].dwHint = 0; pPropBag[storeIndex].pstrName = const_cast(it->first.charactersWithNullTermination()); } ++it; } return S_OK; } HRESULT STDMETHODCALLTYPE FormValuesPropertyBag::LoadObject( /* [in] */ LPCOLESTR pstrName, /* [in] */ DWORD /*dwHint*/, /* [in] */ IUnknown* pUnkObject, /* [in] */ IErrorLog* /*pErrLog*/) { if (!pstrName || !pUnkObject) return E_POINTER; return E_FAIL; } //----------------------------------------------------------------------------- static Element *elementFromDOMElement(IDOMElement *element) { if (!element) return 0; COMPtr elePriv; HRESULT hr = element->QueryInterface(IID_IDOMElementPrivate, (void**) &elePriv); if (SUCCEEDED(hr)) { Element* ele; hr = elePriv->coreElement((void**)&ele); if (SUCCEEDED(hr)) return ele; } return 0; } static HTMLFormElement *formElementFromDOMElement(IDOMElement *element) { if (!element) return 0; IDOMElementPrivate* elePriv; HRESULT hr = element->QueryInterface(IID_IDOMElementPrivate, (void**) &elePriv); if (SUCCEEDED(hr)) { Element* ele; hr = elePriv->coreElement((void**)&ele); elePriv->Release(); if (SUCCEEDED(hr) && ele && ele->hasTagName(formTag)) return static_cast(ele); } return 0; } static HTMLInputElement* inputElementFromDOMElement(IDOMElement* element) { if (!element) return 0; IDOMElementPrivate* elePriv; HRESULT hr = element->QueryInterface(IID_IDOMElementPrivate, (void**) &elePriv); if (SUCCEEDED(hr)) { Element* ele; hr = elePriv->coreElement((void**)&ele); elePriv->Release(); if (SUCCEEDED(hr) && ele && ele->hasTagName(inputTag)) return static_cast(ele); } return 0; } // WebFramePrivate ------------------------------------------------------------ class WebFrame::WebFramePrivate { public: WebFramePrivate() : frame(0) , webView(0) , m_policyFunction(0) , m_pluginView(0) , m_hasSentResponseToPlugin(false) { } ~WebFramePrivate() { } FrameView* frameView() { return frame ? frame->view() : 0; } Frame* frame; WebView* webView; FramePolicyFunction m_policyFunction; COMPtr m_policyListener; // Points to the plugin view that data should be redirected to. PluginViewWin* m_pluginView; bool m_hasSentResponseToPlugin; }; // WebFrame ---------------------------------------------------------------- WebFrame::WebFrame() : m_refCount(0) , d(new WebFrame::WebFramePrivate) , m_quickRedirectComing(false) , m_inPrintingMode(false) , m_pageHeight(0) , m_scriptDebugger(0) { WebFrameCount++; gClassCount++; } WebFrame::~WebFrame() { delete d; WebFrameCount--; gClassCount--; } WebFrame* WebFrame::createInstance() { WebFrame* instance = new WebFrame(); instance->AddRef(); return instance; } HRESULT STDMETHODCALLTYPE WebFrame::setAllowsScrolling( /* [in] */ BOOL flag) { if (Frame* frame = core(this)) if (FrameView* view = frame->view()) view->setAllowsScrolling(!!flag); return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::allowsScrolling( /* [retval][out] */ BOOL *flag) { if (flag) if (Frame* frame = core(this)) if (FrameView* view = frame->view()) *flag = view->allowsScrolling(); return S_OK; } // IUnknown ------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE WebFrame::QueryInterface(REFIID riid, void** ppvObject) { *ppvObject = 0; if (IsEqualGUID(riid, IID_WebFrame)) *ppvObject = this; else if (IsEqualGUID(riid, IID_IUnknown)) *ppvObject = static_cast(this); else if (IsEqualGUID(riid, IID_IWebFrame)) *ppvObject = static_cast(this); else if (IsEqualGUID(riid, IID_IWebFramePrivate)) *ppvObject = static_cast(this); else if (IsEqualGUID(riid, IID_IWebDocumentText)) *ppvObject = static_cast(this); else return E_NOINTERFACE; AddRef(); return S_OK; } ULONG STDMETHODCALLTYPE WebFrame::AddRef(void) { return ++m_refCount; } ULONG STDMETHODCALLTYPE WebFrame::Release(void) { ULONG newRef = --m_refCount; if (!newRef) delete(this); return newRef; } // IWebFrame ------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE WebFrame::name( /* [retval][out] */ BSTR* frameName) { if (!frameName) { ASSERT_NOT_REACHED(); return E_POINTER; } *frameName = 0; Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; *frameName = BString(coreFrame->tree()->name()).release(); return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::webView( /* [retval][out] */ IWebView** view) { *view = 0; if (!d->webView) return E_FAIL; *view = d->webView; (*view)->AddRef(); return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::frameView( /* [retval][out] */ IWebFrameView** /*view*/) { ASSERT_NOT_REACHED(); return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE WebFrame::DOMDocument( /* [retval][out] */ IDOMDocument** result) { if (!result) { ASSERT_NOT_REACHED(); return E_POINTER; } *result = 0; if (Frame* coreFrame = core(this)) if (Document* document = coreFrame->document()) *result = DOMDocument::createInstance(document); return *result ? S_OK : E_FAIL; } HRESULT STDMETHODCALLTYPE WebFrame::frameElement( /* [retval][out] */ IDOMHTMLElement** /*frameElement*/) { ASSERT_NOT_REACHED(); return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE WebFrame::currentForm( /* [retval][out] */ IDOMElement **currentForm) { if (!currentForm) { ASSERT_NOT_REACHED(); return E_POINTER; } *currentForm = 0; if (Frame* coreFrame = core(this)) if (HTMLFormElement* formElement = coreFrame->currentForm()) *currentForm = DOMElement::createInstance(formElement); return *currentForm ? S_OK : E_FAIL; } JSGlobalContextRef STDMETHODCALLTYPE WebFrame::globalContext() { Frame* coreFrame = core(this); if (!coreFrame) return 0; return toGlobalRef(coreFrame->scriptProxy()->globalObject()->globalExec()); } HRESULT STDMETHODCALLTYPE WebFrame::loadRequest( /* [in] */ IWebURLRequest* request) { COMPtr requestImpl; HRESULT hr = request->QueryInterface(&requestImpl); if (FAILED(hr)) return hr; Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; coreFrame->loader()->load(requestImpl->resourceRequest()); return S_OK; } void WebFrame::loadData(PassRefPtr data, BSTR mimeType, BSTR textEncodingName, BSTR baseURL, BSTR failingURL) { String mimeTypeString(mimeType, SysStringLen(mimeType)); if (!mimeType) mimeTypeString = "text/html"; String encodingString(textEncodingName, SysStringLen(textEncodingName)); KURL baseKURL = DeprecatedString((DeprecatedChar*)baseURL, SysStringLen(baseURL)); KURL failingKURL = DeprecatedString((DeprecatedChar*)failingURL, SysStringLen(failingURL)); ResourceRequest request(baseKURL); SubstituteData substituteData(data, mimeTypeString, encodingString, failingKURL); // This method is only called from IWebFrame methods, so don't ASSERT that the Frame pointer isn't null. if (Frame* coreFrame = core(this)) coreFrame->loader()->load(request, substituteData); } HRESULT STDMETHODCALLTYPE WebFrame::loadData( /* [in] */ IStream* data, /* [in] */ BSTR mimeType, /* [in] */ BSTR textEncodingName, /* [in] */ BSTR url) { RefPtr sharedBuffer = new SharedBuffer(); STATSTG stat; if (SUCCEEDED(data->Stat(&stat, STATFLAG_NONAME))) { if (!stat.cbSize.HighPart && stat.cbSize.LowPart) { Vector dataBuffer(stat.cbSize.LowPart); ULONG read; // FIXME: this does a needless copy, would be better to read right into the SharedBuffer // or adopt the Vector or something. if (SUCCEEDED(data->Read(dataBuffer.data(), static_cast(dataBuffer.size()), &read))) sharedBuffer->append(dataBuffer.data(), static_cast(dataBuffer.size())); } } loadData(sharedBuffer, mimeType, textEncodingName, url, 0); return S_OK; } void WebFrame::loadHTMLString(BSTR string, BSTR baseURL, BSTR unreachableURL) { RefPtr sharedBuffer = new SharedBuffer(reinterpret_cast(string), sizeof(UChar) * SysStringLen(string)); BString utf16Encoding(TEXT("utf-16"), 6); loadData(sharedBuffer.release(), 0, utf16Encoding, baseURL, unreachableURL); } HRESULT STDMETHODCALLTYPE WebFrame::loadHTMLString( /* [in] */ BSTR string, /* [in] */ BSTR baseURL) { loadHTMLString(string, baseURL, 0); return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::loadAlternateHTMLString( /* [in] */ BSTR str, /* [in] */ BSTR baseURL, /* [in] */ BSTR unreachableURL) { loadHTMLString(str, baseURL, unreachableURL); return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::loadArchive( /* [in] */ IWebArchive* /*archive*/) { ASSERT_NOT_REACHED(); return E_NOTIMPL; } static inline WebDataSource *getWebDataSource(DocumentLoader* loader) { return loader ? static_cast(loader)->dataSource() : 0; } HRESULT STDMETHODCALLTYPE WebFrame::dataSource( /* [retval][out] */ IWebDataSource** source) { if (!source) { ASSERT_NOT_REACHED(); return E_POINTER; } *source = 0; Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; WebDataSource* webDataSource = getWebDataSource(coreFrame->loader()->documentLoader()); *source = webDataSource; if (webDataSource) webDataSource->AddRef(); return *source ? S_OK : E_FAIL; } HRESULT STDMETHODCALLTYPE WebFrame::provisionalDataSource( /* [retval][out] */ IWebDataSource** source) { if (!source) { ASSERT_NOT_REACHED(); return E_POINTER; } *source = 0; Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; WebDataSource* webDataSource = getWebDataSource(coreFrame->loader()->provisionalDocumentLoader()); *source = webDataSource; if (webDataSource) webDataSource->AddRef(); return *source ? S_OK : E_FAIL; } KURL WebFrame::url() const { Frame* coreFrame = core(this); if (!coreFrame) return KURL(); return coreFrame->loader()->url(); } void WebFrame::attachScriptDebugger() { if (!m_scriptDebugger && core(this)->scriptProxy()->haveGlobalObject()) m_scriptDebugger.set(new WebScriptDebugger(this)); } void WebFrame::detachScriptDebugger() { m_scriptDebugger.clear(); } HRESULT STDMETHODCALLTYPE WebFrame::stopLoading( void) { if (Frame* coreFrame = core(this)) coreFrame->loader()->stopAllLoaders(); return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::reload( void) { Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; coreFrame->loader()->reload(); return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::findFrameNamed( /* [in] */ BSTR name, /* [retval][out] */ IWebFrame** frame) { if (!frame) { ASSERT_NOT_REACHED(); return E_POINTER; } *frame = 0; Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; Frame* foundFrame = coreFrame->tree()->find(AtomicString(name, SysStringLen(name))); if (!foundFrame) return S_OK; WebFrame* foundWebFrame = kit(foundFrame); if (!foundWebFrame) return E_FAIL; return foundWebFrame->QueryInterface(IID_IWebFrame, (void**)frame); } HRESULT STDMETHODCALLTYPE WebFrame::parentFrame( /* [retval][out] */ IWebFrame** frame) { HRESULT hr = S_OK; *frame = 0; if (Frame* coreFrame = core(this)) if (WebFrame* webFrame = kit(coreFrame->tree()->parent())) hr = webFrame->QueryInterface(IID_IWebFrame, (void**) frame); return hr; } class EnumChildFrames : public IEnumVARIANT { public: EnumChildFrames(Frame* f) : m_refCount(1), m_frame(f), m_curChild(f ? f->tree()->firstChild() : 0) { } virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) { *ppvObject = 0; if (IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IEnumVARIANT)) *ppvObject = this; else return E_NOINTERFACE; AddRef(); return S_OK; } virtual ULONG STDMETHODCALLTYPE AddRef(void) { return ++m_refCount; } virtual ULONG STDMETHODCALLTYPE Release(void) { ULONG newRef = --m_refCount; if (!newRef) delete(this); return newRef; } virtual HRESULT STDMETHODCALLTYPE Next(ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched) { if (pCeltFetched) *pCeltFetched = 0; if (!rgVar) return E_POINTER; VariantInit(rgVar); if (!celt || celt > 1) return S_FALSE; if (!m_frame || !m_curChild) return S_FALSE; WebFrame* webFrame = kit(m_curChild); IUnknown* unknown; HRESULT hr = webFrame->QueryInterface(IID_IUnknown, (void**)&unknown); if (FAILED(hr)) return hr; V_VT(rgVar) = VT_UNKNOWN; V_UNKNOWN(rgVar) = unknown; m_curChild = m_curChild->tree()->nextSibling(); if (pCeltFetched) *pCeltFetched = 1; return S_OK; } virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt) { if (!m_frame) return S_FALSE; for (unsigned i = 0; i < celt && m_curChild; i++) m_curChild = m_curChild->tree()->nextSibling(); return m_curChild ? S_OK : S_FALSE; } virtual HRESULT STDMETHODCALLTYPE Reset(void) { if (!m_frame) return S_FALSE; m_curChild = m_frame->tree()->firstChild(); return S_OK; } virtual HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT**) { return E_NOTIMPL; } private: ULONG m_refCount; Frame* m_frame; Frame* m_curChild; }; HRESULT STDMETHODCALLTYPE WebFrame::childFrames( /* [retval][out] */ IEnumVARIANT **enumFrames) { if (!enumFrames) return E_POINTER; *enumFrames = new EnumChildFrames(core(this)); return S_OK; } // IWebFramePrivate ------------------------------------------------------ HRESULT STDMETHODCALLTYPE WebFrame::renderTreeAsExternalRepresentation( /* [retval][out] */ BSTR *result) { if (!result) { ASSERT_NOT_REACHED(); return E_POINTER; } *result = 0; Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; DeprecatedString representation = externalRepresentation(coreFrame->renderer()); *result = SysAllocStringLen((LPCOLESTR)representation.unicode(), representation.length()); return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::scrollOffset( /* [retval][out] */ SIZE* offset) { if (!offset) { ASSERT_NOT_REACHED(); return E_POINTER; } Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; FrameView* view = coreFrame->view(); if (!view) return E_FAIL; *offset = view->scrollOffset(); return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::layout() { Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; FrameView* view = coreFrame->view(); if (!view) return E_FAIL; view->layout(); return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::firstLayoutDone( /* [retval][out] */ BOOL* result) { if (!result) { ASSERT_NOT_REACHED(); return E_POINTER; } *result = 0; Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; *result = coreFrame->loader()->firstLayoutDone(); return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::loadType( /* [retval][out] */ WebFrameLoadType* type) { if (!type) { ASSERT_NOT_REACHED(); return E_POINTER; } *type = (WebFrameLoadType)0; Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; *type = (WebFrameLoadType)coreFrame->loader()->loadType(); return S_OK; } // IWebDocumentText ----------------------------------------------------------- HRESULT STDMETHODCALLTYPE WebFrame::supportsTextEncoding( /* [retval][out] */ BOOL* result) { *result = FALSE; return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE WebFrame::selectedString( /* [retval][out] */ BSTR* result) { *result = 0; Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; String text = coreFrame->selectedText(); text.replace('\\', coreFrame->backslashAsCurrencySymbol()); *result = BString(text).release(); return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::selectAll() { return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE WebFrame::deselectAll() { return E_NOTIMPL; } // WebFrame --------------------------------------------------------------- void WebFrame::initWithWebFrameView(IWebFrameView* /*view*/, IWebView* webView, Page* page, HTMLFrameOwnerElement* ownerElement) { if (FAILED(webView->QueryInterface(&d->webView))) return; d->webView->Release(); // don't hold the extra ref HWND viewWindow; d->webView->viewWindow((OLE_HANDLE*)&viewWindow); this->AddRef(); // We release this ref in frameLoaderDestroyed() Frame* frame = new Frame(page, ownerElement, this); d->frame = frame; FrameView* frameView = new FrameView(frame); frame->setView(frameView); frameView->deref(); // FrameViews are created with a ref count of 1. Release this ref since we've assigned it to frame. frameView->setContainingWindow(viewWindow); } Frame* WebFrame::impl() { return d->frame; } void WebFrame::invalidate() { Frame* coreFrame = core(this); ASSERT(coreFrame); if (Document* document = coreFrame->document()) document->recalcStyle(Node::Force); } void WebFrame::setTextSizeMultiplier(float multiplier) { int newZoomFactor = (int)round(multiplier * 100); Frame* coreFrame = core(this); ASSERT(coreFrame); if (coreFrame->zoomFactor() == newZoomFactor) return; coreFrame->setZoomFactor(newZoomFactor); } HRESULT WebFrame::inViewSourceMode(BOOL* flag) { if (!flag) { ASSERT_NOT_REACHED(); return E_POINTER; } *flag = FALSE; Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; *flag = coreFrame->inViewSourceMode() ? TRUE : FALSE; return S_OK; } HRESULT WebFrame::setInViewSourceMode(BOOL flag) { Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; coreFrame->setInViewSourceMode(!!flag); return S_OK; } HRESULT WebFrame::elementWithName(BSTR name, IDOMElement* form, IDOMElement** element) { if (!form) return E_INVALIDARG; HTMLFormElement *formElement = formElementFromDOMElement(form); if (formElement) { Vector& elements = formElement->formElements; AtomicString targetName((UChar*)name, SysStringLen(name)); for (unsigned int i = 0; i < elements.size(); i++) { HTMLGenericFormElement *elt = elements[i]; // Skip option elements, other duds if (elt->name() == targetName) { *element = DOMElement::createInstance(elt); return S_OK; } } } return E_FAIL; } HRESULT WebFrame::formForElement(IDOMElement* element, IDOMElement** form) { if (!element) return E_INVALIDARG; HTMLInputElement *inputElement = inputElementFromDOMElement(element); if (!inputElement) return E_FAIL; HTMLFormElement *formElement = inputElement->form(); if (!formElement) return E_FAIL; *form = DOMElement::createInstance(formElement); return S_OK; } HRESULT WebFrame::elementDoesAutoComplete(IDOMElement *element, bool *result) { *result = false; if (!element) return E_INVALIDARG; HTMLInputElement *inputElement = inputElementFromDOMElement(element); if (!inputElement) *result = false; else *result = (inputElement->inputType() == HTMLInputElement::TEXT && inputElement->autoComplete()); return S_OK; } HRESULT WebFrame::controlsInForm(IDOMElement* form, IDOMElement** controls, int* cControls) { if (!form) return E_INVALIDARG; HTMLFormElement *formElement = formElementFromDOMElement(form); if (!formElement) return E_FAIL; int inCount = *cControls; int count = (int) formElement->formElements.size(); *cControls = count; if (!controls) return S_OK; if (inCount < count) return E_FAIL; *cControls = 0; Vector& elements = formElement->formElements; for (int i = 0; i < count; i++) { if (elements.at(i)->isEnumeratable()) { // Skip option elements, other duds controls[*cControls] = DOMElement::createInstance(elements.at(i)); (*cControls)++; } } return S_OK; } HRESULT WebFrame::elementIsPassword(IDOMElement *element, bool *result) { HTMLInputElement *inputElement = inputElementFromDOMElement(element); *result = inputElement != 0 && inputElement->inputType() == HTMLInputElement::PASSWORD; return S_OK; } HRESULT WebFrame::searchForLabelsBeforeElement(const BSTR* labels, int cLabels, IDOMElement* beforeElement, BSTR* result) { if (!result) { ASSERT_NOT_REACHED(); return E_POINTER; } *result = 0; if (!cLabels) return S_OK; if (cLabels < 1) return E_INVALIDARG; Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; Vector labelStrings(cLabels); for (int i=0; isearchForLabelsBeforeElement(labelStrings, coreElement); *result = SysAllocStringLen(label.characters(), label.length()); if (label.length() && !*result) return E_OUTOFMEMORY; return S_OK; } HRESULT WebFrame::matchLabelsAgainstElement(const BSTR* labels, int cLabels, IDOMElement* againstElement, BSTR* result) { if (!result) { ASSERT_NOT_REACHED(); return E_POINTER; } *result = 0; if (!cLabels) return S_OK; if (cLabels < 1) return E_INVALIDARG; Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; Vector labelStrings(cLabels); for (int i=0; imatchLabelsAgainstElement(labelStrings, coreElement); *result = SysAllocStringLen(label.characters(), label.length()); if (label.length() && !*result) return E_OUTOFMEMORY; return S_OK; } HRESULT WebFrame::canProvideDocumentSource(bool* result) { HRESULT hr = S_OK; *result = false; COMPtr dataSource; hr = WebFrame::dataSource(&dataSource); if (FAILED(hr)) return hr; COMPtr urlResponse; hr = dataSource->response(&urlResponse); if (SUCCEEDED(hr) && urlResponse) { BSTR mimeTypeBStr; if (SUCCEEDED(urlResponse->MIMEType(&mimeTypeBStr))) { String mimeType(mimeTypeBStr, SysStringLen(mimeTypeBStr)); *result = mimeType == "text/html" || WebCore::DOMImplementation::isXMLMIMEType(mimeType); SysFreeString(mimeTypeBStr); } } return hr; } // FrameWinClient void WebFrame::ref() { this->AddRef(); } void WebFrame::deref() { this->Release(); } void WebFrame::frameLoaderDestroyed() { // The FrameLoader going away is equivalent to the Frame going away, // so we now need to clear our frame pointer. d->frame = 0; this->Release(); } PassRefPtr WebFrame::createFrame(const KURL& URL, const String& name, HTMLFrameOwnerElement* ownerElement, const String& referrer) { Frame* coreFrame = core(this); ASSERT(coreFrame); COMPtr webFrame; webFrame.adoptRef(WebFrame::createInstance()); webFrame->initWithWebFrameView(0, d->webView, coreFrame->page(), ownerElement); RefPtr childFrame(adoptRef(core(webFrame.get()))); // We have to adopt, because Frames start out with a refcount of 1. ASSERT(childFrame); coreFrame->tree()->appendChild(childFrame); childFrame->tree()->setName(name); childFrame->init(); loadURLIntoChild(URL, referrer, webFrame.get()); // The frame's onload handler may have removed it from the document. if (!childFrame->tree()->parent()) return 0; return childFrame.release(); } void WebFrame::loadURLIntoChild(const KURL& originalURL, const String& referrer, WebFrame* childFrame) { ASSERT(childFrame); ASSERT(core(childFrame)); Frame* coreFrame = core(this); ASSERT(coreFrame); HistoryItem* parentItem = coreFrame->loader()->currentHistoryItem(); FrameLoadType loadType = coreFrame->loader()->loadType(); FrameLoadType childLoadType = FrameLoadTypeRedirectWithLockedHistory; KURL url = originalURL; // If we're moving in the backforward list, we might want to replace the content // of this child frame with whatever was there at that point. // Reload will maintain the frame contents, LoadSame will not. if (parentItem && parentItem->children().size() && (isBackForwardLoadType(loadType) || loadType == FrameLoadTypeReload || loadType == FrameLoadTypeReloadAllowingStaleData)) { if (HistoryItem* childItem = parentItem->childItemWithName(core(childFrame)->tree()->name())) { // Use the original URL to ensure we get all the side-effects, such as // onLoad handlers, of any redirects that happened. An example of where // this is needed is Radar 3213556. url = childItem->originalURLString().deprecatedString(); // These behaviors implied by these loadTypes should apply to the child frames childLoadType = loadType; if (isBackForwardLoadType(loadType)) // For back/forward, remember this item so we can traverse any child items as child frames load core(childFrame)->loader()->setProvisionalHistoryItem(childItem); else // For reload, just reinstall the current item, since a new child frame was created but we won't be creating a new BF item core(childFrame)->loader()->setCurrentHistoryItem(childItem); } } // FIXME: Handle loading WebArchives here core(childFrame)->loader()->load(url, referrer, childLoadType, String(), 0, 0); } void WebFrame::openURL(const String& URL, const Event* triggeringEvent, bool newWindow, bool lockHistory) { bool ctrlPressed = false; bool shiftPressed = false; if (triggeringEvent) { if (triggeringEvent->isMouseEvent()) { const MouseRelatedEvent* mouseEvent = static_cast(triggeringEvent); ctrlPressed = mouseEvent->ctrlKey(); shiftPressed = mouseEvent->shiftKey(); } else if (triggeringEvent->isKeyboardEvent()) { const KeyboardEvent* keyEvent = static_cast(triggeringEvent); ctrlPressed = keyEvent->ctrlKey(); shiftPressed = keyEvent->shiftKey(); } } if (ctrlPressed) newWindow = true; BString urlBStr = URL; IWebMutableURLRequest* request = WebMutableURLRequest::createInstance(); if (FAILED(request->initWithURL(urlBStr, WebURLRequestUseProtocolCachePolicy, 0))) goto exit; if (newWindow) { // new tab/window IWebUIDelegate* ui; IWebView* newWebView; if (SUCCEEDED(d->webView->uiDelegate(&ui)) && ui) { if (SUCCEEDED(ui->createWebViewWithRequest(d->webView, request, &newWebView))) { if (shiftPressed) { // Ctrl-Option-Shift-click: Opens a link in a new window and selects it. // Ctrl-Shift-click: Opens a link in a new tab and selects it. ui->webViewShow(d->webView); } newWebView->Release(); newWebView = 0; } ui->Release(); } } else { m_quickRedirectComing = lockHistory; loadRequest(request); } exit: request->Release(); } void WebFrame::dispatchDidHandleOnloadEvents() { IWebFrameLoadDelegatePrivate* frameLoadDelegatePriv; if (SUCCEEDED(d->webView->frameLoadDelegatePrivate(&frameLoadDelegatePriv)) && frameLoadDelegatePriv) { frameLoadDelegatePriv->didHandleOnloadEventsForFrame(d->webView, this); frameLoadDelegatePriv->Release(); } } void WebFrame::windowScriptObjectAvailable(JSContextRef context, JSObjectRef windowObject) { IWebFrameLoadDelegate* frameLoadDelegate; if (SUCCEEDED(d->webView->frameLoadDelegate(&frameLoadDelegate)) && frameLoadDelegate) { frameLoadDelegate->windowScriptObjectAvailable(d->webView, context, windowObject); frameLoadDelegate->Release(); } } WebHistory* WebFrame::webHistory() { if (this != d->webView->topLevelFrame()) return 0; IWebHistoryPrivate* historyInternal = WebHistory::optionalSharedHistoryInternal(); // does not add a ref if (!historyInternal) return 0; WebHistory* webHistory; if (FAILED(historyInternal->QueryInterface(&webHistory))) return 0; return webHistory; } bool WebFrame::hasWebView() const { return !!d->webView; } bool WebFrame::hasFrameView() const { return !!d->frameView(); } void WebFrame::makeDocumentView() { ASSERT(core(this)); // On the mac, this is done in Frame::setView, but since we don't have separate // frame views, we'll just do it here instead. core(this)->loader()->resetMultipleFormSubmissionProtection(); } void WebFrame::makeRepresentation(DocumentLoader*) { notImplemented(); } void WebFrame::forceLayout() { notImplemented(); } void WebFrame::forceLayoutForNonHTML() { notImplemented(); } void WebFrame::setCopiesOnScroll() { notImplemented(); } void WebFrame::detachedFromParent1() { notImplemented(); } void WebFrame::detachedFromParent2() { notImplemented(); } void WebFrame::detachedFromParent3() { notImplemented(); } void WebFrame::detachedFromParent4() { notImplemented(); } void WebFrame::loadedFromCachedPage() { notImplemented(); } void WebFrame::dispatchDidReceiveServerRedirectForProvisionalLoad() { COMPtr frameLoadDelegate; if (SUCCEEDED(d->webView->frameLoadDelegate(&frameLoadDelegate))) frameLoadDelegate->didReceiveServerRedirectForProvisionalLoadForFrame(d->webView, this); } void WebFrame::dispatchDidCancelClientRedirect() { COMPtr frameLoadDelegate; if (SUCCEEDED(d->webView->frameLoadDelegate(&frameLoadDelegate))) frameLoadDelegate->didCancelClientRedirectForFrame(d->webView, this); } void WebFrame::dispatchWillPerformClientRedirect(const KURL& url, double delay, double fireDate) { COMPtr frameLoadDelegate; if (SUCCEEDED(d->webView->frameLoadDelegate(&frameLoadDelegate))) frameLoadDelegate->willPerformClientRedirectToURL(d->webView, BString(url.string()), delay, MarshallingHelpers::CFAbsoluteTimeToDATE(fireDate), this); } void WebFrame::dispatchDidChangeLocationWithinPage() { COMPtr frameLoadDelegate; if (SUCCEEDED(d->webView->frameLoadDelegate(&frameLoadDelegate))) frameLoadDelegate->didChangeLocationWithinPageForFrame(d->webView, this); } void WebFrame::dispatchWillClose() { COMPtr frameLoadDelegate; if (SUCCEEDED(d->webView->frameLoadDelegate(&frameLoadDelegate))) frameLoadDelegate->willCloseFrame(d->webView, this); } void WebFrame::dispatchDidReceiveIcon() { d->webView->dispatchDidReceiveIconFromWebFrame(this); } void WebFrame::dispatchDidStartProvisionalLoad() { COMPtr frameLoadDelegate; if (SUCCEEDED(d->webView->frameLoadDelegate(&frameLoadDelegate))) frameLoadDelegate->didStartProvisionalLoadForFrame(d->webView, this); } void WebFrame::dispatchDidReceiveTitle(const String& title) { COMPtr frameLoadDelegate; if (SUCCEEDED(d->webView->frameLoadDelegate(&frameLoadDelegate))) frameLoadDelegate->didReceiveTitle(d->webView, BString(title), this); } void WebFrame::dispatchDidCommitLoad() { COMPtr frameLoadDelegate; if (SUCCEEDED(d->webView->frameLoadDelegate(&frameLoadDelegate))) frameLoadDelegate->didCommitLoadForFrame(d->webView, this); } void WebFrame::dispatchDidFinishDocumentLoad() { COMPtr frameLoadDelegatePriv; if (SUCCEEDED(d->webView->frameLoadDelegatePrivate(&frameLoadDelegatePriv)) && frameLoadDelegatePriv) frameLoadDelegatePriv->didFinishDocumentLoadForFrame(d->webView, this); } void WebFrame::dispatchDidFinishLoad() { COMPtr frameLoadDelegate; if (SUCCEEDED(d->webView->frameLoadDelegate(&frameLoadDelegate))) frameLoadDelegate->didFinishLoadForFrame(d->webView, this); } void WebFrame::dispatchDidFirstLayout() { COMPtr frameLoadDelegatePriv; if (SUCCEEDED(d->webView->frameLoadDelegatePrivate(&frameLoadDelegatePriv)) && frameLoadDelegatePriv) frameLoadDelegatePriv->didFirstLayoutInFrame(d->webView, this); } void WebFrame::dispatchShow() { COMPtr ui; if (SUCCEEDED(d->webView->uiDelegate(&ui))) ui->webViewShow(d->webView); } void WebFrame::cancelPolicyCheck() { if (d->m_policyListener) { d->m_policyListener->invalidate(); d->m_policyListener = 0; } d->m_policyFunction = 0; } void WebFrame::dispatchWillSubmitForm(FramePolicyFunction function, PassRefPtr formState) { Frame* coreFrame = core(this); ASSERT(coreFrame); COMPtr formDelegate; if (FAILED(d->webView->formDelegate(&formDelegate))) { (coreFrame->loader()->*function)(PolicyUse); return; } COMPtr formElement; formElement.adoptRef(DOMElement::createInstance(formState->form())); // FIXME: The FormValuesPropertyBag constructor should take a const pointer FormValuesPropertyBag formValuesPropBag(const_cast*>(&formState->values())); COMPtr sourceFrame(kit(formState->sourceFrame())); if (SUCCEEDED(formDelegate->willSubmitForm(this, sourceFrame.get(), formElement.get(), &formValuesPropBag, setUpPolicyListener(function).get()))) return; // FIXME: Add a sane default implementation (coreFrame->loader()->*function)(PolicyUse); } void WebFrame::dispatchDidLoadMainResource(DocumentLoader* loader) { if (WebScriptDebugServer::listenerCount() > 0) { Frame* coreFrame = core(this); if (!coreFrame) return; WebScriptDebugServer::sharedWebScriptDebugServer()->didLoadMainResourceForDataSource( kit(coreFrame->page()), loader ? static_cast(loader)->dataSource() : 0); } } void WebFrame::revertToProvisionalState(DocumentLoader*) { notImplemented(); } void WebFrame::clearUnarchivingState(DocumentLoader*) { notImplemented(); } void WebFrame::setMainFrameDocumentReady(bool) { notImplemented(); } void WebFrame::willChangeTitle(DocumentLoader*) { notImplemented(); } void WebFrame::didChangeTitle(DocumentLoader*) { notImplemented(); } void WebFrame::finishedLoading(DocumentLoader* loader) { // Telling the frame we received some data and passing 0 as the data is our // way to get work done that is normally done when the first bit of data is // received, even for the case of a document with no data (like about:blank) if (!d->m_pluginView) committedLoad(loader, 0, 0); else { if (d->m_pluginView->status() == PluginStatusLoadedSuccessfully) d->m_pluginView->didFinishLoading(); d->m_pluginView = 0; d->m_hasSentResponseToPlugin = false; } } void WebFrame::finalSetupForReplace(DocumentLoader*) { notImplemented(); } void WebFrame::setDefersLoading(bool) { notImplemented(); } bool WebFrame::isArchiveLoadPending(ResourceLoader*) const { notImplemented(); return false; } void WebFrame::cancelPendingArchiveLoad(ResourceLoader*) { notImplemented(); } void WebFrame::clearArchivedResources() { notImplemented(); } bool WebFrame::canHandleRequest(const ResourceRequest& request) const { return WebView::canHandleRequest(request); } bool WebFrame::canShowMIMEType(const String& /*MIMEType*/) const { notImplemented(); return true; } bool WebFrame::representationExistsForURLScheme(const String& /*URLScheme*/) const { notImplemented(); return false; } String WebFrame::generatedMIMETypeForURLScheme(const String& /*URLScheme*/) const { notImplemented(); ASSERT_NOT_REACHED(); return String(); } void WebFrame::frameLoadCompleted() { if (Frame* coreFrame = core(this)) coreFrame->loader()->setPreviousHistoryItem(0); } void WebFrame::restoreViewState() { // FIXME: Need to restore view state for page caching notImplemented(); } void WebFrame::provisionalLoadStarted() { notImplemented(); } bool WebFrame::shouldTreatURLAsSameAsCurrent(const KURL&) const { notImplemented(); return false; } void WebFrame::addHistoryItemForFragmentScroll() { notImplemented(); } void WebFrame::didFinishLoad() { notImplemented(); } void WebFrame::prepareForDataSourceReplacement() { notImplemented(); } void WebFrame::setTitle(const String& title, const KURL& url) { BOOL privateBrowsingEnabled = FALSE; COMPtr preferences; if (SUCCEEDED(d->webView->preferences(&preferences))) preferences->privateBrowsingEnabled(&privateBrowsingEnabled); if (!privateBrowsingEnabled) { // update title in global history COMPtr history; history.adoptRef(webHistory()); if (history) { COMPtr item; if (SUCCEEDED(history->itemForURL(BString(url.string()), &item))) { COMPtr itemPrivate; if (SUCCEEDED(item->QueryInterface(IID_IWebHistoryItemPrivate, (void**)&itemPrivate))) itemPrivate->setTitle(BString(title)); } } } } String WebFrame::userAgent(const KURL& url) { return d->webView->userAgentForKURL(url); } void WebFrame::setDocumentViewFromCachedPage(CachedPage*) { notImplemented(); } void WebFrame::updateGlobalHistoryForStandardLoad(const KURL& url) { COMPtr history; history.adoptRef(webHistory()); if (!history) return; history->addItemForURL(BString(url.string()), 0); } void WebFrame::updateGlobalHistoryForReload(const KURL& url) { BString urlBStr(url.string()); COMPtr history; history.adoptRef(webHistory()); if (!history) return; COMPtr item; if (SUCCEEDED(history->itemForURL(urlBStr, &item))) { COMPtr itemPrivate; if (SUCCEEDED(item->QueryInterface(IID_IWebHistoryItemPrivate, (void**)&itemPrivate))) { SYSTEMTIME currentTime; GetSystemTime(¤tTime); DATE visitedTime = 0; SystemTimeToVariantTime(¤tTime, &visitedTime); // FIXME - bumping the last visited time doesn't mark the history as changed itemPrivate->setLastVisitedTimeInterval(visitedTime); } } } bool WebFrame::shouldGoToHistoryItem(HistoryItem*) const { notImplemented(); return true; } void WebFrame::saveViewStateToItem(HistoryItem*) { // FIXME: Need to save view state for page caching notImplemented(); } void WebFrame::saveDocumentViewToCachedPage(CachedPage*) { notImplemented(); } bool WebFrame::canCachePage() const { notImplemented(); return false; } PassRefPtr WebFrame::createDocumentLoader(const ResourceRequest& request, const SubstituteData& substituteData) { RefPtr loader = new WebDocumentLoader(request, substituteData); COMPtr dataSource; dataSource.adoptRef(WebDataSource::createInstance(loader.get())); loader->setDataSource(dataSource.get()); return loader.release(); } void WebFrame::setMainDocumentError(DocumentLoader*, const ResourceError& error) { if (d->m_pluginView) { if (d->m_pluginView->status() == PluginStatusLoadedSuccessfully) d->m_pluginView->didFail(error); d->m_pluginView = 0; d->m_hasSentResponseToPlugin = false; } } ResourceError WebFrame::cancelledError(const ResourceRequest& request) { // FIXME: Need ChickenCat to include CFNetwork/CFURLError.h to get these values // Alternatively, we could create our own error domain/codes. return ResourceError(String(WebURLErrorDomain), -999, request.url().string(), String()); } ResourceError WebFrame::blockedError(const ResourceRequest& request) { // FIXME: Need to implement the String descriptions for errors in the WebKitErrorDomain and have them localized return ResourceError(String(WebKitErrorDomain), WebKitErrorCannotUseRestrictedPort, request.url().string(), String()); } ResourceError WebFrame::cannotShowURLError(const ResourceRequest&) { notImplemented(); return ResourceError(); } ResourceError WebFrame::interruptForPolicyChangeError(const ResourceRequest& request) { // FIXME: Need to implement the String descriptions for errors in the WebKitErrorDomain and have them localized return ResourceError(String(WebKitErrorDomain), WebKitErrorFrameLoadInterruptedByPolicyChange, request.url().string(), String()); } ResourceError WebFrame::cannotShowMIMETypeError(const ResourceResponse&) { notImplemented(); return ResourceError(); } ResourceError WebFrame::fileDoesNotExistError(const ResourceResponse&) { notImplemented(); return ResourceError(); } bool WebFrame::shouldFallBack(const ResourceError& error) { return error.errorCode() != WebURLErrorCancelled; } void WebFrame::receivedData(const char* data, int length, const String& textEncoding) { Frame* coreFrame = core(this); if (!coreFrame) return; // Set the encoding. This only needs to be done once, but it's harmless to do it again later. String encoding = coreFrame->loader()->documentLoader()->overrideEncoding(); bool userChosen = !encoding.isNull(); if (encoding.isNull()) encoding = textEncoding; coreFrame->loader()->setEncoding(encoding, userChosen); coreFrame->loader()->addData(data, length); } COMPtr WebFrame::setUpPolicyListener(WebCore::FramePolicyFunction function) { // FIXME: We need to support multiple active policy listeners. if (d->m_policyListener) d->m_policyListener->invalidate(); Frame* coreFrame = core(this); ASSERT(coreFrame); d->m_policyListener.adoptRef(WebFramePolicyListener::createInstance(coreFrame)); d->m_policyFunction = function; return d->m_policyListener; } void WebFrame::receivedPolicyDecision(PolicyAction action) { ASSERT(d->m_policyListener); ASSERT(d->m_policyFunction); FramePolicyFunction function = d->m_policyFunction; d->m_policyListener = 0; d->m_policyFunction = 0; Frame* coreFrame = core(this); ASSERT(coreFrame); (coreFrame->loader()->*function)(action); } void WebFrame::committedLoad(DocumentLoader* loader, const char* data, int length) { // FIXME: This should probably go through the data source. const String& textEncoding = loader->response().textEncodingName(); if (!d->m_pluginView) receivedData(data, length, textEncoding); if (d->m_pluginView && d->m_pluginView->status() == PluginStatusLoadedSuccessfully) { if (!d->m_hasSentResponseToPlugin) { d->m_pluginView->didReceiveResponse(d->frame->loader()->documentLoader()->response()); // didReceiveResponse sets up a new stream to the plug-in. on a full-page plug-in, a failure in // setting up this stream can cause the main document load to be cancelled, setting m_pluginView // to null if (!d->m_pluginView) return; d->m_hasSentResponseToPlugin = true; } d->m_pluginView->didReceiveData(data, length); } } void WebFrame::dispatchDecidePolicyForMIMEType(FramePolicyFunction function, const String& mimeType, const ResourceRequest& request) { Frame* coreFrame = core(this); ASSERT(coreFrame); COMPtr policyDelegate; if (FAILED(d->webView->policyDelegate(&policyDelegate))) policyDelegate = DefaultPolicyDelegate::sharedInstance(); COMPtr urlRequest(AdoptCOM, WebMutableURLRequest::createInstance(request)); if (SUCCEEDED(policyDelegate->decidePolicyForMIMEType(d->webView, BString(mimeType), urlRequest.get(), this, setUpPolicyListener(function).get()))) return; (coreFrame->loader()->*function)(PolicyUse); } void WebFrame::dispatchDecidePolicyForNewWindowAction(FramePolicyFunction function, const NavigationAction& action, const ResourceRequest& request, const String& frameName) { Frame* coreFrame = core(this); ASSERT(coreFrame); COMPtr policyDelegate; if (FAILED(d->webView->policyDelegate(&policyDelegate))) policyDelegate = DefaultPolicyDelegate::sharedInstance(); COMPtr urlRequest(AdoptCOM, WebMutableURLRequest::createInstance(request)); COMPtr actionInformation(AdoptCOM, WebActionPropertyBag::createInstance(action, coreFrame)); if (SUCCEEDED(policyDelegate->decidePolicyForNewWindowAction(d->webView, actionInformation.get(), urlRequest.get(), BString(frameName), setUpPolicyListener(function).get()))) return; (coreFrame->loader()->*function)(PolicyUse); } void WebFrame::dispatchDecidePolicyForNavigationAction(FramePolicyFunction function, const NavigationAction& action, const ResourceRequest& request) { Frame* coreFrame = core(this); ASSERT(coreFrame); COMPtr policyDelegate; if (FAILED(d->webView->policyDelegate(&policyDelegate))) policyDelegate = DefaultPolicyDelegate::sharedInstance(); COMPtr urlRequest(AdoptCOM, WebMutableURLRequest::createInstance(request)); COMPtr actionInformation(AdoptCOM, WebActionPropertyBag::createInstance(action, coreFrame)); if (SUCCEEDED(policyDelegate->decidePolicyForNavigationAction(d->webView, actionInformation.get(), urlRequest.get(), this, setUpPolicyListener(function).get()))) return; (coreFrame->loader()->*function)(PolicyUse); } void WebFrame::dispatchUnableToImplementPolicy(const ResourceError& error) { COMPtr policyDelegate; if (FAILED(d->webView->policyDelegate(&policyDelegate))) policyDelegate = DefaultPolicyDelegate::sharedInstance(); COMPtr webError(AdoptCOM, WebError::createInstance(error)); policyDelegate->unableToImplementPolicyWithError(d->webView, webError.get(), this); } void WebFrame::download(ResourceHandle* handle, const ResourceRequest& request, const ResourceRequest&, const ResourceResponse& response) { COMPtr downloadDelegate; COMPtr webView; if (SUCCEEDED(this->webView(&webView))) { if (FAILED(webView->downloadDelegate(&downloadDelegate))) { // If the WebView doesn't successfully provide a download delegate we'll pass a null one // into the WebDownload - which may or may not decide to use a DefaultDownloadDelegate LOG_ERROR("Failed to get downloadDelegate from WebView"); downloadDelegate = 0; } } // Its the delegate's job to ref the WebDownload to keep it alive - otherwise it will be destroyed // when this method returns COMPtr download; download.adoptRef(WebDownload::createInstance(handle, request, response, downloadDelegate.get())); } bool WebFrame::willUseArchive(ResourceLoader*, const ResourceRequest&, const KURL&) const { notImplemented(); return false; } void WebFrame::assignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request) { COMPtr resourceLoadDelegate; if (SUCCEEDED(d->webView->resourceLoadDelegate(&resourceLoadDelegate))) { COMPtr webURLRequest; webURLRequest.adoptRef(WebMutableURLRequest::createInstance(request)); resourceLoadDelegate->identifierForInitialRequest(d->webView, webURLRequest.get(), getWebDataSource(loader), identifier); } } void WebFrame::dispatchWillSendRequest(DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse) { COMPtr resourceLoadDelegate; if (SUCCEEDED(d->webView->resourceLoadDelegate(&resourceLoadDelegate))) { COMPtr webURLRequest; webURLRequest.adoptRef(WebMutableURLRequest::createInstance(request)); COMPtr webURLRedirectResponse; webURLRedirectResponse.adoptRef(WebURLResponse::createInstance(redirectResponse)); COMPtr newWebURLRequest; if (FAILED(resourceLoadDelegate->willSendRequest(d->webView, identifier, webURLRequest.get(), webURLRedirectResponse.get(), getWebDataSource(loader), &newWebURLRequest))) return; if (webURLRequest == newWebURLRequest) return; COMPtr newWebURLRequestImpl; if (FAILED(newWebURLRequest->QueryInterface(&newWebURLRequestImpl))) return; request = newWebURLRequestImpl->resourceRequest(); } } void WebFrame::dispatchDidReceiveResponse(DocumentLoader* loader, unsigned long identifier, const ResourceResponse& response) { COMPtr resourceLoadDelegate; if (SUCCEEDED(d->webView->resourceLoadDelegate(&resourceLoadDelegate))) { COMPtr webURLResponse; webURLResponse.adoptRef(WebURLResponse::createInstance(response)); resourceLoadDelegate->didReceiveResponse(d->webView, identifier, webURLResponse.get(), getWebDataSource(loader)); } } void WebFrame::dispatchDidReceiveContentLength(DocumentLoader* loader, unsigned long identifier, int length) { COMPtr resourceLoadDelegate; if (SUCCEEDED(d->webView->resourceLoadDelegate(&resourceLoadDelegate))) resourceLoadDelegate->didReceiveContentLength(d->webView, identifier, length, getWebDataSource(loader)); } void WebFrame::dispatchDidFinishLoading(DocumentLoader* loader, unsigned long identifier) { COMPtr resourceLoadDelegate; if (SUCCEEDED(d->webView->resourceLoadDelegate(&resourceLoadDelegate))) resourceLoadDelegate->didFinishLoadingFromDataSource(d->webView, identifier, getWebDataSource(loader)); } void WebFrame::dispatchDidFailLoading(DocumentLoader* loader, unsigned long identifier, const ResourceError& error) { COMPtr resourceLoadDelegate; if (SUCCEEDED(d->webView->resourceLoadDelegate(&resourceLoadDelegate))) { COMPtr webError; webError.adoptRef(WebError::createInstance(error)); resourceLoadDelegate->didFailLoadingWithError(d->webView, identifier, webError.get(), getWebDataSource(loader)); } } bool WebFrame::dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int /*length*/) { notImplemented(); return false; } void WebFrame::dispatchDidFailProvisionalLoad(const ResourceError& error) { COMPtr frameLoadDelegate; if (SUCCEEDED(d->webView->frameLoadDelegate(&frameLoadDelegate))) { COMPtr webError; webError.adoptRef(WebError::createInstance(error)); frameLoadDelegate->didFailProvisionalLoadWithError(d->webView, webError.get(), this); } } void WebFrame::dispatchDidFailLoad(const ResourceError& error) { COMPtr frameLoadDelegate; if (SUCCEEDED(d->webView->frameLoadDelegate(&frameLoadDelegate))) { COMPtr webError; webError.adoptRef(WebError::createInstance(error)); frameLoadDelegate->didFailLoadWithError(d->webView, webError.get(), this); } } Frame* WebFrame::dispatchCreatePage() { COMPtr ui; if (SUCCEEDED(d->webView->uiDelegate(&ui))) { COMPtr newWebView; if (SUCCEEDED(ui->createWebViewWithRequest(d->webView, 0, &newWebView))) { COMPtr mainFrame; if (SUCCEEDED(newWebView->mainFrame(&mainFrame))) { COMPtr mainFrameImpl; if (SUCCEEDED(mainFrame->QueryInterface(IID_WebFrame, (void**)&mainFrameImpl))) return core(mainFrameImpl.get()); } } } return 0; } void WebFrame::postProgressStartedNotification() { static BSTR progressStartedName = SysAllocString(WebViewProgressStartedNotification); IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal(); notifyCenter->postNotificationName(progressStartedName, static_cast(d->webView), 0); } void WebFrame::postProgressEstimateChangedNotification() { static BSTR progressEstimateChangedName = SysAllocString(WebViewProgressEstimateChangedNotification); IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal(); notifyCenter->postNotificationName(progressEstimateChangedName, static_cast(d->webView), 0); } void WebFrame::postProgressFinishedNotification() { static BSTR progressFinishedName = SysAllocString(WebViewProgressFinishedNotification); IWebNotificationCenter* notifyCenter = WebNotificationCenter::defaultCenterInternal(); notifyCenter->postNotificationName(progressFinishedName, static_cast(d->webView), 0); } void WebFrame::startDownload(const ResourceRequest&) { notImplemented(); } void WebFrame::dispatchDidReceiveAuthenticationChallenge(DocumentLoader* loader, unsigned long identifier, const AuthenticationChallenge& challenge) { ASSERT(challenge.sourceHandle()); COMPtr resourceLoadDelegate; if (SUCCEEDED(d->webView->resourceLoadDelegate(&resourceLoadDelegate))) { COMPtr webChallenge(AdoptCOM, WebURLAuthenticationChallenge::createInstance(challenge)); if (SUCCEEDED(resourceLoadDelegate->didReceiveAuthenticationChallenge(d->webView, identifier, webChallenge.get(), getWebDataSource(loader)))) return; } // If the ResourceLoadDelegate doesn't exist or fails to handle the call, we tell the ResourceHandle // to continue without credential - this is the best approximation of Mac behavior challenge.sourceHandle()->receivedRequestToContinueWithoutCredential(challenge); } void WebFrame::dispatchDidCancelAuthenticationChallenge(DocumentLoader* loader, unsigned long identifier, const AuthenticationChallenge& challenge) { COMPtr resourceLoadDelegate; if (SUCCEEDED(d->webView->resourceLoadDelegate(&resourceLoadDelegate))) { COMPtr webChallenge(AdoptCOM, WebURLAuthenticationChallenge::createInstance(challenge)); if (SUCCEEDED(resourceLoadDelegate->didCancelAuthenticationChallenge(d->webView, identifier, webChallenge.get(), getWebDataSource(loader)))) return; } } PassRefPtr WebFrame::createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement, const String& referrer, bool /*allowsScrolling*/, int /*marginWidth*/, int /*marginHeight*/) { RefPtr result = createFrame(url, name, ownerElement, referrer); if (!result) return 0; // Propagate the marginwidth/height and scrolling modes to the view. if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) { HTMLFrameElement* frameElt = static_cast(ownerElement); if (frameElt->scrollingMode() == ScrollbarAlwaysOff) result->view()->setScrollbarsMode(ScrollbarAlwaysOff); int marginWidth = frameElt->getMarginWidth(); int marginHeight = frameElt->getMarginHeight(); if (marginWidth != -1) result->view()->setMarginWidth(marginWidth); if (marginHeight != -1) result->view()->setMarginHeight(marginHeight); } return result.release(); } Widget* WebFrame::createPlugin(const IntSize& pluginSize, Element* element, const KURL& url, const Vector& paramNames, const Vector& paramValues, const String& mimeType, bool loadManually) { PluginViewWin* pluginView = PluginDatabaseWin::installedPlugins()->createPluginView(core(this), pluginSize, element, url, paramNames, paramValues, mimeType, loadManually); if (pluginView->status() == PluginStatusLoadedSuccessfully) return pluginView; COMPtr resourceLoadDelegate; if (FAILED(d->webView->resourceLoadDelegate(&resourceLoadDelegate))) return pluginView; RetainPtr userInfo(AdoptCF, CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); unsigned count = (unsigned)paramNames.size(); for (unsigned i = 0; i < count; i++) { if (paramNames[i] == "pluginspage") { static CFStringRef key = MarshallingHelpers::LPCOLESTRToCFStringRef(WebKitErrorPlugInPageURLStringKey); RetainPtr str(AdoptCF, paramValues[i].createCFString()); CFDictionarySetValue(userInfo.get(), key, str.get()); break; } } if (!mimeType.isNull()) { static CFStringRef key = MarshallingHelpers::LPCOLESTRToCFStringRef(WebKitErrorMIMETypeKey); RetainPtr str(AdoptCF, mimeType.createCFString()); CFDictionarySetValue(userInfo.get(), key, str.get()); } String pluginName; if (pluginView->plugin()) pluginName = pluginView->plugin()->name(); if (!pluginName.isNull()) { static CFStringRef key = MarshallingHelpers::LPCOLESTRToCFStringRef(WebKitErrorPlugInNameKey); RetainPtr str(AdoptCF, pluginName.createCFString()); CFDictionarySetValue(userInfo.get(), key, str.get()); } COMPtr userInfoBag(AdoptCOM, CFDictionaryPropertyBag::createInstance()); userInfoBag->setDictionary(userInfo.get()); int errorCode = 0; switch (pluginView->status()) { case PluginStatusCanNotFindPlugin: errorCode = WebKitErrorCannotFindPlugIn; break; case PluginStatusCanNotLoadPlugin: errorCode = WebKitErrorCannotLoadPlugIn; break; default: ASSERT_NOT_REACHED(); } ResourceError resourceError(String(WebKitErrorDomain), errorCode, url.string(), String()); COMPtr error(AdoptCOM, WebError::createInstance(resourceError, userInfoBag.get())); resourceLoadDelegate->plugInFailedWithError(d->webView, error.get(), getWebDataSource(d->frame->loader()->documentLoader())); return pluginView; } void WebFrame::redirectDataToPlugin(Widget* pluginWidget) { // Ideally, this function shouldn't be necessary, see d->m_pluginView = static_cast(pluginWidget); } Widget* WebFrame::createJavaAppletWidget(const IntSize& pluginSize, Element* element, const KURL& /*baseURL*/, const Vector& paramNames, const Vector& paramValues) { PluginViewWin* pluginView = PluginDatabaseWin::installedPlugins()-> createPluginView(core(this), pluginSize, element, KURL(), paramNames, paramValues, "application/x-java-applet", false); // Check if the plugin can be loaded successfully if (pluginView->plugin() && pluginView->plugin()->load()) return pluginView; COMPtr resourceLoadDelegate; if (FAILED(d->webView->resourceLoadDelegate(&resourceLoadDelegate))) return pluginView; COMPtr userInfoBag(AdoptCOM, CFDictionaryPropertyBag::createInstance()); ResourceError resourceError(String(WebKitErrorDomain), WebKitErrorJavaUnavailable, String(), String()); COMPtr error(AdoptCOM, WebError::createInstance(resourceError, userInfoBag.get())); resourceLoadDelegate->plugInFailedWithError(d->webView, error.get(), getWebDataSource(d->frame->loader()->documentLoader())); return pluginView; } ObjectContentType WebFrame::objectContentType(const KURL& url, const String& mimeTypeIn) { String mimeType = mimeTypeIn; if (mimeType.isEmpty()) mimeType = MIMETypeRegistry::getMIMETypeForExtension(url.path().mid(url.path().findRev('.')+1)); if (mimeType.isEmpty()) return ObjectContentFrame; // Go ahead and hope that we can display the content. if (MIMETypeRegistry::isSupportedImageMIMEType(mimeType)) return WebCore::ObjectContentImage; if (PluginDatabaseWin::installedPlugins()->isMIMETypeRegistered(mimeType)) return WebCore::ObjectContentNetscapePlugin; if (MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType)) return WebCore::ObjectContentFrame; return WebCore::ObjectContentNone; } String WebFrame::overrideMediaType() const { notImplemented(); return String(); } void WebFrame::windowObjectCleared() { Frame* coreFrame = core(this); ASSERT(coreFrame); Settings* settings = coreFrame->settings(); if (!settings || !settings->isJavaScriptEnabled()) return; COMPtr frameLoadDelegate; if (SUCCEEDED(d->webView->frameLoadDelegate(&frameLoadDelegate))) { COMPtr frameLoadDelegate2(Query, frameLoadDelegate); JSContextRef context = toRef(coreFrame->scriptProxy()->globalObject()->globalExec()); JSObjectRef windowObject = toRef(KJS::Window::retrieve(coreFrame)->getObject()); ASSERT(windowObject); if (!frameLoadDelegate2 || FAILED(frameLoadDelegate2->didClearWindowObject(d->webView, context, windowObject, this))) frameLoadDelegate->windowScriptObjectAvailable(d->webView, context, windowObject); } if (WebScriptDebugServer::listenerCount() > 0) { detachScriptDebugger(); attachScriptDebugger(); } } void WebFrame::didPerformFirstNavigation() const { COMPtr preferences; if (FAILED(d->webView->preferences(&preferences))) return; COMPtr preferencesPrivate(Query, preferences); if (!preferencesPrivate) return; BOOL automaticallyDetectsCacheModel; if (FAILED(preferencesPrivate->automaticallyDetectsCacheModel(&automaticallyDetectsCacheModel))) return; WebCacheModel cacheModel; if (FAILED(preferences->cacheModel(&cacheModel))) return; if (automaticallyDetectsCacheModel && cacheModel < WebCacheModelDocumentBrowser) preferences->setCacheModel(WebCacheModelDocumentBrowser); } void WebFrame::registerForIconNotification(bool listen) { d->webView->registerForIconNotification(listen); } static IntRect printerRect(HDC printDC) { return IntRect(0, 0, GetDeviceCaps(printDC, PHYSICALWIDTH) - 2 * GetDeviceCaps(printDC, PHYSICALOFFSETX), GetDeviceCaps(printDC, PHYSICALHEIGHT) - 2 * GetDeviceCaps(printDC, PHYSICALOFFSETY)); } void WebFrame::setPrinting(bool printing, float minPageWidth, float maxPageWidth, bool adjustViewSize) { Frame* coreFrame = core(this); ASSERT(coreFrame); coreFrame->setPrinting(printing, minPageWidth, maxPageWidth, adjustViewSize); } HRESULT STDMETHODCALLTYPE WebFrame::setInPrintingMode( /* [in] */ BOOL value, /* [in] */ HDC printDC) { if (m_inPrintingMode == !!value) return S_OK; Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; m_inPrintingMode = !!value; // If we are a frameset just print with the layout we have onscreen, otherwise relayout // according to the paper size float minLayoutWidth = 0.0f; float maxLayoutWidth = 0.0f; if (m_inPrintingMode && !coreFrame->isFrameSet()) { if (!printDC) { ASSERT_NOT_REACHED(); return E_POINTER; } const int desiredHorizontalPixelsPerInch = 72; int paperHorizontalPixelsPerInch = ::GetDeviceCaps(printDC, LOGPIXELSX); int paperWidth = printerRect(printDC).width() * desiredHorizontalPixelsPerInch / paperHorizontalPixelsPerInch; minLayoutWidth = paperWidth * PrintingMinimumShrinkFactor; maxLayoutWidth = paperWidth * PrintingMaximumShrinkFactor; } setPrinting(m_inPrintingMode, minLayoutWidth, maxLayoutWidth, true); if (!m_inPrintingMode) m_pageRects.clear(); return S_OK; } void WebFrame::headerAndFooterHeights(float* headerHeight, float* footerHeight) { if (headerHeight) *headerHeight = 0; if (footerHeight) *footerHeight = 0; float height = 0; COMPtr ui; if (FAILED(d->webView->uiDelegate(&ui))) return; COMPtr ui2; if (FAILED(ui->QueryInterface(IID_IWebUIDelegate2, (void**) &ui2))) return; if (headerHeight && SUCCEEDED(ui2->webViewHeaderHeight(d->webView, &height))) *headerHeight = height; if (footerHeight && SUCCEEDED(ui2->webViewFooterHeight(d->webView, &height))) *footerHeight = height; } IntRect WebFrame::printerMarginRect(HDC printDC) { IntRect emptyRect(0, 0, 0, 0); COMPtr ui; if (FAILED(d->webView->uiDelegate(&ui))) return emptyRect; COMPtr ui2; if (FAILED(ui->QueryInterface(IID_IWebUIDelegate2, (void**) &ui2))) return emptyRect; RECT rect; if (FAILED(ui2->webViewPrintingMarginRect(d->webView, &rect))) return emptyRect; rect.left = MulDiv(rect.left, ::GetDeviceCaps(printDC, LOGPIXELSX), 1000); rect.top = MulDiv(rect.top, ::GetDeviceCaps(printDC, LOGPIXELSY), 1000); rect.right = MulDiv(rect.right, ::GetDeviceCaps(printDC, LOGPIXELSX), 1000); rect.bottom = MulDiv(rect.bottom, ::GetDeviceCaps(printDC, LOGPIXELSY), 1000); return IntRect(rect.left, rect.top, (rect.right - rect.left), rect.bottom - rect.top); } const Vector& WebFrame::computePageRects(HDC printDC) { ASSERT(m_inPrintingMode); Frame* coreFrame = core(this); ASSERT(coreFrame); ASSERT(coreFrame->document()); if (!printDC) return m_pageRects; // adjust the page rect by the header and footer float headerHeight = 0, footerHeight = 0; headerAndFooterHeights(&headerHeight, &footerHeight); IntRect pageRect = printerRect(printDC); IntRect marginRect = printerMarginRect(printDC); IntRect adjustedRect = IntRect( pageRect.x() + marginRect.x(), pageRect.y() + marginRect.y(), pageRect.width() - marginRect.x() - marginRect.right(), pageRect.height() - marginRect.y() - marginRect.bottom()); computePageRectsForFrame(coreFrame, adjustedRect, headerHeight, footerHeight, 1.0,m_pageRects, m_pageHeight); return m_pageRects; } HRESULT STDMETHODCALLTYPE WebFrame::getPrintedPageCount( /* [in] */ HDC printDC, /* [retval][out] */ UINT *pageCount) { if (!pageCount || !printDC) { ASSERT_NOT_REACHED(); return E_POINTER; } *pageCount = 0; if (!m_inPrintingMode) { ASSERT_NOT_REACHED(); return E_FAIL; } Frame* coreFrame = core(this); if (!coreFrame || !coreFrame->document()) return E_FAIL; const Vector& pages = computePageRects(printDC); *pageCount = (UINT) pages.size(); return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::spoolPages( /* [in] */ HDC printDC, /* [in] */ UINT startPage, /* [in] */ UINT endPage, /* [retval][out] */ void* ctx) { if (!printDC || !ctx) { ASSERT_NOT_REACHED(); return E_POINTER; } if (!m_inPrintingMode) { ASSERT_NOT_REACHED(); return E_FAIL; } Frame* coreFrame = core(this); if (!coreFrame || !coreFrame->document()) return E_FAIL; UINT pageCount = (UINT) m_pageRects.size(); PlatformGraphicsContext* pctx = (PlatformGraphicsContext*)ctx; if (!pageCount || startPage > pageCount) { ASSERT_NOT_REACHED(); return E_FAIL; } if (startPage > 0) startPage--; if (endPage == 0) endPage = pageCount; COMPtr ui; if (FAILED(d->webView->uiDelegate(&ui))) return E_FAIL; // FIXME: we can return early after the updated app is released COMPtr ui2; if (FAILED(ui->QueryInterface(IID_IWebUIDelegate2, (void**) &ui2))) ui2 = 0; float headerHeight = 0, footerHeight = 0; headerAndFooterHeights(&headerHeight, &footerHeight); GraphicsContext spoolCtx(pctx); for (UINT ii = startPage; ii < endPage; ii++) { IntRect pageRect = m_pageRects[ii]; CGContextSaveGState(pctx); IntRect printRect = printerRect(printDC); CGRect mediaBox = CGRectMake(CGFloat(0), CGFloat(0), CGFloat(printRect.width()), CGFloat(printRect.height())); CGContextBeginPage(pctx, &mediaBox); CGFloat scale = (float)mediaBox.size.width/ (float)pageRect.width(); CGAffineTransform ctm = CGContextGetBaseCTM(pctx); ctm = CGAffineTransformScale(ctm, -scale, -scale); ctm = CGAffineTransformTranslate(ctm, CGFloat(-pageRect.x()), CGFloat(-pageRect.y()+headerHeight)); // reserves space for header CGContextScaleCTM(pctx, scale, scale); CGContextTranslateCTM(pctx, CGFloat(-pageRect.x()), CGFloat(-pageRect.y()+headerHeight)); // reserves space for header CGContextSetBaseCTM(pctx, ctm); coreFrame->paint(&spoolCtx, pageRect); if (ui2) { CGContextTranslateCTM(pctx, CGFloat(pageRect.x()), CGFloat(pageRect.y())-headerHeight); int x = pageRect.x(); int y = 0; if (headerHeight) { RECT headerRect = {x, y, x+pageRect.width(), y+(int)headerHeight}; ui2->drawHeaderInRect(d->webView, &headerRect, (OLE_HANDLE)(LONG64)pctx); } if (footerHeight) { y = max((int)headerHeight+pageRect.height(), m_pageHeight-(int)footerHeight); RECT footerRect = {x, y, x+pageRect.width(), y+(int)footerHeight}; ui2->drawFooterInRect(d->webView, &footerRect, (OLE_HANDLE)(LONG64)pctx, ii+1, pageCount); } } CGContextEndPage(pctx); CGContextRestoreGState(pctx); } return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::isFrameSet( /* [retval][out] */ BOOL* result) { *result = FALSE; Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; *result = coreFrame->isFrameSet() ? TRUE : FALSE; return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::string( /* [retval][out] */ BSTR *result) { *result = 0; Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; RefPtr allRange(rangeOfContents(coreFrame->document())); String allString = plainText(allRange.get()); *result = BString(allString).release(); return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::size( /* [retval][out] */ SIZE *size) { if (!size) return E_POINTER; size->cx = size->cy = 0; Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; FrameView* view = coreFrame->view(); if (!view) return E_FAIL; size->cx = view->width(); size->cy = view->height(); return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::hasScrollBars( /* [retval][out] */ BOOL *result) { if (!result) return E_POINTER; *result = FALSE; Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; FrameView* view = coreFrame->view(); if (!view) return E_FAIL; if (view->vScrollbarMode() == ScrollbarAlwaysOn || view->visibleHeight() < view->contentsHeight() || view->hScrollbarMode() == ScrollbarAlwaysOn || view->visibleWidth() < view->contentsWidth()) *result = TRUE; return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::contentBounds( /* [retval][out] */ RECT *result) { if (!result) return E_POINTER; ::SetRectEmpty(result); Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; FrameView* view = coreFrame->view(); if (!view) return E_FAIL; result->bottom = view->contentsHeight(); result->right = view->contentsWidth(); return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::frameBounds( /* [retval][out] */ RECT *result) { if (!result) return E_POINTER; ::SetRectEmpty(result); Frame* coreFrame = core(this); if (!coreFrame) return E_FAIL; FrameView* view = coreFrame->view(); if (!view) return E_FAIL; FloatRect bounds = view->visibleContentRectConsideringExternalScrollers(); result->bottom = (LONG) bounds.height(); result->right = (LONG) bounds.width(); return S_OK; } HRESULT STDMETHODCALLTYPE WebFrame::isDescendantOfFrame( /* [in] */ IWebFrame *ancestor, /* [retval][out] */ BOOL *result) { if (!result) return E_POINTER; *result = FALSE; Frame* coreFrame = core(this); COMPtr ancestorWebFrame; if (!ancestor || FAILED(ancestor->QueryInterface(IID_WebFrame, (void**)&ancestorWebFrame))) return S_OK; *result = (coreFrame && coreFrame->tree()->isDescendantOf(core(ancestorWebFrame.get()))) ? TRUE : FALSE; return S_OK; } void WebFrame::unmarkAllMisspellings() { Frame* coreFrame = core(this); for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) { Document *doc = frame->document(); if (!doc) return; doc->removeMarkers(DocumentMarker::Spelling); } } void WebFrame::unmarkAllBadGrammar() { Frame* coreFrame = core(this); for (Frame* frame = coreFrame; frame; frame = frame->tree()->traverseNext(coreFrame)) { Document *doc = frame->document(); if (!doc) return; doc->removeMarkers(DocumentMarker::Grammar); } }