diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-27 00:20:51 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-27 00:20:51 +0000 |
commit | f5b16fed647e941aa66933178da85db2860d639b (patch) | |
tree | f00e9856c04aad3b558a140955e7674add33f051 /webkit/activex_shim/activex_util.cc | |
parent | 920c091ac3ee15079194c82ae8a7a18215f3f23c (diff) | |
download | chromium_src-f5b16fed647e941aa66933178da85db2860d639b.zip chromium_src-f5b16fed647e941aa66933178da85db2860d639b.tar.gz chromium_src-f5b16fed647e941aa66933178da85db2860d639b.tar.bz2 |
Add webkit to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/activex_shim/activex_util.cc')
-rw-r--r-- | webkit/activex_shim/activex_util.cc | 495 |
1 files changed, 495 insertions, 0 deletions
diff --git a/webkit/activex_shim/activex_util.cc b/webkit/activex_shim/activex_util.cc new file mode 100644 index 0000000..f7f218b --- /dev/null +++ b/webkit/activex_shim/activex_util.cc @@ -0,0 +1,495 @@ +// Copyright 2008, Google 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: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "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 THE COPYRIGHT +// OWNER 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 "webkit/activex_shim/activex_util.h" + +#include <exdisp.h> +#include <math.h> +#include <ocmm.h> + +#include "base/string_util.h" +#include "webkit/activex_shim/npp_impl.h" +#include "webkit/activex_shim/activex_plugin.h" + +using std::string; +using std::wstring; + +namespace activex_shim { + +#ifdef TRACK_INTERFACE + +namespace { +struct IIDToName { + IID iid; + const char* name; +}; +} // namespace + +#define MAP_IID_TO_NAME(name) {IID_##name, #name}, + +// Map frequently used iid to names. If unknown, return "Unknown:{xxxx-..}". +static string MapIIDToName(REFIID iid) { + IIDToName const well_known_interface_names[] = { + MAP_IID_TO_NAME(IUnknown) + MAP_IID_TO_NAME(IDispatch) + MAP_IID_TO_NAME(IParseDisplayName) + MAP_IID_TO_NAME(IOleContainer) + MAP_IID_TO_NAME(IOleWindow) + MAP_IID_TO_NAME(IOleInPlaceUIWindow) + MAP_IID_TO_NAME(IOleInPlaceFrame) + MAP_IID_TO_NAME(IHTMLDocument) + MAP_IID_TO_NAME(IHTMLDocument2) + MAP_IID_TO_NAME(IHTMLWindow2) + MAP_IID_TO_NAME(IOleClientSite) + MAP_IID_TO_NAME(IOleControlSite) + MAP_IID_TO_NAME(IOleInPlaceSite) + MAP_IID_TO_NAME(IOleInPlaceSiteEx) + MAP_IID_TO_NAME(IOleInPlaceSiteWindowless) + MAP_IID_TO_NAME(IServiceProvider) + MAP_IID_TO_NAME(IBindHost) + MAP_IID_TO_NAME(IWebBrowserApp) + MAP_IID_TO_NAME(ITimerService) + }; + for (int i = 0; i < arraysize(well_known_interface_names); ++i) { + if (well_known_interface_names[i].iid == iid) + return well_known_interface_names[i].name; + } + LPOLESTR sz = NULL; + StringFromIID(iid, &sz); + string res = string("Unknown:") + WideToUTF8(sz); + CoTaskMemFree(sz); + return res; +} + +void TrackQueryInterface(REFIID iid, bool succeeded, + const char* from_function) { + string name = MapIIDToName(iid); + if (succeeded) { + LOG(INFO) << "Successfully Queried: " << name << " in " \ + << from_function; + } else { + LOG(WARNING) << "Failed to Query: " << name << " in " \ + << from_function; + } +} + +#endif // #ifdef TRACK_INTERFACE + +bool NPIdentifierToWString(NPIdentifier name, wstring* ret) { + if (!g_browser->identifierisstring(name)) + return false; + + NPUTF8* str = g_browser->utf8fromidentifier(name); + *ret = UTF8ToWide(str); + g_browser->memfree(str); + + return true; +} + +bool DispGetID(IDispatch* disp, const wchar_t* name, DISPID* dispid) { + if (disp == NULL) + return false; + HRESULT hr = disp->GetIDsOfNames(IID_NULL, const_cast<LPOLESTR*>(&name), 1, + LOCALE_SYSTEM_DEFAULT, dispid); + if (FAILED(hr)) + return false; + return true; +} + +// Get the ITypeInfo of the dispatch interface and look for the FUNCDESC of +// the member. If not found or disp is NULL, return false. +static bool DispGetFuncDesc(IDispatch* disp, const wchar_t* name, + FUNCDESC* func) { + if (disp == NULL) + return false; + bool res = false; + CComPtr<ITypeInfo> tpi; + TYPEATTR* typeattr = NULL; + do { + HRESULT hr = disp->GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, &tpi); + if (FAILED(hr)) + break; + hr = tpi->GetTypeAttr(&typeattr); + if (FAILED(hr)) + break; + + MEMBERID memid; + hr = tpi->GetIDsOfNames(const_cast<LPOLESTR*>(&name), 1, &memid); + if (FAILED(hr)) + break; + + for (int i = 0; i < typeattr->cFuncs && !res; i++) { + FUNCDESC* funcdesc = NULL; + hr = tpi->GetFuncDesc(i, &funcdesc); + if (FAILED(hr)) + continue; + if (memid == funcdesc->memid) { + *func = *funcdesc; + res = true; + } + tpi->ReleaseFuncDesc(funcdesc); + } + } while(false); + if (tpi && typeattr) + tpi->ReleaseTypeAttr(typeattr); + return res; +} + +bool DispIsMethodOrProperty(IDispatch* disp, const wchar_t* name, + bool checkmethod) { + FUNCDESC funcdesc; + if (DispGetFuncDesc(disp, name, &funcdesc)) { + // If it has multiple params, for PROPERTYGET, we have to treat it like a + // method, because the scripting engine will not handle properties with + // parameters. + bool is_method = funcdesc.invkind == INVOKE_FUNC || funcdesc.cParams > 0; + return checkmethod == is_method; + } else { + // If it does not have a FUNCDESC, it should be a variable (property) if it + // has a dispid. + DISPID dispid; + if (DispGetID(disp, name, &dispid)) + return checkmethod == false; + else + return false; + } +} + +bool DispSetProperty(IDispatch* disp, const wchar_t* name, + const VARIANT& rvalue) { + if (disp == NULL) + return false; + + DISPID dispid; + if (!DispGetID(disp, name, &dispid)) + return false; + DISPPARAMS params = {0}; + params.cArgs = 1; + params.rgvarg = const_cast<VARIANTARG*>(&rvalue); + DISPID dispid_named = DISPID_PROPERTYPUT; + params.cNamedArgs = 1; + params.rgdispidNamedArgs = &dispid_named; + + unsigned int argerr; + ScopedVariant result; + HRESULT hr = disp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, + DISPATCH_PROPERTYPUT, ¶ms, &result, NULL, + &argerr); + return SUCCEEDED(hr); +} + +bool DispInvoke(IDispatch* disp, const wchar_t* name, VARIANT* args, + int arg_count, VARIANT* result) { + if (disp == NULL) + return false; + + unsigned int invoke_option; + DISPID dispid; + FUNCDESC funcdesc; + if (DispGetFuncDesc(disp, name, &funcdesc)) { + dispid = funcdesc.memid; + switch (funcdesc.invkind) { + case INVOKE_FUNC: + invoke_option = DISPATCH_METHOD; + break; + case INVOKE_PROPERTYGET: + invoke_option = DISPATCH_PROPERTYGET; + break; + default: + return false; + } + } else { + // Could be a variable if it doesn't have a FUNCDESC. + if (DispGetID(disp, name, &dispid)) + invoke_option = DISPATCH_PROPERTYGET; + else + return false; + } + VariantInit(result); + DISPPARAMS params = {0}; + params.cArgs = arg_count; + params.rgvarg = args; + unsigned int argerr; + + HRESULT hr = disp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, + invoke_option, ¶ms, result, NULL, &argerr); + return SUCCEEDED(hr); +} + +// If the given interface is safe for the flag, return true. Otherwise +// try to enable the safety option for the flag, return true if succeeded. +bool TestAndSetObjectSafetyOption(IObjectSafety* object_safety, + const IID& iid, DWORD flag) { + DWORD supported_options = 0, enabled_options = 0; + HRESULT hr = object_safety->GetInterfaceSafetyOptions(iid, + &supported_options, + &enabled_options); + if (SUCCEEDED(hr)) { + if (enabled_options & flag) { + return true; + } else if (supported_options & flag) { + hr = object_safety->SetInterfaceSafetyOptions(iid, flag, flag); + if (SUCCEEDED(hr)) + return true; + } + } + return false; +} + +unsigned long GetAndSetObjectSafetyOptions(IUnknown* control) { + unsigned long ret = 0; + + // If we have the interface then check that first. + CComQIPtr<IObjectSafety> object_safety = control; + if (object_safety != NULL) { + // Some controls only claim IPersistPropertyBag is safe. The best way + // would be checking if an interface is safe only when we use it. In reality + // this is sufficient enough, considering we have a whitelist. + static IID persist_iids[] = {IID_IPersist, IID_IPersistPropertyBag, + IID_IPersistPropertyBag2}; + for (int i = 0; i < arraysize(persist_iids); ++i) { + if (TestAndSetObjectSafetyOption(object_safety, persist_iids[i], + INTERFACESAFE_FOR_UNTRUSTED_DATA)) { + ret |= SAFE_FOR_INITIALIZING; + break; + } + } + if (TestAndSetObjectSafetyOption(object_safety, IID_IDispatch, + INTERFACESAFE_FOR_UNTRUSTED_CALLER)) + ret |= SAFE_FOR_SCRIPTING; + } + return ret; +} + +unsigned long GetRegisteredObjectSafetyOptions(const CLSID& clsid) { + unsigned long ret = 0; + HRESULT hr; + CComPtr<ICatInformation> cat_info; + hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, + NULL, CLSCTX_INPROC_SERVER, IID_ICatInformation, + reinterpret_cast<void**>(&cat_info)); + DCHECK(SUCCEEDED(hr)); + if (FAILED(hr)) + return ret; + + hr = cat_info->IsClassOfCategories(clsid, 1, &CATID_SafeForInitializing, + 0, NULL); + if (hr == S_OK) + ret |= SAFE_FOR_INITIALIZING; + hr = cat_info->IsClassOfCategories(clsid, 1, &CATID_SafeForScripting, + 0, NULL); + if (hr == S_OK) + ret |= SAFE_FOR_SCRIPTING; + + return ret; +} + +namespace { +// To allow only querying once for most frequently used device caps. +struct DeviceCaps { + DeviceCaps() { + inited_ = false; + } + long GetLogPixelX() { + Use(); + return log_pixel_x; + } + long GetLogPixelY() { + Use(); + return log_pixel_y; + } + private: + // Purposely make this inline. + void Use() { + if (!inited_) + Init(); + } + void Init(); + + bool inited_; + long log_pixel_x; + long log_pixel_y; +}; + +void DeviceCaps::Init() { + HDC dc = ::GetWindowDC(NULL); + log_pixel_x = ::GetDeviceCaps(dc, LOGPIXELSX); + log_pixel_y = ::GetDeviceCaps(dc, LOGPIXELSY); + ::ReleaseDC(NULL, dc); + inited_ = true; +} +} // namespace + +static DeviceCaps g_devicecaps; + +long ScreenToHimetricX(long x) { + return MulDiv(x, kHimetricPerInch, g_devicecaps.GetLogPixelX()); +} + +long ScreenToHimetricY(long y) { + return MulDiv(y, kHimetricPerInch, g_devicecaps.GetLogPixelY()); +} + +void ScreenToHimetric(long cx, long cy, SIZE* size) { + size->cx = ScreenToHimetricX(cx); + size->cy = ScreenToHimetricY(cy); +} + +bool VariantToNPVariant(DispatchObject* obj, const VARIANT* vt, + NPVariant* npv) { + // TODO(ruijiang): Support more types when necessary. + switch(vt->vt) { + case VT_BSTR: { + npv->type = NPVariantType_String; + if (vt->bstrVal == NULL) { + npv->value.stringValue.UTF8Characters = NULL; + npv->value.stringValue.UTF8Length = 0; + return true; + } + string s; + s = WideToUTF8(vt->bstrVal); + // We need to let browser allocate this memory because this will go + // out of our control and be used/released by the browser. + npv->value.stringValue.UTF8Characters = + static_cast<NPUTF8*>(g_browser->memalloc((uint32)s.size())); + memcpy(static_cast<void*>(const_cast<NPUTF8*>( + npv->value.stringValue.UTF8Characters)), + s.c_str(), s.size()); + npv->value.stringValue.UTF8Length = static_cast<uint32>(s.size()); + return true; + } + case VT_DISPATCH: { + SpawnedDispatchObject* disp_object = + new SpawnedDispatchObject(vt->pdispVal, obj->root()); + npv->type = NPVariantType_Object; + npv->value.objectValue = disp_object->GetScriptableNPObject(); + return true; + } + // All integer types. + case VT_I1: + case VT_I2: + case VT_I4: + case VT_INT: + case VT_UI1: + case VT_UI2: + case VT_UI4: + case VT_UINT: { + ScopedVariant tmp; + if (FAILED(VariantChangeType(&tmp, vt, 0, VT_I4))) + return false; + npv->type = NPVariantType_Int32; + npv->value.intValue = tmp.lVal; + return true; + } + // Float number types. + case VT_I8: + case VT_UI8: + case VT_CY: + case VT_R4: + case VT_R8: { + ScopedVariant tmp; + if (FAILED(VariantChangeType(&tmp, vt, 0, VT_R8))) + return false; + npv->type = NPVariantType_Double; + npv->value.doubleValue = tmp.dblVal; + return true; + } + case VT_BOOL: { + npv->type = NPVariantType_Bool; + npv->value.boolValue = vt->boolVal != VARIANT_FALSE; + return true; + } + case VT_NULL: { + npv->type = NPVariantType_Null; + return true; + } + case VT_EMPTY: { + npv->type = NPVariantType_Void; + return true; + } + default: { + return false; + } + } +} + +bool NPVariantToVariant(const NPVariant* npv, VARIANT* vt) { + VariantInit(vt); + switch(npv->type) { + case NPVariantType_String: + vt->vt = VT_BSTR; + if (npv->value.stringValue.UTF8Length > 0) { + string str; + str.assign(npv->value.stringValue.UTF8Characters, + npv->value.stringValue.UTF8Length); + vt->bstrVal = SysAllocString(UTF8ToWide(str.c_str()).c_str()); + } else { + vt->bstrVal = NULL; + } + return true; + case NPVariantType_Int32: + vt->vt = VT_I4; + vt->intVal = npv->value.intValue; + return true; + case NPVariantType_Double: + vt->vt = VT_R8; + vt->dblVal = npv->value.doubleValue; + return true; + case NPVariantType_Bool: + vt->vt = VT_BOOL; + vt->boolVal = npv->value.boolValue ? VARIANT_TRUE : VARIANT_FALSE; + return true; + case NPVariantType_Null: + vt->vt = VT_NULL; + return true; + case NPVariantType_Void: + // According to: http://developer.mozilla.org/en/docs/NPVariant + // Void type corresponds to JavaScript type: undefined, which means + // no value has been assigned. Thus VT_EMPTY is the best variant matches + // void. + vt->vt = VT_EMPTY; + return true; + case NPVariantType_Object: + // TODO(ruijiang): We probably need to convert NP object to IDispatch, + // which would be a pretty hard job. (consider the many interfaces of + // IHTML*). + return false; + default: + return false; + } +} + +wchar_t* CoTaskMemAllocString(const std::wstring& s) { + size_t cb = (s.size() + 1) * sizeof(wchar_t); + LPOLESTR p = static_cast<LPOLESTR>(CoTaskMemAlloc(cb)); + memcpy(p, s.c_str(), cb); + return p; +} + +} // namespace activex_shim |